diff --git a/packages/dashboard/src/app-config.ts b/packages/dashboard/src/app-config.ts index 8778599d1..66d12903c 100644 --- a/packages/dashboard/src/app-config.ts +++ b/packages/dashboard/src/app-config.ts @@ -2,7 +2,9 @@ import React from 'react'; import { getDefaultTaskDefinition, TaskDefinition } from 'react-components'; import testConfig from '../app-config.json'; -import { Authenticator, KeycloakAuthenticator, StubAuthenticator } from './auth'; +import { Authenticator } from './services/authenticator'; +import { KeycloakAuthenticator } from './services/keycloak'; +import { StubAuthenticator } from './services/stub-authenticator'; export interface RobotResource { /** diff --git a/packages/dashboard/src/components/app.css b/packages/dashboard/src/app.css similarity index 100% rename from packages/dashboard/src/components/app.css rename to packages/dashboard/src/app.css diff --git a/packages/dashboard/src/components/app.tsx b/packages/dashboard/src/app.tsx similarity index 79% rename from packages/dashboard/src/components/app.tsx rename to packages/dashboard/src/app.tsx index 85dbf8093..51d1983e4 100644 --- a/packages/dashboard/src/components/app.tsx +++ b/packages/dashboard/src/app.tsx @@ -8,8 +8,19 @@ import './app.css'; import React from 'react'; import { Navigate, Route, Routes } from 'react-router-dom'; -import { AppConfigContext, AuthenticatorContext, ResourcesContext } from '../app-config'; -import { LoginPage, PrivateRoute } from '../auth'; +import { AppConfigContext, AuthenticatorContext, ResourcesContext } from './app-config'; +import { + AdminRouter, + AppBase, + AppEvents, + ManagedWorkspace, + PrivateRoute, + RmfApp, + SettingsContext, + Workspace, + WorkspaceState, +} from './components'; +import { LoginPage } from './pages'; import { AdminRoute, CustomRoute1, @@ -18,16 +29,40 @@ import { LoginRoute, RobotsRoute, TasksRoute, -} from '../util/url'; -import { AdminRouter } from './admin'; -import { AppBase } from './app-base'; -import { SettingsContext } from './app-contexts'; -import { AppEvents } from './app-events'; -import { dashboardWorkspace } from './dashboard'; -import { RmfApp } from './rmf-app'; -import { robotsWorkspace } from './robots/robots-workspace'; -import { tasksWorkspace } from './tasks/tasks-workspace'; -import { ManagedWorkspace, Workspace } from './workspace'; +} from './utils/url'; + +const dashboardWorkspace: WorkspaceState = { + layout: [{ i: 'map', x: 0, y: 0, w: 12, h: 12 }], + windows: [{ key: 'map', appName: 'Map' }], +}; + +const robotsWorkspace: WorkspaceState = { + layout: [ + { i: 'robots', x: 0, y: 0, w: 7, h: 4 }, + { i: 'map', x: 8, y: 0, w: 5, h: 8 }, + { i: 'doors', x: 0, y: 0, w: 7, h: 4 }, + { i: 'lifts', x: 0, y: 0, w: 7, h: 4 }, + { i: 'mutexGroups', x: 8, y: 0, w: 5, h: 4 }, + ], + windows: [ + { key: 'robots', appName: 'Robots' }, + { key: 'map', appName: 'Map' }, + { key: 'doors', appName: 'Doors' }, + { key: 'lifts', appName: 'Lifts' }, + { key: 'mutexGroups', appName: 'Mutex Groups' }, + ], +}; + +const tasksWorkspace: WorkspaceState = { + layout: [ + { i: 'tasks', x: 0, y: 0, w: 7, h: 12 }, + { i: 'map', x: 8, y: 0, w: 5, h: 12 }, + ], + windows: [ + { key: 'tasks', appName: 'Tasks' }, + { key: 'map', appName: 'Map' }, + ], +}; export default function App(): JSX.Element | null { const authenticator = React.useContext(AuthenticatorContext); diff --git a/packages/dashboard/src/auth/index.ts b/packages/dashboard/src/auth/index.ts deleted file mode 100644 index af62c26f5..000000000 --- a/packages/dashboard/src/auth/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from './authenticator'; -export * from './keycloak'; -export * from './login-card'; -export * from './login-page'; -export * from './private-route'; -export * from './stub'; -export * from './user-profile'; diff --git a/packages/dashboard/src/auth/login.stories.tsx b/packages/dashboard/src/auth/login.stories.tsx deleted file mode 100644 index c69fc43e2..000000000 --- a/packages/dashboard/src/auth/login.stories.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Meta, StoryFn } from '@storybook/react'; - -import { LoginCard as LoginCard_, LoginPage as LoginPage_ } from '.'; -import { LoginCardProps } from './login-card'; - -export default { - title: 'Login', - component: LoginCard_, - argTypes: { - title: { - defaultValue: 'Title', - }, - logo: { - control: { - disable: true, - }, - }, - }, -} satisfies Meta; - -export const LoginCard: StoryFn = (args) => ( - -); - -export const LoginPage: StoryFn = (args) => ( - -); diff --git a/packages/dashboard/src/components/admin/add-permission-dialog.stories.tsx b/packages/dashboard/src/components/admin/add-permission-dialog.stories.tsx index 48eca88a4..9d5558ff9 100644 --- a/packages/dashboard/src/components/admin/add-permission-dialog.stories.tsx +++ b/packages/dashboard/src/components/admin/add-permission-dialog.stories.tsx @@ -1,21 +1,22 @@ -import { Meta, StoryFn } from '@storybook/react'; +import { Meta, StoryObj } from '@storybook/react'; -import { AddPermissionDialog, AddPermissionDialogProps } from './add-permission-dialog'; +import { AddPermissionDialog } from './add-permission-dialog'; export default { title: 'Admin/Add Permission Dialog', component: AddPermissionDialog, } satisfies Meta; -export const Default: StoryFn = (args) => { - return ( +type Story = StoryObj; + +export const Default: Story = { + storyName: 'Add Permission Dialog', + render: (args) => ( {}} savePermission={() => new Promise((res) => setTimeout(res, 100))} /> - ); + ), }; - -Default.storyName = 'Add Permission Dialog'; diff --git a/packages/dashboard/src/components/admin/tests/add-permission-dialog.test.tsx b/packages/dashboard/src/components/admin/add-permission-dialog.test.tsx similarity index 87% rename from packages/dashboard/src/components/admin/tests/add-permission-dialog.test.tsx rename to packages/dashboard/src/components/admin/add-permission-dialog.test.tsx index 8c29866a0..6d5448207 100644 --- a/packages/dashboard/src/components/admin/tests/add-permission-dialog.test.tsx +++ b/packages/dashboard/src/components/admin/add-permission-dialog.test.tsx @@ -2,8 +2,8 @@ import { render } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { describe, expect, it, vi } from 'vitest'; -import { RmfAction } from '../../permissions'; -import { AddPermissionDialog } from '../add-permission-dialog'; +import { RmfAction } from '../../services/permissions'; +import { AddPermissionDialog } from './add-permission-dialog'; describe('AddPermissionDialog', () => { it('calls savePermission when form is submitted', async () => { diff --git a/packages/dashboard/src/components/admin/add-permission-dialog.tsx b/packages/dashboard/src/components/admin/add-permission-dialog.tsx index 5b91d128a..ff5ab4541 100644 --- a/packages/dashboard/src/components/admin/add-permission-dialog.tsx +++ b/packages/dashboard/src/components/admin/add-permission-dialog.tsx @@ -3,8 +3,8 @@ import { Permission } from 'api-client'; import React from 'react'; import { ConfirmationDialog, useAsync } from 'react-components'; +import { getActionText, RmfAction } from '../../services/permissions'; import { AppControllerContext } from '../app-contexts'; -import { getActionText, RmfAction } from '../permissions'; export interface AddPermissionDialogProps { open: boolean; diff --git a/packages/dashboard/src/components/admin/create-role-dialog.stories.tsx b/packages/dashboard/src/components/admin/create-role-dialog.stories.tsx index b5739af3e..6d8b9f61c 100644 --- a/packages/dashboard/src/components/admin/create-role-dialog.stories.tsx +++ b/packages/dashboard/src/components/admin/create-role-dialog.stories.tsx @@ -1,20 +1,21 @@ -import { Meta, StoryFn } from '@storybook/react'; +import { Meta, StoryObj } from '@storybook/react'; -import { CreateRoleDialog, CreateRoleDialogProps } from './create-role-dialog'; +import { CreateRoleDialog } from './create-role-dialog'; export default { title: 'Admin/Create Role Dialog', component: CreateRoleDialog, } satisfies Meta; -export const Default: StoryFn = (args) => { - return ( +type Story = StoryObj; + +export const Default: Story = { + storyName: 'Create Role Dialog', + render: (args) => ( new Promise((res) => setTimeout(res, 100))} /> - ); + ), }; - -Default.storyName = 'Create Role Dialog'; diff --git a/packages/dashboard/src/components/admin/tests/create-role-dialog.test.tsx b/packages/dashboard/src/components/admin/create-role-dialog.test.tsx similarity index 91% rename from packages/dashboard/src/components/admin/tests/create-role-dialog.test.tsx rename to packages/dashboard/src/components/admin/create-role-dialog.test.tsx index 16c24c880..de606ddb9 100644 --- a/packages/dashboard/src/components/admin/tests/create-role-dialog.test.tsx +++ b/packages/dashboard/src/components/admin/create-role-dialog.test.tsx @@ -2,7 +2,7 @@ import { render } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { describe, expect, it, vi } from 'vitest'; -import { CreateRoleDialog } from '../create-role-dialog'; +import { CreateRoleDialog } from './create-role-dialog'; describe('CreateRoleDialog', () => { it('calls createRole when form is submitted', async () => { diff --git a/packages/dashboard/src/components/admin/create-user-dialog.stories.tsx b/packages/dashboard/src/components/admin/create-user-dialog.stories.tsx index 8ab90a54a..59f6aab95 100644 --- a/packages/dashboard/src/components/admin/create-user-dialog.stories.tsx +++ b/packages/dashboard/src/components/admin/create-user-dialog.stories.tsx @@ -1,20 +1,23 @@ -import { Meta, StoryFn } from '@storybook/react'; +import { Meta, StoryObj } from '@storybook/react'; -import { CreateUserDialog, CreateUserDialogProps } from './create-user-dialog'; +import { CreateUserDialog } from './create-user-dialog'; export default { title: 'Admin/Create User Dialog', component: CreateUserDialog, } satisfies Meta; -export const Default: StoryFn = (args) => { - return ( +type Story = StoryObj; + +export const Default: Story = { + storyName: 'Create User Dialog', + render: (args) => ( new Promise((res) => setTimeout(res, 100))} /> - ); + ), }; Default.storyName = 'Create User Dialog'; diff --git a/packages/dashboard/src/components/admin/tests/create-user-dialog.test.tsx b/packages/dashboard/src/components/admin/create-user-dialog.test.tsx similarity index 91% rename from packages/dashboard/src/components/admin/tests/create-user-dialog.test.tsx rename to packages/dashboard/src/components/admin/create-user-dialog.test.tsx index 223718d29..603ac7085 100644 --- a/packages/dashboard/src/components/admin/tests/create-user-dialog.test.tsx +++ b/packages/dashboard/src/components/admin/create-user-dialog.test.tsx @@ -2,7 +2,7 @@ import { render } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { describe, expect, it, vi } from 'vitest'; -import { CreateUserDialog } from '../create-user-dialog'; +import { CreateUserDialog } from './create-user-dialog'; describe('CreateUserDialog', () => { it('calls createUser when form is submitted', async () => { diff --git a/packages/dashboard/src/components/admin/drawer.stories.tsx b/packages/dashboard/src/components/admin/drawer.stories.tsx index 79750bc76..966886c85 100644 --- a/packages/dashboard/src/components/admin/drawer.stories.tsx +++ b/packages/dashboard/src/components/admin/drawer.stories.tsx @@ -1,4 +1,4 @@ -import { Meta, StoryFn } from '@storybook/react'; +import { Meta, StoryObj } from '@storybook/react'; import { AdminDrawer } from './drawer'; @@ -12,8 +12,8 @@ export default { }, } satisfies Meta; -export const Default: StoryFn<{}> = (args) => { - return ; -}; +type Story = StoryObj; -Default.storyName = 'Drawer'; +export const Default: Story = { + storyName: 'Drawer', +}; diff --git a/packages/dashboard/src/components/admin/drawer.test.tsx b/packages/dashboard/src/components/admin/drawer.test.tsx new file mode 100644 index 000000000..3045ede59 --- /dev/null +++ b/packages/dashboard/src/components/admin/drawer.test.tsx @@ -0,0 +1,15 @@ +import { render } from '@testing-library/react'; +import { MemoryRouter } from 'react-router'; +import { describe, it } from 'vitest'; + +import { AdminDrawer } from './drawer'; + +describe('AdminDrawer', () => { + it('smoke test', () => { + render( + + + , + ); + }); +}); diff --git a/packages/dashboard/src/components/admin/manage-roles-dialog.stories.tsx b/packages/dashboard/src/components/admin/manage-roles-dialog.stories.tsx index db6a1d24b..8f089a85e 100644 --- a/packages/dashboard/src/components/admin/manage-roles-dialog.stories.tsx +++ b/packages/dashboard/src/components/admin/manage-roles-dialog.stories.tsx @@ -1,10 +1,10 @@ -import { Meta, StoryFn } from '@storybook/react'; +import { Meta, StoryObj } from '@storybook/react'; import { ManageRolesCard } from './manage-roles-dialog'; -import { RoleListCardProps } from './role-list-card'; export default { title: 'Admin/Manage Roles Card', + component: ManageRolesCard, } satisfies Meta; const allRoles: string[] = []; @@ -12,10 +12,15 @@ for (let i = 0; i < 5; i++) { allRoles.push(`role${i}`); } -export const Default: StoryFn = (args) => { - return ( +type Story = StoryObj; + +export const Default: Story = { + storyName: 'Manage Roles Card', + args: { + assignedRoles: ['role1'], + }, + render: (args) => ( { await new Promise((res) => setTimeout(res, 100)); return allRoles; @@ -25,7 +30,5 @@ export const Default: StoryFn = (args) => { }} {...args} /> - ); + ), }; - -Default.storyName = 'Manage Roles Card'; diff --git a/packages/dashboard/src/components/admin/tests/manage-roles-dialog.test.tsx b/packages/dashboard/src/components/admin/manage-roles-dialog.test.tsx similarity index 94% rename from packages/dashboard/src/components/admin/tests/manage-roles-dialog.test.tsx rename to packages/dashboard/src/components/admin/manage-roles-dialog.test.tsx index c0d65b054..c99567e81 100644 --- a/packages/dashboard/src/components/admin/tests/manage-roles-dialog.test.tsx +++ b/packages/dashboard/src/components/admin/manage-roles-dialog.test.tsx @@ -2,7 +2,7 @@ import { render, waitFor, waitForElementToBeRemoved } from '@testing-library/rea import userEvent from '@testing-library/user-event'; import { describe, expect, it, vi } from 'vitest'; -import { ManageRolesCard, ManageRolesDialog } from '../manage-roles-dialog'; +import { ManageRolesCard, ManageRolesDialog } from './manage-roles-dialog'; describe('ManageRolesCard', () => { it('shows dialog when add/remove is clicked', async () => { diff --git a/packages/dashboard/src/components/admin/permissions-card.stories.tsx b/packages/dashboard/src/components/admin/permissions-card.stories.tsx index 5813c72f0..84ad07cd3 100644 --- a/packages/dashboard/src/components/admin/permissions-card.stories.tsx +++ b/packages/dashboard/src/components/admin/permissions-card.stories.tsx @@ -1,7 +1,7 @@ -import { Meta, StoryFn } from '@storybook/react'; +import { Meta, StoryObj } from '@storybook/react'; import { Permission } from 'api-client'; -import { PermissionsCard, PermissionsCardProps } from './permissions-card'; +import { PermissionsCard } from './permissions-card'; export default { title: 'Admin/Permissions Card', @@ -16,10 +16,11 @@ export default { }, } satisfies Meta; -export const Default: StoryFn = (args) => { - return ( +type Story = StoryObj; + +export const Default: Story = { + storyName: 'Permissions Card', + render: (args) => ( new Promise((res) => setTimeout(res, 100))} /> - ); + ), }; - -Default.storyName = 'Permissions Card'; diff --git a/packages/dashboard/src/components/admin/tests/permissions-card.test.tsx b/packages/dashboard/src/components/admin/permissions-card.test.tsx similarity index 94% rename from packages/dashboard/src/components/admin/tests/permissions-card.test.tsx rename to packages/dashboard/src/components/admin/permissions-card.test.tsx index c836beb1a..af1b32e67 100644 --- a/packages/dashboard/src/components/admin/tests/permissions-card.test.tsx +++ b/packages/dashboard/src/components/admin/permissions-card.test.tsx @@ -2,8 +2,8 @@ import { fireEvent, render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'; -import { getActionText, RmfAction } from '../../permissions'; -import { PermissionsCard } from '../permissions-card'; +import { getActionText, RmfAction } from '../../services/permissions'; +import { PermissionsCard } from './permissions-card'; // TODO(AA): To remove after // https://github.com/testing-library/react-testing-library/issues/1216 diff --git a/packages/dashboard/src/components/admin/permissions-card.tsx b/packages/dashboard/src/components/admin/permissions-card.tsx index 616bb9d96..c6265007b 100644 --- a/packages/dashboard/src/components/admin/permissions-card.tsx +++ b/packages/dashboard/src/components/admin/permissions-card.tsx @@ -19,8 +19,8 @@ import { Permission } from 'api-client'; import React from 'react'; import { Loading, useAsync } from 'react-components'; +import { getActionText } from '../../services/permissions'; import { AppControllerContext } from '../app-contexts'; -import { getActionText } from '../permissions'; import { AddPermissionDialog, AddPermissionDialogProps } from './add-permission-dialog'; const prefix = 'permissions-card'; diff --git a/packages/dashboard/src/components/admin/role-list-card.stories.tsx b/packages/dashboard/src/components/admin/role-list-card.stories.tsx index 059c1d865..ded434fa1 100644 --- a/packages/dashboard/src/components/admin/role-list-card.stories.tsx +++ b/packages/dashboard/src/components/admin/role-list-card.stories.tsx @@ -1,15 +1,18 @@ -import { Meta, StoryFn } from '@storybook/react'; +import { Meta, StoryObj } from '@storybook/react'; -import { RmfAction } from '../permissions'; -import { RoleListCard, RoleListCardProps } from './role-list-card'; +import { RmfAction } from '../../services/permissions'; +import { RoleListCard } from './role-list-card'; export default { title: 'Admin/Role List Card', component: RoleListCard, } satisfies Meta; -export const Default: StoryFn = (args) => { - return ( +type Story = StoryObj; + +export const Default: Story = { + storyName: 'Role List Card', + render: (args) => ( { @@ -26,7 +29,5 @@ export const Default: StoryFn = (args) => { createRole={() => new Promise((res) => setTimeout(res, 100))} deleteRole={() => new Promise((res) => setTimeout(res, 100))} /> - ); + ), }; - -Default.storyName = 'Role List Card'; diff --git a/packages/dashboard/src/components/admin/tests/role-list-card.test.tsx b/packages/dashboard/src/components/admin/role-list-card.test.tsx similarity index 93% rename from packages/dashboard/src/components/admin/tests/role-list-card.test.tsx rename to packages/dashboard/src/components/admin/role-list-card.test.tsx index 5021ae95e..90099709b 100644 --- a/packages/dashboard/src/components/admin/tests/role-list-card.test.tsx +++ b/packages/dashboard/src/components/admin/role-list-card.test.tsx @@ -2,7 +2,7 @@ import { render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { describe, expect, it } from 'vitest'; -import { RoleListCard } from '../role-list-card'; +import { RoleListCard } from './role-list-card'; describe('Role List', () => { it('renders list of roles', async () => { diff --git a/packages/dashboard/src/components/admin/role-list-page.tsx b/packages/dashboard/src/components/admin/role-list-page.tsx index 67ef880e3..3334090c8 100644 --- a/packages/dashboard/src/components/admin/role-list-page.tsx +++ b/packages/dashboard/src/components/admin/role-list-page.tsx @@ -1,7 +1,7 @@ import React from 'react'; +import { getApiErrorMessage } from '../../utils/api'; import { RmfAppContext } from '../rmf-app'; -import { getApiErrorMessage } from '../utils'; import { adminPageClasses, AdminPageContainer } from './page-css'; import { RoleListCard } from './role-list-card'; diff --git a/packages/dashboard/src/components/admin/tests/drawer.test.tsx b/packages/dashboard/src/components/admin/tests/drawer.test.tsx deleted file mode 100644 index c3b54635f..000000000 --- a/packages/dashboard/src/components/admin/tests/drawer.test.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { describe, it } from 'vitest'; - -import { render } from '../../tests/test-utils'; -import { AdminDrawer } from '../drawer'; - -describe('AdminDrawer', () => { - it('smoke test', () => { - render(); - }); -}); diff --git a/packages/dashboard/src/components/admin/user-list-card.stories.tsx b/packages/dashboard/src/components/admin/user-list-card.stories.tsx index a0a4690d7..797090ef2 100644 --- a/packages/dashboard/src/components/admin/user-list-card.stories.tsx +++ b/packages/dashboard/src/components/admin/user-list-card.stories.tsx @@ -1,13 +1,15 @@ -import { Meta, StoryFn } from '@storybook/react'; +import { Meta, StoryObj } from '@storybook/react'; import { MemoryRouter } from 'react-router'; -import { UserListCard, UserListCardProps } from './user-list-card'; +import { UserListCard } from './user-list-card'; export default { title: 'Admin/User List Card', component: UserListCard, } satisfies Meta; +type Story = StoryObj; + const users: string[] = []; for (let i = 0; i < 100; i++) { users.push(`user${i + 1}`); @@ -18,8 +20,9 @@ async function searchUsers(search: string, limit: number, offset: number) { return users.filter((u) => u.startsWith(search)).slice(offset, offset + limit); } -export const Default: StoryFn = (args) => { - return ( +export const Default: Story = { + storyName: 'User List Card', + render: (args) => ( = (args) => { createUser={() => new Promise((res) => setTimeout(res, 100))} /> - ); + ), }; - -Default.storyName = 'User List Card'; diff --git a/packages/dashboard/src/components/admin/tests/user-list-card.test.tsx b/packages/dashboard/src/components/admin/user-list-card.test.tsx similarity index 96% rename from packages/dashboard/src/components/admin/tests/user-list-card.test.tsx rename to packages/dashboard/src/components/admin/user-list-card.test.tsx index d9d679ad3..2d5c9c6e1 100644 --- a/packages/dashboard/src/components/admin/tests/user-list-card.test.tsx +++ b/packages/dashboard/src/components/admin/user-list-card.test.tsx @@ -3,7 +3,7 @@ import userEvent from '@testing-library/user-event'; import { MemoryRouter } from 'react-router'; import { describe, expect, it, vi } from 'vitest'; -import { UserListCard } from '../user-list-card'; +import { UserListCard } from './user-list-card'; describe('UserListCard', () => { it('opens delete dialog when button is clicked', async () => { diff --git a/packages/dashboard/src/components/admin/user-list-page.tsx b/packages/dashboard/src/components/admin/user-list-page.tsx index f0615d9e2..12071b9c7 100644 --- a/packages/dashboard/src/components/admin/user-list-page.tsx +++ b/packages/dashboard/src/components/admin/user-list-page.tsx @@ -1,7 +1,7 @@ import React from 'react'; +import { getApiErrorMessage } from '../../utils/api'; import { RmfAppContext } from '../rmf-app'; -import { getApiErrorMessage } from '../utils'; import { adminPageClasses, AdminPageContainer } from './page-css'; import { UserListCard } from './user-list-card'; diff --git a/packages/dashboard/src/components/admin/user-profile-page.tsx b/packages/dashboard/src/components/admin/user-profile-page.tsx index 86571712f..662abbdc0 100644 --- a/packages/dashboard/src/components/admin/user-profile-page.tsx +++ b/packages/dashboard/src/components/admin/user-profile-page.tsx @@ -5,8 +5,8 @@ import React from 'react'; import { useAsync } from 'react-components'; import { useParams } from 'react-router'; +import { getApiErrorMessage } from '../../utils/api'; import { RmfAppContext } from '../rmf-app'; -import { getApiErrorMessage } from '../utils'; import { ManageRolesCard } from './manage-roles-dialog'; import { adminPageClasses, AdminPageContainer } from './page-css'; import { UserProfileCard } from './user-profile'; diff --git a/packages/dashboard/src/components/admin/user-profile.stories.tsx b/packages/dashboard/src/components/admin/user-profile.stories.tsx index 7a54b114d..dc8b59796 100644 --- a/packages/dashboard/src/components/admin/user-profile.stories.tsx +++ b/packages/dashboard/src/components/admin/user-profile.stories.tsx @@ -1,8 +1,8 @@ -import { Meta, StoryFn } from '@storybook/react'; +import { Meta, StoryObj } from '@storybook/react'; import { User } from 'api-client'; import React from 'react'; -import { UserProfileCard, UserProfileCardProps } from './user-profile'; +import { UserProfileCard } from './user-profile'; export default { title: 'Admin/User Profile Card', @@ -16,22 +16,25 @@ export default { }, } satisfies Meta; -export const Default: StoryFn = (args) => { - const [user, setUser] = React.useState({ - username: 'example', - is_admin: false, - roles: [], - }); - return ( - { - await new Promise((res) => setTimeout(res, 100)); - setUser((prev) => ({ ...prev, is_admin: admin })); - }} - > - ); -}; +type Story = StoryObj; -Default.storyName = 'User Profile Card'; +export const Default: Story = { + storyName: 'User Profile Card', + render: (args) => { + const [user, setUser] = React.useState({ + username: 'example', + is_admin: false, + roles: [], + }); + return ( + { + await new Promise((res) => setTimeout(res, 100)); + setUser((prev) => ({ ...prev, is_admin: admin })); + }} + > + ); + }, +}; diff --git a/packages/dashboard/src/components/admin/tests/user-profile.test.tsx b/packages/dashboard/src/components/admin/user-profile.test.tsx similarity index 95% rename from packages/dashboard/src/components/admin/tests/user-profile.test.tsx rename to packages/dashboard/src/components/admin/user-profile.test.tsx index 8f8fb8c08..9c4a5919e 100644 --- a/packages/dashboard/src/components/admin/tests/user-profile.test.tsx +++ b/packages/dashboard/src/components/admin/user-profile.test.tsx @@ -2,7 +2,7 @@ import { render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { describe, expect, it, vi } from 'vitest'; -import { UserProfileCard } from '../user-profile'; +import { UserProfileCard } from './user-profile'; describe('UserProfileCard', () => { it('renders username', () => { diff --git a/packages/dashboard/src/components/app-base.tsx b/packages/dashboard/src/components/app-base.tsx index 329971c10..76ff446cc 100644 --- a/packages/dashboard/src/components/app-base.tsx +++ b/packages/dashboard/src/components/app-base.tsx @@ -11,7 +11,7 @@ import { import { ThemeProvider } from '@mui/material/styles'; import React from 'react'; -import { loadSettings, saveSettings, Settings } from '../settings'; +import { loadSettings, saveSettings, Settings } from '../services/settings'; import { AlertManager } from './alert-manager'; import { AppController, AppControllerContext, SettingsContext } from './app-contexts'; import { AppEvents } from './app-events'; diff --git a/packages/dashboard/src/components/app-contexts.tsx b/packages/dashboard/src/components/app-contexts.tsx index 51bde179c..c48a7df99 100644 --- a/packages/dashboard/src/components/app-contexts.tsx +++ b/packages/dashboard/src/components/app-contexts.tsx @@ -1,7 +1,7 @@ import { AlertProps } from '@mui/material'; import React from 'react'; -import { defaultSettings, Settings } from '../settings'; +import { defaultSettings, Settings } from '../services/settings'; export const SettingsContext = React.createContext(defaultSettings()); diff --git a/packages/dashboard/src/components/tests/appbar.test.tsx b/packages/dashboard/src/components/appbar.test.tsx similarity index 84% rename from packages/dashboard/src/components/tests/appbar.test.tsx rename to packages/dashboard/src/components/appbar.test.tsx index 806163ba2..6f4e546d6 100644 --- a/packages/dashboard/src/components/tests/appbar.test.tsx +++ b/packages/dashboard/src/components/appbar.test.tsx @@ -3,12 +3,21 @@ import userEvent from '@testing-library/user-event'; import React from 'react'; import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { AuthenticatorContext, Resources, ResourcesContext } from '../../app-config'; -import { StubAuthenticator, UserProfile, UserProfileContext } from '../../auth'; -import { AppController, AppControllerContext } from '../app-contexts'; -import AppBar from '../appbar'; -import { render } from '../tests/test-utils'; -import { makeMockAppController } from './mock-app-controller'; +import { AuthenticatorContext, Resources, ResourcesContext } from '../app-config'; +import { UserProfile } from '../services/authenticator'; +import { StubAuthenticator } from '../services/stub-authenticator'; +import { render } from '../utils/test-utils.test'; +import { AppController, AppControllerContext } from './app-contexts'; +import AppBar from './appbar'; +import { UserProfileContext } from './user-profile-provider'; + +function makeMockAppController(): AppController { + return { + updateSettings: vi.fn(), + showAlert: vi.fn(), + setExtraAppbarIcons: vi.fn(), + }; +} describe('AppBar', () => { let appController: AppController; diff --git a/packages/dashboard/src/components/appbar.tsx b/packages/dashboard/src/components/appbar.tsx index 4487642cb..610381eb4 100644 --- a/packages/dashboard/src/components/appbar.tsx +++ b/packages/dashboard/src/components/appbar.tsx @@ -57,7 +57,6 @@ import { AuthenticatorContext, ResourcesContext, } from '../app-config'; -import { UserProfileContext } from '../auth'; import { useCreateTaskFormData } from '../hooks/useCreateTaskForm'; import useGetUsername from '../hooks/useFetchUser'; import { @@ -67,11 +66,12 @@ import { DashboardRoute, RobotsRoute, TasksRoute, -} from '../util/url'; +} from '../utils/url'; import { AppControllerContext, SettingsContext } from './app-contexts'; import { AppEvents } from './app-events'; import { RmfAppContext } from './rmf-app'; import { toApiSchedule } from './tasks/utils'; +import { UserProfileContext } from './user-profile-provider'; const StyledIconButton = styled(IconButton)(({ theme }) => ({ fontSize: theme.spacing(4), // spacing = 8 diff --git a/packages/dashboard/src/components/dashboard.tsx b/packages/dashboard/src/components/dashboard.tsx deleted file mode 100644 index 6042317fa..000000000 --- a/packages/dashboard/src/components/dashboard.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import { WorkspaceState } from './workspace'; - -export const dashboardWorkspace: WorkspaceState = { - layout: [{ i: 'map', x: 0, y: 0, w: 12, h: 12 }], - windows: [{ key: 'map', appName: 'Map' }], -}; diff --git a/packages/dashboard/src/components/door-summary.tsx b/packages/dashboard/src/components/door-summary.tsx index 2f40001c5..a4d40d651 100644 --- a/packages/dashboard/src/components/door-summary.tsx +++ b/packages/dashboard/src/components/door-summary.tsx @@ -5,8 +5,8 @@ import { doorModeToOpModeString } from 'react-components'; import { base, doorModeToString, DoorTableData, doorTypeToString } from 'react-components'; import { Door as DoorModel } from 'rmf-models/ros/rmf_building_map_msgs/msg'; +import { getApiErrorMessage } from '../utils/api'; import { RmfAppContext } from './rmf-app'; -import { getApiErrorMessage } from './utils'; interface DoorSummaryProps { onClose: () => void; diff --git a/packages/dashboard/src/components/doors-app.tsx b/packages/dashboard/src/components/doors-app.tsx index 5e78019e5..320cbfdf8 100644 --- a/packages/dashboard/src/components/doors-app.tsx +++ b/packages/dashboard/src/components/doors-app.tsx @@ -4,10 +4,10 @@ import { DoorDataGridTable, DoorTableData } from 'react-components'; import { DoorMode as RmfDoorMode } from 'rmf-models/ros/rmf_door_msgs/msg/DoorMode'; import { throttleTime } from 'rxjs'; +import { getApiErrorMessage } from '../utils/api'; import { AppEvents } from './app-events'; import { createMicroApp } from './micro-app'; import { RmfAppContext } from './rmf-app'; -import { getApiErrorMessage } from './utils'; export const DoorsApp = createMicroApp('Doors', () => { const rmf = React.useContext(RmfAppContext); diff --git a/packages/dashboard/src/components/index.ts b/packages/dashboard/src/components/index.ts new file mode 100644 index 000000000..26bcfb24b --- /dev/null +++ b/packages/dashboard/src/components/index.ts @@ -0,0 +1,8 @@ +export * from './admin'; +export * from './app-base'; +export * from './app-contexts'; +export * from './app-events'; +export * from './login-card'; +export * from './private-route'; +export * from './rmf-app'; +export * from './workspace'; diff --git a/packages/dashboard/src/components/lift-summary.tsx b/packages/dashboard/src/components/lift-summary.tsx index a4c65c844..b7bbc2e5f 100644 --- a/packages/dashboard/src/components/lift-summary.tsx +++ b/packages/dashboard/src/components/lift-summary.tsx @@ -11,8 +11,8 @@ import { Lift } from 'api-client'; import React from 'react'; import { base, doorStateToString, liftModeToString, LiftTableData } from 'react-components'; +import { getApiErrorMessage } from '../utils/api'; import { RmfAppContext } from './rmf-app'; -import { getApiErrorMessage } from './utils'; interface LiftSummaryProps { onClose: () => void; diff --git a/packages/dashboard/src/components/lifts-app.tsx b/packages/dashboard/src/components/lifts-app.tsx index 83ad7f12f..3aa0d4dfd 100644 --- a/packages/dashboard/src/components/lifts-app.tsx +++ b/packages/dashboard/src/components/lifts-app.tsx @@ -5,11 +5,11 @@ import { LiftDataGridTable, LiftTableData } from 'react-components'; import { LiftRequest as RmfLiftRequest } from 'rmf-models/ros/rmf_lift_msgs/msg'; import { throttleTime } from 'rxjs'; +import { getApiErrorMessage } from '../utils/api'; import { AppEvents } from './app-events'; import { LiftSummary } from './lift-summary'; import { createMicroApp } from './micro-app'; import { RmfAppContext } from './rmf-app'; -import { getApiErrorMessage } from './utils'; export const LiftsApp = createMicroApp('Lifts', () => { const rmf = React.useContext(RmfAppContext); diff --git a/packages/dashboard/src/components/login-card.stories.tsx b/packages/dashboard/src/components/login-card.stories.tsx new file mode 100644 index 000000000..6aa2ea3fb --- /dev/null +++ b/packages/dashboard/src/components/login-card.stories.tsx @@ -0,0 +1,25 @@ +import { Meta, StoryObj } from '@storybook/react'; + +import { LoginCard } from './login-card'; + +export default { + title: 'Login', + component: LoginCard, + argTypes: { + title: { + defaultValue: 'Title', + }, + logo: { + control: { + disable: true, + }, + }, + }, +} satisfies Meta; + +type Story = StoryObj; + +export const Default: Story = { + storyName: 'Login Card', + render: (args) => , +}; diff --git a/packages/dashboard/src/auth/login-card.tsx b/packages/dashboard/src/components/login-card.tsx similarity index 100% rename from packages/dashboard/src/auth/login-card.tsx rename to packages/dashboard/src/components/login-card.tsx diff --git a/packages/dashboard/src/components/map-app.tsx b/packages/dashboard/src/components/map-app.tsx index d7459ac7d..5709bc8a0 100644 --- a/packages/dashboard/src/components/map-app.tsx +++ b/packages/dashboard/src/components/map-app.tsx @@ -29,7 +29,7 @@ import { FleetResource, ResourcesContext, } from '../app-config'; -import { TrajectoryData } from '../managers/robot-trajectory-manager'; +import { TrajectoryData } from '../services/robot-trajectory-manager'; import { AppControllerContext } from './app-contexts'; import { AppEvents } from './app-events'; import { DoorSummary } from './door-summary'; diff --git a/packages/dashboard/src/auth/private-route.test.tsx b/packages/dashboard/src/components/private-route.test.tsx similarity index 100% rename from packages/dashboard/src/auth/private-route.test.tsx rename to packages/dashboard/src/components/private-route.test.tsx diff --git a/packages/dashboard/src/auth/private-route.tsx b/packages/dashboard/src/components/private-route.tsx similarity index 100% rename from packages/dashboard/src/auth/private-route.tsx rename to packages/dashboard/src/components/private-route.tsx diff --git a/packages/dashboard/src/components/rmf-app/index.tsx b/packages/dashboard/src/components/rmf-app.tsx similarity index 81% rename from packages/dashboard/src/components/rmf-app/index.tsx rename to packages/dashboard/src/components/rmf-app.tsx index 9f9288b36..e33ec8be5 100644 --- a/packages/dashboard/src/components/rmf-app/index.tsx +++ b/packages/dashboard/src/components/rmf-app.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import { AppConfigContext, AuthenticatorContext } from '../../app-config'; -import { UserProfileProvider } from '../../auth'; -import { RmfIngress } from './rmf-ingress'; +import { AppConfigContext, AuthenticatorContext } from '../app-config'; +import { RmfIngress } from '../services/rmf-ingress'; +import { UserProfileProvider } from './user-profile-provider'; -export * from './rmf-ingress'; +export * from '../services/rmf-ingress'; export const RmfAppContext = React.createContext(undefined); diff --git a/packages/dashboard/src/components/robots/robot-mutex-group-app.tsx b/packages/dashboard/src/components/robots/robot-mutex-group-app.tsx index 5ed74b00c..67301c66e 100644 --- a/packages/dashboard/src/components/robots/robot-mutex-group-app.tsx +++ b/packages/dashboard/src/components/robots/robot-mutex-group-app.tsx @@ -2,9 +2,9 @@ import { TableContainer, Typography } from '@mui/material'; import React from 'react'; import { ConfirmationDialog, MutexGroupData, MutexGroupTable } from 'react-components'; +import { AppControllerContext } from '../app-contexts'; import { createMicroApp } from '../micro-app'; import { RmfAppContext } from '../rmf-app'; -import { AppControllerContext } from './../app-contexts'; const RefreshMutexGroupTableInterval = 5000; diff --git a/packages/dashboard/src/components/robots/robots-workspace.tsx b/packages/dashboard/src/components/robots/robots-workspace.tsx deleted file mode 100644 index 78526533f..000000000 --- a/packages/dashboard/src/components/robots/robots-workspace.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { WorkspaceState } from '../workspace'; - -export const robotsWorkspace: WorkspaceState = { - layout: [ - { i: 'robots', x: 0, y: 0, w: 7, h: 4 }, - { i: 'map', x: 8, y: 0, w: 5, h: 8 }, - { i: 'doors', x: 0, y: 0, w: 7, h: 4 }, - { i: 'lifts', x: 0, y: 0, w: 7, h: 4 }, - { i: 'mutexGroups', x: 8, y: 0, w: 5, h: 4 }, - ], - windows: [ - { key: 'robots', appName: 'Robots' }, - { key: 'map', appName: 'Map' }, - { key: 'doors', appName: 'Doors' }, - { key: 'lifts', appName: 'Lifts' }, - { key: 'mutexGroups', appName: 'Mutex Groups' }, - ], -}; diff --git a/packages/dashboard/src/components/tasks/tests/make-tasks.ts b/packages/dashboard/src/components/tasks/make-tasks.test.ts similarity index 100% rename from packages/dashboard/src/components/tasks/tests/make-tasks.ts rename to packages/dashboard/src/components/tasks/make-tasks.test.ts diff --git a/packages/dashboard/src/components/tasks/task-cancellation.tsx b/packages/dashboard/src/components/tasks/task-cancellation.tsx index 4038ece41..a8b253f71 100644 --- a/packages/dashboard/src/components/tasks/task-cancellation.tsx +++ b/packages/dashboard/src/components/tasks/task-cancellation.tsx @@ -3,11 +3,12 @@ import { TaskStateOutput as TaskState } from 'api-client'; import React from 'react'; import { ConfirmationDialog } from 'react-components'; -import { UserProfile, UserProfileContext } from '../../auth'; +import { UserProfile } from '../../services/authenticator'; +import { Enforcer } from '../../services/permissions'; import { AppControllerContext } from '../app-contexts'; import { AppEvents } from '../app-events'; -import { Enforcer } from '../permissions'; import { RmfAppContext } from '../rmf-app'; +import { UserProfileContext } from '../user-profile-provider'; export interface TaskCancelButtonProp extends ButtonProps { taskId: string | null; diff --git a/packages/dashboard/src/components/tasks/tests/task-logs.test.tsx b/packages/dashboard/src/components/tasks/task-logs.test.tsx similarity index 69% rename from packages/dashboard/src/components/tasks/tests/task-logs.test.tsx rename to packages/dashboard/src/components/tasks/task-logs.test.tsx index fb46ad267..1721cf7bd 100644 --- a/packages/dashboard/src/components/tasks/tests/task-logs.test.tsx +++ b/packages/dashboard/src/components/tasks/task-logs.test.tsx @@ -1,8 +1,8 @@ import { it, Mock, vi } from 'vitest'; -import { render } from '../../tests/test-utils'; -import { TaskLogs } from '../task-logs'; -import { makeTaskLog, makeTaskState } from './make-tasks'; +import { render } from '../../utils/test-utils.test'; +import { makeTaskLog, makeTaskState } from './make-tasks.test'; +import { TaskLogs } from './task-logs'; it('renders without crashing', async () => { URL.createObjectURL = vi.fn(); diff --git a/packages/dashboard/src/components/tasks/tasks-workspace.tsx b/packages/dashboard/src/components/tasks/tasks-workspace.tsx deleted file mode 100644 index c3e43d43d..000000000 --- a/packages/dashboard/src/components/tasks/tasks-workspace.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { WorkspaceState } from '../workspace'; - -export const tasksWorkspace: WorkspaceState = { - layout: [ - { i: 'tasks', x: 0, y: 0, w: 7, h: 12 }, - { i: 'map', x: 8, y: 0, w: 5, h: 12 }, - ], - windows: [ - { key: 'tasks', appName: 'Tasks' }, - { key: 'map', appName: 'Map' }, - ], -}; diff --git a/packages/dashboard/src/components/tests/mock-app-controller.ts b/packages/dashboard/src/components/tests/mock-app-controller.ts deleted file mode 100644 index f8a882d18..000000000 --- a/packages/dashboard/src/components/tests/mock-app-controller.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { vi } from 'vitest'; - -import { AppController } from '../app-contexts'; - -export function makeMockAppController(): AppController { - return { - updateSettings: vi.fn(), - showAlert: vi.fn(), - setExtraAppbarIcons: vi.fn(), - }; -} diff --git a/packages/dashboard/src/auth/user-profile.tsx b/packages/dashboard/src/components/user-profile-provider.tsx similarity index 90% rename from packages/dashboard/src/auth/user-profile.tsx rename to packages/dashboard/src/components/user-profile-provider.tsx index fba668e34..44a6c2390 100644 --- a/packages/dashboard/src/auth/user-profile.tsx +++ b/packages/dashboard/src/components/user-profile-provider.tsx @@ -1,12 +1,8 @@ -import { Configuration, DefaultApi, Permission, User } from 'api-client'; +import { Configuration, DefaultApi } from 'api-client'; import React from 'react'; -import Authenticator from './authenticator'; - -export interface UserProfile { - user: User; - permissions: Permission[]; -} +import { UserProfile } from '../services/authenticator'; +import Authenticator from '../services/authenticator'; export const UserProfileContext = React.createContext(null); diff --git a/packages/dashboard/src/index.tsx b/packages/dashboard/src/index.tsx index 9bbd8bce9..62c8c7d2f 100644 --- a/packages/dashboard/src/index.tsx +++ b/packages/dashboard/src/index.tsx @@ -2,7 +2,7 @@ import { LocalizationProvider } from 'react-components'; import ReactDOM from 'react-dom/client'; import { BrowserRouter } from 'react-router-dom'; -import App from './components/app'; +import App from './app'; const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement); root.render( diff --git a/packages/dashboard/src/pages/index.ts b/packages/dashboard/src/pages/index.ts new file mode 100644 index 000000000..a4d80b3ab --- /dev/null +++ b/packages/dashboard/src/pages/index.ts @@ -0,0 +1 @@ +export * from './login-page'; diff --git a/packages/dashboard/src/pages/login-page.stories.tsx b/packages/dashboard/src/pages/login-page.stories.tsx new file mode 100644 index 000000000..9d2d3b0e7 --- /dev/null +++ b/packages/dashboard/src/pages/login-page.stories.tsx @@ -0,0 +1,25 @@ +import { Meta, StoryObj } from '@storybook/react'; + +import { LoginPage } from './login-page'; + +export default { + title: 'Login', + component: LoginPage, + argTypes: { + title: { + defaultValue: 'Title', + }, + logo: { + control: { + disable: true, + }, + }, + }, +} satisfies Meta; + +type Story = StoryObj; + +export const Default: Story = { + storyName: 'LoginPage', + render: (args) => , +}; diff --git a/packages/dashboard/src/auth/login-page.test.tsx b/packages/dashboard/src/pages/login-page.test.tsx similarity index 100% rename from packages/dashboard/src/auth/login-page.test.tsx rename to packages/dashboard/src/pages/login-page.test.tsx diff --git a/packages/dashboard/src/auth/login-page.tsx b/packages/dashboard/src/pages/login-page.tsx similarity index 91% rename from packages/dashboard/src/auth/login-page.tsx rename to packages/dashboard/src/pages/login-page.tsx index 0042fa89f..2716c776d 100644 --- a/packages/dashboard/src/auth/login-page.tsx +++ b/packages/dashboard/src/pages/login-page.tsx @@ -1,6 +1,6 @@ import { styled } from '@mui/material'; -import { LoginCard, LoginCardProps } from './login-card'; +import { LoginCard, LoginCardProps } from '../components'; const prefix = 'login-page'; const classes = { diff --git a/packages/dashboard/src/managers/__mocks__/robot-trajectory-manager.ts b/packages/dashboard/src/services/__mocks__/robot-trajectory-manager.ts similarity index 100% rename from packages/dashboard/src/managers/__mocks__/robot-trajectory-manager.ts rename to packages/dashboard/src/services/__mocks__/robot-trajectory-manager.ts diff --git a/packages/dashboard/src/managers/__mocks__/trajectories.json b/packages/dashboard/src/services/__mocks__/trajectories.json similarity index 100% rename from packages/dashboard/src/managers/__mocks__/trajectories.json rename to packages/dashboard/src/services/__mocks__/trajectories.json diff --git a/packages/dashboard/src/auth/authenticator.ts b/packages/dashboard/src/services/authenticator.ts similarity index 87% rename from packages/dashboard/src/auth/authenticator.ts rename to packages/dashboard/src/services/authenticator.ts index e061dddc1..2d510cc46 100644 --- a/packages/dashboard/src/auth/authenticator.ts +++ b/packages/dashboard/src/services/authenticator.ts @@ -1,3 +1,4 @@ +import { Permission, User } from 'api-client'; import EventEmitter from 'eventemitter3'; export type AuthenticatorEventType = { @@ -5,6 +6,11 @@ export type AuthenticatorEventType = { tokenRefresh: null; }; +export interface UserProfile { + user: User; + permissions: Permission[]; +} + export interface Authenticator extends EventEmitter { readonly user?: string; readonly token?: string; diff --git a/packages/dashboard/src/auth/keycloak.ts b/packages/dashboard/src/services/keycloak.ts similarity index 100% rename from packages/dashboard/src/auth/keycloak.ts rename to packages/dashboard/src/services/keycloak.ts diff --git a/packages/dashboard/src/managers/negotiation-status-manager.ts b/packages/dashboard/src/services/negotiation-status-manager.ts similarity index 99% rename from packages/dashboard/src/managers/negotiation-status-manager.ts rename to packages/dashboard/src/services/negotiation-status-manager.ts index f84576859..dcb5ffaaf 100644 --- a/packages/dashboard/src/managers/negotiation-status-manager.ts +++ b/packages/dashboard/src/services/negotiation-status-manager.ts @@ -1,4 +1,4 @@ -import { Authenticator } from '../auth'; +import { Authenticator } from './authenticator'; import { Trajectory } from './robot-trajectory-manager'; import TrajectorySocketManager from './trajectory-socket-manager'; diff --git a/packages/dashboard/src/components/permissions.ts b/packages/dashboard/src/services/permissions.ts similarity index 94% rename from packages/dashboard/src/components/permissions.ts rename to packages/dashboard/src/services/permissions.ts index 3c8afdb0b..5bb268b54 100644 --- a/packages/dashboard/src/components/permissions.ts +++ b/packages/dashboard/src/services/permissions.ts @@ -1,5 +1,5 @@ // import { Task } from 'api-client'; -import { UserProfile } from '../auth'; +import { UserProfile } from './authenticator'; export enum RmfAction { TaskRead = 'task_read', diff --git a/packages/dashboard/src/components/rmf-app/rmf-ingress.ts b/packages/dashboard/src/services/rmf-ingress.ts similarity index 96% rename from packages/dashboard/src/components/rmf-app/rmf-ingress.ts rename to packages/dashboard/src/services/rmf-ingress.ts index 313386c54..f68cfbf84 100644 --- a/packages/dashboard/src/components/rmf-app/rmf-ingress.ts +++ b/packages/dashboard/src/services/rmf-ingress.ts @@ -33,13 +33,10 @@ import { import axios from 'axios'; import { map, Observable, shareReplay } from 'rxjs'; -import { AppConfig } from '../../app-config'; -import { Authenticator } from '../../auth'; -import { NegotiationStatusManager } from '../../managers/negotiation-status-manager'; -import { - DefaultTrajectoryManager, - RobotTrajectoryManager, -} from '../../managers/robot-trajectory-manager'; +import { AppConfig } from '../app-config'; +import { Authenticator } from './authenticator'; +import { NegotiationStatusManager } from './negotiation-status-manager'; +import { DefaultTrajectoryManager, RobotTrajectoryManager } from './robot-trajectory-manager'; export class RmfIngress { // This should be private because socketio does not support "replaying" subscription. If diff --git a/packages/dashboard/src/managers/robot-trajectory-manager.ts b/packages/dashboard/src/services/robot-trajectory-manager.ts similarity index 98% rename from packages/dashboard/src/managers/robot-trajectory-manager.ts rename to packages/dashboard/src/services/robot-trajectory-manager.ts index a6d4d910b..11303974c 100644 --- a/packages/dashboard/src/managers/robot-trajectory-manager.ts +++ b/packages/dashboard/src/services/robot-trajectory-manager.ts @@ -1,6 +1,6 @@ import { Knot } from 'react-components'; -import { Authenticator } from '../auth'; +import { Authenticator } from './authenticator'; import TrajectorySocketManager from './trajectory-socket-manager'; // RawVelocity received from server is in this format (x, y, theta) diff --git a/packages/dashboard/src/settings.ts b/packages/dashboard/src/services/settings.ts similarity index 100% rename from packages/dashboard/src/settings.ts rename to packages/dashboard/src/services/settings.ts diff --git a/packages/dashboard/src/auth/stub.ts b/packages/dashboard/src/services/stub-authenticator.ts similarity index 100% rename from packages/dashboard/src/auth/stub.ts rename to packages/dashboard/src/services/stub-authenticator.ts diff --git a/packages/dashboard/src/managers/trajectory-socket-manager.ts b/packages/dashboard/src/services/trajectory-socket-manager.ts similarity index 100% rename from packages/dashboard/src/managers/trajectory-socket-manager.ts rename to packages/dashboard/src/services/trajectory-socket-manager.ts diff --git a/packages/dashboard/src/components/utils.ts b/packages/dashboard/src/utils/api.ts similarity index 100% rename from packages/dashboard/src/components/utils.ts rename to packages/dashboard/src/utils/api.ts diff --git a/packages/dashboard/src/components/tests/test-utils.tsx b/packages/dashboard/src/utils/test-utils.test.tsx similarity index 91% rename from packages/dashboard/src/components/tests/test-utils.tsx rename to packages/dashboard/src/utils/test-utils.test.tsx index a1917c476..495c6bfe5 100644 --- a/packages/dashboard/src/components/tests/test-utils.tsx +++ b/packages/dashboard/src/utils/test-utils.test.tsx @@ -6,7 +6,8 @@ import React from 'react'; import { rmfLight } from 'react-components'; import { MemoryRouter } from 'react-router'; -import { UserProfile, UserProfileContext } from '../../auth'; +import { UserProfileContext } from '../components/user-profile-provider'; +import { UserProfile } from '../services/authenticator'; export const superUser: UserProfile = { user: { diff --git a/packages/dashboard/src/util/url.ts b/packages/dashboard/src/utils/url.ts similarity index 100% rename from packages/dashboard/src/util/url.ts rename to packages/dashboard/src/utils/url.ts diff --git a/packages/dashboard/vite.config.ts b/packages/dashboard/vite.config.ts index 6cc10bff3..1db6ca3e6 100644 --- a/packages/dashboard/vite.config.ts +++ b/packages/dashboard/vite.config.ts @@ -53,5 +53,6 @@ export default defineConfig({ test: { environment: 'jsdom', globals: true, + passWithNoTests: true, }, }); diff --git a/packages/react-components/lib/alert-dialog.stories.tsx b/packages/react-components/lib/alert-dialog.stories.tsx index a24b689e7..2a6b02758 100644 --- a/packages/react-components/lib/alert-dialog.stories.tsx +++ b/packages/react-components/lib/alert-dialog.stories.tsx @@ -1,7 +1,7 @@ -import { Meta, StoryFn } from '@storybook/react'; +import { Meta, StoryObj } from '@storybook/react'; import React from 'react'; -import { AlertContent, AlertDialog, DialogAlertProps } from './alert-dialog'; +import { AlertContent, AlertDialog } from './alert-dialog'; const buildAlertDialogContent = (): AlertContent[] => { return [ @@ -24,19 +24,24 @@ export default { component: AlertDialog, } satisfies Meta; -export const AlertDialogComponent: StoryFn = () => { - const [acknowledged, setAcknowledged] = React.useState(false); - const [dismissed, setDismissed] = React.useState(false); - return ( - setDismissed(true)} - onAcknowledge={() => setAcknowledged(true)} - title={`${acknowledged ? 'acknowledged!' : 'default'} and ${ - dismissed ? 'dismissed!' : 'default' - }`} - progress={1} - alertContents={buildAlertDialogContent()} - backgroundColor={'ffff'} - > - ); +type Story = StoryObj; + +export const Default: Story = { + storyName: 'Alert Dialog', + render: () => { + const [acknowledged, setAcknowledged] = React.useState(false); + const [dismissed, setDismissed] = React.useState(false); + return ( + setDismissed(true)} + onAcknowledge={() => setAcknowledged(true)} + title={`${acknowledged ? 'acknowledged!' : 'default'} and ${ + dismissed ? 'dismissed!' : 'default' + }`} + progress={1} + alertContents={buildAlertDialogContent()} + backgroundColor={'ffff'} + > + ); + }, }; diff --git a/packages/react-components/lib/confirmation-dialog.stories.tsx b/packages/react-components/lib/confirmation-dialog.stories.tsx index 9e40f8c2c..14c89b4dd 100644 --- a/packages/react-components/lib/confirmation-dialog.stories.tsx +++ b/packages/react-components/lib/confirmation-dialog.stories.tsx @@ -1,7 +1,7 @@ import { Button, Paper, Typography } from '@mui/material'; -import { Meta, StoryFn } from '@storybook/react'; +import { Meta, StoryObj } from '@storybook/react'; -import { ConfirmationDialog, ConfirmationDialogProps } from './confirmation-dialog'; +import { ConfirmationDialog } from './confirmation-dialog'; export default { title: 'Dialog/Confirmation Dialog', @@ -11,8 +11,11 @@ export default { }, } satisfies Meta; -export const Default: StoryFn = (args) => { - return ( +type Story = StoryObj; + +export const Default: Story = { + storyName: 'Confirmation Dialog', + render: (args) => ( = (args) => { Content - ); + ), }; - -Default.storyName = 'Confirmation Dialog'; diff --git a/packages/react-components/lib/doors/door-card.stories.tsx b/packages/react-components/lib/doors/door-card.stories.tsx index d78fafd78..de399883d 100644 --- a/packages/react-components/lib/doors/door-card.stories.tsx +++ b/packages/react-components/lib/doors/door-card.stories.tsx @@ -1,28 +1,35 @@ import { CardActions } from '@mui/material'; -import { Meta, StoryFn } from '@storybook/react'; +import { Meta, StoryObj } from '@storybook/react'; import { Door } from 'rmf-models/ros/rmf_building_map_msgs/msg'; import { DoorMode } from 'rmf-models/ros/rmf_door_msgs/msg'; -import { DoorCard, DoorCardProps } from './door-card'; +import { DoorCard } from './door-card'; import { DoorControls } from './door-controls'; export default { title: 'Door Card', + component: DoorCard, } satisfies Meta; -export const Default: StoryFn = (args) => ; -Default.args = { - name: 'main_door', - level: 'L1', - mode: DoorMode.MODE_OPEN, - type: Door.DOOR_TYPE_SINGLE_SWING, +type Story = StoryObj; + +export const Default: Story = { + args: { + name: 'main_door', + level: 'L1', + mode: DoorMode.MODE_OPEN, + type: Door.DOOR_TYPE_SINGLE_SWING, + }, + render: (args) => , }; -export const WithControls: StoryFn = (args) => ( - - - - - -); -WithControls.args = Default.args; +export const WithControls: Story = { + args: Default.args, + render: (args) => ( + + + + + + ), +}; diff --git a/packages/react-components/lib/error-overlay.stories.tsx b/packages/react-components/lib/error-overlay.stories.tsx index e2f86ba5d..0675023a9 100644 --- a/packages/react-components/lib/error-overlay.stories.tsx +++ b/packages/react-components/lib/error-overlay.stories.tsx @@ -1,5 +1,5 @@ import { styled } from '@mui/material'; -import { Meta, StoryFn } from '@storybook/react'; +import { Meta, StoryObj } from '@storybook/react'; import { ErrorOverlay } from './error-overlay'; import { SimpleInfo, SimpleInfoProps } from './simple-info'; @@ -9,6 +9,8 @@ export default { component: ErrorOverlay, } satisfies Meta; +type Story = StoryObj; + const classes = { container: 'simple-info-testcomponent', }; @@ -34,12 +36,10 @@ function TestComponent() { return ; } -export const ErrorOverlayPanel: StoryFn = (args) => { - return ( - <> - - - - - ); +export const ErrorOverlayPanel: Story = { + render: (args) => ( + + + + ), }; diff --git a/packages/react-components/lib/header-bar.stories.tsx b/packages/react-components/lib/header-bar.stories.tsx index e0b6932aa..fc3591e50 100644 --- a/packages/react-components/lib/header-bar.stories.tsx +++ b/packages/react-components/lib/header-bar.stories.tsx @@ -2,7 +2,7 @@ import AccountCircleIcon from '@mui/icons-material/AccountCircle'; import TabContext from '@mui/lab/TabContext'; import TabPanel from '@mui/lab/TabPanel'; import { IconButton, styled, Toolbar, Typography } from '@mui/material'; -import { Meta, StoryFn } from '@storybook/react'; +import { Meta, StoryObj } from '@storybook/react'; import React from 'react'; import { HeaderBar } from '../lib/header-bar'; @@ -15,104 +15,110 @@ export default { component: HeaderBar, } satisfies Meta; -export const NavBar: StoryFn = () => { - const [value, setValue] = React.useState('building'); +type Story = StoryObj; - const onTabChange = (_event: React.ChangeEvent, newValue: string) => { - setValue(newValue); - }; +export const NavBar: Story = { + render: () => { + const [value, setValue] = React.useState('building'); - return ( - <> - - - - - - - - - tab panel data - - - other tab panel data - - - - ); + const onTabChange = (_event: React.ChangeEvent, newValue: string) => { + setValue(newValue); + }; + + return ( + <> + + + + + + + + + tab panel data + + + other tab panel data + + + + ); + }, }; -export const FullHeaderBar: StoryFn = () => { - const classes = { - toolbar: 'headerbar-story-toolbar', - avatar: 'headerbar-story-avatar', - logo: 'headerbar-story-logo', - }; - const FullHeaderBarStory = styled('div')(({ theme }) => ({ - [`& .${classes.toolbar}`]: { - textAlign: 'right', - flexGrow: -1, - }, - [`& .${classes.avatar}`]: { - flexGrow: 1, - minWidth: theme.spacing(16), - overflow: 'auto', - }, - [`& .${classes.logo}`]: { - maxWidth: 120, - opacity: 1, - }, - })); +export const FullHeaderBar: Story = { + render: () => { + const classes = { + toolbar: 'headerbar-story-toolbar', + avatar: 'headerbar-story-avatar', + logo: 'headerbar-story-logo', + }; + const FullHeaderBarStory = styled('div')(({ theme }) => ({ + [`& .${classes.toolbar}`]: { + textAlign: 'right', + flexGrow: -1, + }, + [`& .${classes.avatar}`]: { + flexGrow: 1, + minWidth: theme.spacing(16), + overflow: 'auto', + }, + [`& .${classes.logo}`]: { + maxWidth: 120, + opacity: 1, + }, + })); - const [value, setValue] = React.useState('building'); + const [value, setValue] = React.useState('building'); - const onTabChange = (_event: React.ChangeEvent, newValue: string) => { - setValue(newValue); - }; + const onTabChange = (_event: React.ChangeEvent, newValue: string) => { + setValue(newValue); + }; - return ( - - - - - - - - - - Powered by Open-RMF - - - - - - - tab panel data - - - other tab panel data - - - - ); + return ( + + + + + + + + + + Powered by Open-RMF + + + + + + + tab panel data + + + other tab panel data + + + + ); + }, }; diff --git a/packages/react-components/lib/info-card.stories.tsx b/packages/react-components/lib/info-card.stories.tsx index 8e59905de..996c6b817 100644 --- a/packages/react-components/lib/info-card.stories.tsx +++ b/packages/react-components/lib/info-card.stories.tsx @@ -1,5 +1,5 @@ import { styled } from '@mui/material'; -import { Meta, StoryFn } from '@storybook/react'; +import { Meta, StoryObj } from '@storybook/react'; import { SimpleInfo } from '../lib'; @@ -16,6 +16,7 @@ const InfoCardRoot = styled('div')(({ theme }) => ({ export default { title: 'Simple Info', + component: SimpleInfo, argTypes: { stringDisplayName: { name: 'String Display Name', @@ -32,36 +33,20 @@ export default { }, } satisfies Meta; -export const SimpleData: StoryFn = ({ - stringDisplayName, - stringValue, - numberDisplayName, - numberValue, - ...args -}) => { - return ( +type Story = StoryObj; + +export const StringData: Story = { + render: (args) => ( - + - ); -}; -SimpleData.args = { - stringDisplayName: 'string', - stringValue: 'value', - numberDisplayName: 'number', - numberValue: 0, + ), }; -export const Array: StoryFn = (args) => { - return ( +export const ArrayData: Story = { + render: (args) => ( - + - ); + ), }; diff --git a/packages/react-components/lib/lifts/lift-card.stories.tsx b/packages/react-components/lib/lifts/lift-card.stories.tsx index 2e7752807..ebb3388de 100644 --- a/packages/react-components/lib/lifts/lift-card.stories.tsx +++ b/packages/react-components/lib/lifts/lift-card.stories.tsx @@ -1,28 +1,35 @@ import { CardActions } from '@mui/material'; -import { Meta, StoryFn } from '@storybook/react'; +import { Meta, StoryObj } from '@storybook/react'; import { LiftState } from 'rmf-models/ros/rmf_lift_msgs/msg'; -import { LiftCard, LiftCardProps } from './lift-card'; +import { LiftCard } from './lift-card'; import { LiftControls } from './lift-controls'; export default { title: 'Lift Card', + component: LiftCard, } satisfies Meta; -export const Default: StoryFn = (args) => ; -Default.args = { - name: 'main_lift', - motionState: LiftState.MOTION_UP, - currentFloor: 'L1', - destinationFloor: 'L2', - doorState: LiftState.DOOR_CLOSED, +type Story = StoryObj; + +export const Default: Story = { + args: { + name: 'main_lift', + motionState: LiftState.MOTION_UP, + currentFloor: 'L1', + destinationFloor: 'L2', + doorState: LiftState.DOOR_CLOSED, + }, + render: (args) => , }; -export const WithControls: StoryFn = (args) => ( - - - - - -); -WithControls.args = Default.args; +export const WithControls: Story = { + args: Default.args, + render: (args) => ( + + + + + + ), +}; diff --git a/packages/react-components/lib/loading.stories.tsx b/packages/react-components/lib/loading.stories.tsx index 29322c006..af6a292f1 100644 --- a/packages/react-components/lib/loading.stories.tsx +++ b/packages/react-components/lib/loading.stories.tsx @@ -1,7 +1,7 @@ import { Button, Typography } from '@mui/material'; -import { Meta, StoryFn } from '@storybook/react'; +import { Meta, StoryObj } from '@storybook/react'; -import { Loading, LoadingProps } from './loading'; +import { Loading } from './loading'; export default { title: 'Loading', @@ -13,8 +13,10 @@ export default { }, } satisfies Meta; -export const LoadingButton: StoryFn = (args) => { - return ( +type Story = StoryObj; + +export const LoadingButton: Story = { + render: (args) => ( <>