Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

merge rmf-auth into dashboard #985

Merged
merged 5 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/dashboard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ on:
- '.github/workflows/dashboard.yml'
- 'packages/dashboard/**'
- 'packages/react-components/**'
- 'packages/rmf-auth/**'
- 'packages/rmf-models/**'
- 'packages/api-client/**'
push:
Expand Down
41 changes: 0 additions & 41 deletions .github/workflows/rmf-auth.yml

This file was deleted.

41 changes: 23 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[![Nightly](https://github.com/open-rmf/rmf-web/actions/workflows/nightly.yml/badge.svg)](https://github.com/open-rmf/rmf-web/actions/workflows/nightly.yml) [![Dashboard End-to-End](https://github.com/open-rmf/rmf-web/actions/workflows/dashboard-e2e.yml/badge.svg)](https://github.com/open-rmf/rmf-web/actions/workflows/dashboard-e2e.yml) [![react-components](https://github.com/open-rmf/rmf-web/workflows/react-components/badge.svg)](https://github.com/open-rmf/rmf-web/actions?query=workflow%3Areact-components+branch%3Amain) [![dashboard](https://github.com/open-rmf/rmf-web/workflows/dashboard/badge.svg)](https://github.com/open-rmf/rmf-web/actions?query=workflow%3Adashboard+branch%3Amain) [![api-server](https://github.com/open-rmf/rmf-web/workflows/api-server/badge.svg)](https://github.com/open-rmf/rmf-web/actions?query=workflow%3Aapi-server+branch%3Amain) [![rmf-auth](https://github.com/open-rmf/rmf-web/actions/workflows/rmf-auth.yml/badge.svg)](https://github.com/open-rmf/rmf-web/actions/workflows/rmf-auth.yml) [![ros-translator](https://github.com/open-rmf/rmf-web/actions/workflows/ros-translator.yml/badge.svg)](https://github.com/open-rmf/rmf-web/actions/workflows/ros-translator.yml) [![api-client](https://github.com/open-rmf/rmf-web/actions/workflows/api-client.yml/badge.svg)](https://github.com/open-rmf/rmf-web/actions/workflows/api-client.yml) [![codecov](https://codecov.io/gh/open-rmf/rmf-web/branch/main/graph/badge.svg)](https://codecov.io/gh/open-rmf/rmf-web)
[![Nightly](https://github.com/open-rmf/rmf-web/actions/workflows/nightly.yml/badge.svg)](https://github.com/open-rmf/rmf-web/actions/workflows/nightly.yml) [![Dashboard End-to-End](https://github.com/open-rmf/rmf-web/actions/workflows/dashboard-e2e.yml/badge.svg)](https://github.com/open-rmf/rmf-web/actions/workflows/dashboard-e2e.yml) [![react-components](https://github.com/open-rmf/rmf-web/workflows/react-components/badge.svg)](https://github.com/open-rmf/rmf-web/actions?query=workflow%3Areact-components+branch%3Amain) [![dashboard](https://github.com/open-rmf/rmf-web/workflows/dashboard/badge.svg)](https://github.com/open-rmf/rmf-web/actions?query=workflow%3Adashboard+branch%3Amain) [![api-server](https://github.com/open-rmf/rmf-web/workflows/api-server/badge.svg)](https://github.com/open-rmf/rmf-web/actions?query=workflow%3Aapi-server+branch%3Amain) [![ros-translator](https://github.com/open-rmf/rmf-web/actions/workflows/ros-translator.yml/badge.svg)](https://github.com/open-rmf/rmf-web/actions/workflows/ros-translator.yml) [![api-client](https://github.com/open-rmf/rmf-web/actions/workflows/api-client.yml/badge.svg)](https://github.com/open-rmf/rmf-web/actions/workflows/api-client.yml) [![codecov](https://codecov.io/gh/open-rmf/rmf-web/branch/main/graph/badge.svg)](https://codecov.io/gh/open-rmf/rmf-web)

# RMF Web

Expand All @@ -21,12 +21,14 @@ Open-RMF Web is a collection of packages that provide a web-based interface for
We currently support [Ubuntu 24.04](https://releases.ubuntu.com/noble/), [ROS 2 Jazzy](https://docs.ros.org/en/jazzy/index.html) and Open-RMF's [22.09](https://github.com/open-rmf/rmf/releases/tag/22.09) release. Other distributions may work as well, but is not guaranteed.

Install pnpm and nodejs

```bash
curl -fsSL https://get.pnpm.io/install.sh | bash -
pnpm env use --global lts
```

For Debian/Ubuntu systems,

```bash
sudo apt install python3-pip python3-venv
```
Expand All @@ -35,26 +37,29 @@ sudo apt install python3-pip python3-venv

Refer to the following documentation for either building from source or installing released binaries:

* [rmf](https://github.com/open-rmf/rmf)
- [rmf](https://github.com/open-rmf/rmf)

> **Note**
> Simulation demos are not part of the released binaries, and therefore a built workspace with at least the [demos repository](https://github.com/open-rmf/rmf_demos) would be required for trying out the web dashboard with simulation.

### Install dependencies

Run

```bash
pnpm install
```

You may also install dependencies for only a subset of the packages

```bash
pnpm install -w --filter <package>...
```

### Launching

Source Open-RMF and launch the dashboard in development mode,

```bash
# For binary installation
source /opt/ros/jazzy/setup.bash
Expand Down Expand Up @@ -117,27 +122,27 @@ pnpm run start

# Contribution guide

* For general contribution guidelines, see [CONTRIBUTING](CONTRIBUTING.md).
* Follow [typescript guidelines](https://basarat.gitbook.io/typescript/styleguide).
* When introducing a new feature or component in [`react-components`](packages/react-components), write tests and stories.
* When introducing a new feature in [`dashboard`](packages/dashboard), write tests as well as [e2e](packages/dashboard-e2e) test whenever possible.
* When introducing API changes with [`api-server`](packages/api-server),
* If the new changes are to be used externally (outside of the web packages, with other Open-RMF packages for example), make changes to [`rmf_api_msgs`](https://github.com/open-rmf/rmf_api_msgs), before generating the required models using [this script](packages/api-server/generate-models.sh) with modified commit hashes.
* Don't forget to update the API client with the newly added changes with [these instructions](packages/api-client/README.md/#generating-rest-api-client).
* Check out the latest API definitions [here](https://open-rmf.github.io/rmf-web/), or visit `/docs` relative to your running server's url, e.g. `http://localhost:8000/docs`.
* Develop the frontend without launching any Open-RMF components using [storybook](packages/dashboard/README.md/#storybook).
* For integration with new devices/infrastructure, check out [Robot Interaction Objects (RIO)](https://github.com/open-rmf/rmf-web/wiki/Robot-Interaction-Objects-(RIO)).
* Update documentation alongside development, and update the [`ros2multirobotbook`](https://osrf.github.io/ros2multirobotbook) where necessary.
- For general contribution guidelines, see [CONTRIBUTING](CONTRIBUTING.md).
- Follow [typescript guidelines](https://basarat.gitbook.io/typescript/styleguide).
- When introducing a new feature or component in [`react-components`](packages/react-components), write tests and stories.
- When introducing a new feature in [`dashboard`](packages/dashboard), write tests as well as [e2e](packages/dashboard-e2e) test whenever possible.
- When introducing API changes with [`api-server`](packages/api-server),
- If the new changes are to be used externally (outside of the web packages, with other Open-RMF packages for example), make changes to [`rmf_api_msgs`](https://github.com/open-rmf/rmf_api_msgs), before generating the required models using [this script](packages/api-server/generate-models.sh) with modified commit hashes.
- Don't forget to update the API client with the newly added changes with [these instructions](packages/api-client/README.md/#generating-rest-api-client).
- Check out the latest API definitions [here](https://open-rmf.github.io/rmf-web/), or visit `/docs` relative to your running server's url, e.g. `http://localhost:8000/docs`.
- Develop the frontend without launching any Open-RMF components using [storybook](packages/dashboard/README.md/#storybook).
- For integration with new devices/infrastructure, check out [Robot Interaction Objects (RIO)](<https://github.com/open-rmf/rmf-web/wiki/Robot-Interaction-Objects-(RIO)>).
- Update documentation alongside development, and update the [`ros2multirobotbook`](https://osrf.github.io/ros2multirobotbook) where necessary.

# Configuration

* See the [rmf-dashboard](packages/dashboard/README.md#configuration) docs for the frontend build-time and run-time configurations.
* See the [api-server](packages/api-server/README.md#configuration) docs for API server run-time configurations.
- See the [rmf-dashboard](packages/dashboard/README.md#configuration) docs for the frontend build-time and run-time configurations.
- See the [api-server](packages/api-server/README.md#configuration) docs for API server run-time configurations.

# Troubleshooting

* If a feature is missing or is not working, it could be only available in an Open-RMF source build, and not in the binaries. Try building Open-RMF from source and source that new workspace before launching the API server. `rmf-web` may use in-development features of Open-RMF.
- If a feature is missing or is not working, it could be only available in an Open-RMF source build, and not in the binaries. Try building Open-RMF from source and source that new workspace before launching the API server. `rmf-web` may use in-development features of Open-RMF.

* Creating tasks from the web dashboard when running a simulated Open-RMF deployment will require the task start time suit simulation time, which starts from unix millis 0. Try creating the same task with a start date of before the year of 1970.
- Creating tasks from the web dashboard when running a simulated Open-RMF deployment will require the task start time suit simulation time, which starts from unix millis 0. Try creating the same task with a start date of before the year of 1970.

* Check if the issue has already been [reported or fixed](https://github.com/open-rmf/rmf-web/issues).
- Check if the issue has already been [reported or fixed](https://github.com/open-rmf/rmf-web/issues).
4 changes: 0 additions & 4 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,3 @@ flags:
paths:
- packages/api-server
carryforward: true
rmf-auth:
paths:
- packages/rmf-auth
carryforward: true
4 changes: 3 additions & 1 deletion packages/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@
"debug": "^4.2.0",
"eventemitter3": "^4.0.7",
"jsdom": "^24.1.1",
"keycloak-js": "^25.0.2",
"react": "^18.2.0",
"react-components": "workspace:*",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.0.13",
"react-grid-layout": "^1.3.4",
"react-router": "^6.14.1",
"react-router-dom": "^6.14.1",
"rmf-auth": "workspace:*",
"rmf-models": "workspace:*",
"rxjs": "^7.5.5",
"three": "^0.166.1"
Expand All @@ -66,11 +66,13 @@
"@testing-library/dom": "^9.3.4",
"@testing-library/react": "^14.2.2",
"@testing-library/user-event": "^14.5.2",
"@types/history": "^5.0.0",
"@vitejs/plugin-react-swc": "^3.7.0",
"@vitest/coverage-v8": "^2.0.4",
"api-server": "file:../api-server",
"concurrently": "^8.2.2",
"eslint": "^8.57.0",
"history": "^5.3.0",
"storybook": "^8.0.5",
"typescript": "~5.4.3",
"vite": "^5.3.5",
Expand Down
2 changes: 1 addition & 1 deletion packages/dashboard/src/app-config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';
import { getDefaultTaskDefinition, TaskDefinition } from 'react-components';
import { Authenticator, KeycloakAuthenticator, StubAuthenticator } from 'rmf-auth';

import appConfigJson from '../app-config.json';
import { Authenticator, KeycloakAuthenticator, StubAuthenticator } from './auth';
import { BasePath } from './util/url';

export interface RobotResource {
Expand Down
7 changes: 7 additions & 0 deletions packages/dashboard/src/auth/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export * from './authenticator';
export * from './keycloak';
export * from './#-card';
export * from './#-page';
export * from './private-route';
export * from './stub';
export * from './user-profile';
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Debug from 'debug';
import EventEmitter from 'eventemitter3';
import Keycloak, { KeycloakInstance } from 'keycloak-js';
import Keycloak from 'keycloak-js';

import { Authenticator, AuthenticatorEventType } from './authenticator';

Expand Down Expand Up @@ -31,7 +31,7 @@ export class KeycloakAuthenticator
*/
constructor(config: Keycloak.KeycloakConfig | string, silentCheckSsoRedirectUri?: string) {
super();
this._inst = Keycloak(config);
this._inst = new Keycloak(config);
this._silentCheckSsoRedirectUri = silentCheckSsoRedirectUri;
}

Expand Down Expand Up @@ -118,7 +118,7 @@ export class KeycloakAuthenticator
}

private _initialized = false;
private _inst: KeycloakInstance;
private _inst: Keycloak;
private _silentCheckSsoRedirectUri?: string;
private _user?: string;
private _isAdmin = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { render } from '@testing-library/react';
import React from 'react';
import { it } from 'vitest';

import { LoginPage } from './#-page';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { styled } from '@mui/material';
import React from 'react';

import { LoginCard, LoginCardProps } from './#-card';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { render } from '@testing-library/react';
import { createMemoryHistory, MemoryHistory } from 'history';
import React from 'react';
import { Router } from 'react-router-dom';
import { beforeEach, describe, expect, it } from 'vitest';

import { PrivateRoute } from './private-route';

Expand All @@ -13,7 +13,7 @@ describe('PrivateRoute', () => {
history.push('/private');
});

test('renders unauthorizedComponent when unauthenticated', () => {
it('renders unauthorizedComponent when unauthenticated', () => {
const root = render(
<Router location={history.location} navigator={history}>
<PrivateRoute path="/private" unauthorizedComponent="test" user={null} />
Expand All @@ -22,7 +22,7 @@ describe('PrivateRoute', () => {
expect(() => root.getByText('test')).not.toThrow();
});

test('renders children when authenticated', () => {
it('renders children when authenticated', () => {
const root = render(
<Router location={history.location} navigator={history}>
<PrivateRoute path="/private" user="test" unauthorizedComponent="unauthorized">
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
/* istanbul ignore file */

import { Configuration, DefaultApi, Permission, User } from 'api-client';
import React from 'react';

import Authenticator from '../authenticator';
import Authenticator from './authenticator';

export interface UserProfile {
user: User;
Expand Down
2 changes: 1 addition & 1 deletion packages/dashboard/src/components/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import './app.css';

import React from 'react';
import { Navigate, Route, Routes } from 'react-router-dom';
import { LoginPage, PrivateRoute } from 'rmf-auth';

import { AppConfigContext, AuthenticatorContext, ResourcesContext } from '../app-config';
import { LoginPage, PrivateRoute } from '../auth';
import {
AdminRoute,
CustomRoute1,
Expand Down
2 changes: 1 addition & 1 deletion packages/dashboard/src/components/appbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ import {
NavigationBar,
} from 'react-components';
import { useLocation, useNavigate } from 'react-router-dom';
import { UserProfileContext } from 'rmf-auth';
import { Subscription } from 'rxjs';

import {
Expand All @@ -58,6 +57,7 @@ import {
AuthenticatorContext,
ResourcesContext,
} from '../app-config';
import { UserProfileContext } from '../auth';
import { useCreateTaskFormData } from '../hooks/useCreateTaskForm';
import useGetUsername from '../hooks/useFetchUser';
import {
Expand Down
2 changes: 1 addition & 1 deletion packages/dashboard/src/components/permissions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// import { Task } from 'api-client';
import { UserProfile } from 'rmf-auth';
import { UserProfile } from '../auth';

export enum RmfAction {
TaskRead = 'task_read',
Expand Down
2 changes: 1 addition & 1 deletion packages/dashboard/src/components/rmf-app/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { UserProfileProvider } from 'rmf-auth';

import { AppConfigContext, AuthenticatorContext } from '../../app-config';
import { UserProfileProvider } from '../../auth';
import { RmfIngress } from './rmf-ingress';

export * from './rmf-ingress';
Expand Down
2 changes: 1 addition & 1 deletion packages/dashboard/src/components/rmf-app/rmf-ingress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ import {
TaskStateOutput as TaskState,
} from 'api-client';
import axios from 'axios';
import { Authenticator } from 'rmf-auth';
import { map, Observable, shareReplay } from 'rxjs';

import { AppConfig } from '../../app-config';
import { Authenticator } from '../../auth';
import { NegotiationStatusManager } from '../../managers/negotiation-status-manager';
import {
DefaultTrajectoryManager,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { Button, ButtonProps, Tooltip, Typography } from '@mui/material';
import { TaskStateOutput as TaskState } from 'api-client';
import React from 'react';
import { ConfirmationDialog } from 'react-components';
import { UserProfile, UserProfileContext } from 'rmf-auth';

import { UserProfile, UserProfileContext } from '../../auth';
import { AppControllerContext } from '../app-contexts';
import { AppEvents } from '../app-events';
import { Enforcer } from '../permissions';
Expand Down
12 changes: 6 additions & 6 deletions packages/dashboard/src/components/tests/appbar.test.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { StubAuthenticator, UserProfile, UserProfileContext } from 'rmf-auth';
import { beforeEach, describe, expect, test, vi } from 'vitest';
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';
Expand All @@ -24,7 +24,7 @@ describe('AppBar', () => {
appController = makeMockAppController();
});

test('renders with navigation bar', () => {
it('renders with navigation bar', () => {
const root = render(
<Base>
<AppBar />
Expand All @@ -33,7 +33,7 @@ describe('AppBar', () => {
expect(root.getAllByRole('tablist').length > 0).toBeTruthy();
});

test('user button is shown when there is an authenticated user', () => {
it('user button is shown when there is an authenticated user', () => {
const profile: UserProfile = {
user: { username: 'test', is_admin: false, roles: [] },
permissions: [],
Expand All @@ -48,7 +48,7 @@ describe('AppBar', () => {
expect(root.getByLabelText('user-btn')).toBeTruthy();
});

test('logout is triggered when logout button is clicked', async () => {
it('logout is triggered when logout button is clicked', async () => {
const authenticator = new StubAuthenticator('test');
const spy = vi.spyOn(authenticator, 'logout').mockImplementation(() => undefined as any);
const profile: UserProfile = {
Expand All @@ -70,7 +70,7 @@ describe('AppBar', () => {
await expect(waitFor(() => expect(spy).toHaveBeenCalledTimes(1))).resolves.not.toThrow();
});

test('uses headerLogo from logo resources manager', async () => {
it('uses headerLogo from logo resources manager', async () => {
const resources: Resources = {
fleets: {},
logos: {
Expand Down
Loading
Loading