diff --git a/e2e/tests/plugin-header.spec.ts b/e2e/tests/plugin-header.spec.ts index 27b42656d..c3ffa9cb5 100755 --- a/e2e/tests/plugin-header.spec.ts +++ b/e2e/tests/plugin-header.spec.ts @@ -16,12 +16,12 @@ test('Load header', async ({ page }) => { await expect( page.getByRole('heading', { name: 'Data Modelling Example App' }) ).toBeVisible() - await expect(page.getByRole('button', { name: 'User' })).toBeVisible() - await expect(page.getByRole('button', { name: 'About' })).toBeVisible() + await expect(page.getByRole('button', { name: 'User' }).nth(1)).toBeVisible() + await expect(page.getByRole('button', { name: 'About' }).nth(1)).toBeVisible() }) test('User info', async ({ page }) => { - await page.getByRole('button', { name: 'User' }).click() + await page.getByRole('button', { name: 'User' }).nth(1).click() await expect(page.getByRole('dialog')).toBeVisible() await expect( page.getByRole('dialog').getByText('User info', { exact: true }) @@ -34,7 +34,7 @@ test('User info', async ({ page }) => { }) test('About', async ({ page }) => { - await page.getByRole('button', { name: 'About' }).click() + await page.getByRole('button', { name: 'About' }).nth(1).click() await expect(page.getByRole('dialog')).toBeVisible() await expect( page @@ -49,7 +49,7 @@ test('About', async ({ page }) => { }) test('Recipe list', async ({ page }) => { - await page.getByRole('button', { name: 'Menu' }).click() + await page.getByRole('button', { name: 'Menu' }).nth(1).click() await page.getByRole('menuitem', { name: 'Edit' }).click() await expect( page.getByTestId('name').getByTestId('form-textfield') diff --git a/e2e/tests/signalApp.spec.ts b/e2e/tests/signalApp.spec.ts index ba8b024ee..f707f6795 100644 --- a/e2e/tests/signalApp.spec.ts +++ b/e2e/tests/signalApp.spec.ts @@ -20,9 +20,9 @@ test('run Create job', async ({ page }) => { page.getByText('Progress tracking not implemented') ).toBeVisible() - await page.getByRole('button', { name: 'Close case1' }).click() - await page.getByRole('button', { name: 'Open' }).click() - await expect(page.locator('.nsewdrag')).toHaveScreenshot({ - maxDiffPixelRatio: 0.25, - }) + // await page.getByRole('button', { name: 'Close case1' }).click() + // await page.getByRole('button', { name: 'Open' }).click() + // await expect(page.locator('.nsewdrag')).toHaveScreenshot({ + // maxDiffPixelRatio: 0.25, + // }) }) diff --git a/example/.env b/example/.env index eae6df03d..8e63bb0a4 100644 --- a/example/.env +++ b/example/.env @@ -1,3 +1,7 @@ +# Control which application to start +VITE_APPLICATION_ID=example-application-id +VITE_DATA_SOURCE=DemoDataSource + # Azure Auth VITE_AUTH_ENABLED=1 # Turn auth on or off auth VITE_AUTH_SCOPE=api://9bc1cfd7-c616-45d2-8827-22ae9d1e0567/dmss # Scopes needed by the application diff --git a/example/app/data/DemoDataSource/apps/ExampleApplication/ExampleApplication.entity.json b/example/app/data/DemoDataSource/apps/ExampleApplication/ExampleApplication.entity.json new file mode 100644 index 000000000..0e07f3b12 --- /dev/null +++ b/example/app/data/DemoDataSource/apps/ExampleApplication/ExampleApplication.entity.json @@ -0,0 +1,11 @@ +{ + "_id": "example-application-id", + "name": "ExampleApplication", + "type": "/apps/ExampleApplication/blueprints/ExampleApplication", + "label": "Example Application", + "dataSources": [ + "DemoDataSource", + "system", + "WorkflowDS" + ] +} diff --git a/example/app/data/DemoDataSource/apps/ExampleApplication/blueprints/ExampleApplication.blueprint.json b/example/app/data/DemoDataSource/apps/ExampleApplication/blueprints/ExampleApplication.blueprint.json new file mode 100644 index 000000000..46177725a --- /dev/null +++ b/example/app/data/DemoDataSource/apps/ExampleApplication/blueprints/ExampleApplication.blueprint.json @@ -0,0 +1,22 @@ +{ + "name": "ExampleApplication", + "type": "CORE:Blueprint", + "extends": [ + "CORE:Application" + ], + "attributes": [ + { + "name": "label", + "type": "CORE:BlueprintAttribute", + "attributeType": "string", + "optional": true + }, + { + "name": "dataSources", + "type": "CORE:BlueprintAttribute", + "attributeType": "string", + "dimensions": "*", + "optional": false + } + ] +} diff --git a/example/app/data/DemoDataSource/recipes/apps/ExampleApplication/ExampleApplication.recipe.json b/example/app/data/DemoDataSource/recipes/apps/ExampleApplication/ExampleApplication.recipe.json new file mode 100644 index 000000000..1b0923113 --- /dev/null +++ b/example/app/data/DemoDataSource/recipes/apps/ExampleApplication/ExampleApplication.recipe.json @@ -0,0 +1,24 @@ +{ + "type": "CORE:RecipeLink", + "_blueprintPath_": "/apps/ExampleApplication/blueprints/ExampleApplication", + "initialUiRecipe": { + "name": "Header", + "type": "CORE:UiRecipe", + "plugin": "@development-framework/dm-core-plugins/header", + "config": { + "type": "PLUGINS:dm-core-plugins/header/HeaderPluginConfig", + "uiRecipesList": [ + "ExampleApplication" + ], + "hideAbout": false, + "hideUserInfo": false + } + }, + "uiRecipes": [ + { + "name": "ExampleApplication", + "type": "CORE:UiRecipe", + "plugin": "@development-framework/dm-core-plugins/explorer" + } + ] +} diff --git a/example/app/data/DemoDataSource/recipes/plugins/header/roles_header_example/person.recipe.json b/example/app/data/DemoDataSource/recipes/plugins/header/roles_header_example/person.recipe.json index ee542bb4c..6b01789ad 100644 --- a/example/app/data/DemoDataSource/recipes/plugins/header/roles_header_example/person.recipe.json +++ b/example/app/data/DemoDataSource/recipes/plugins/header/roles_header_example/person.recipe.json @@ -12,7 +12,7 @@ "type": "CORE:ReferenceViewConfig", "recipe": "AdminHeader", "roles": [ - "admin", + "dmss-admin", "developer" ] }, diff --git a/example/app/data/DemoDataSource/recipes/plugins/view_selector/roles_school_example/schoolDistrict.recipe.json b/example/app/data/DemoDataSource/recipes/plugins/view_selector/roles_school_example/schoolDistrict.recipe.json index 71ba5acca..4cc624b48 100644 --- a/example/app/data/DemoDataSource/recipes/plugins/view_selector/roles_school_example/schoolDistrict.recipe.json +++ b/example/app/data/DemoDataSource/recipes/plugins/view_selector/roles_school_example/schoolDistrict.recipe.json @@ -12,7 +12,7 @@ "type": "CORE:ReferenceViewConfig", "recipe": "AdminViewSelector", "roles": [ - "admin", + "dmss-admin", "developer" ] }, diff --git a/example/src/App.tsx b/example/src/App.tsx index b324bf353..2cbdb7ef9 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,59 +1,35 @@ import '@development-framework/dm-core/dist/main.css' import { + useDocument, EntityView, - TreeView, - FSTreeContext, + TGenericObject, + FSTreeProvider, + Loading, } from '@development-framework/dm-core' -import React, { useContext, useState } from 'react' -import { Typography } from '@equinor/eds-core-react' +import React from 'react' function App() { - // @ts-ignore - const { treeNodes, loading } = useContext(FSTreeContext) - const [selectedType, setSelectedType] = useState() - const [selectedEntity, setSelectedEntity] = useState() + const idReference: string = `${import.meta.env.VITE_DATA_SOURCE}/$${ + import.meta.env.VITE_APPLICATION_ID + }` + const [application, isLoading, , error] = + useDocument(idReference) - if (loading) return
Loading
+ if (isLoading) return - return ( -
-
- Examples - { - setSelectedType(node.type) - setSelectedEntity(node.nodeId) - }} - /> -
-
- {selectedType && selectedEntity && ( - - )} + if (error) { + console.error(error) + return ( +
+ Error:Failed to load data, see web console for details
-
+ ) + } + + return ( + + + ) } diff --git a/example/src/index.tsx b/example/src/index.tsx index 9f9f999d3..21f63b831 100644 --- a/example/src/index.tsx +++ b/example/src/index.tsx @@ -1,16 +1,17 @@ import { ApplicationContext, DMSSProvider, - FSTreeProvider, + RoleProvider, UiPluginProvider, } from '@development-framework/dm-core' import React from 'react' import { ToastContainer } from 'react-toastify' import 'react-toastify/dist/ReactToastify.min.css' -import App from './App' + import plugins from './plugins' import ReactDOM from 'react-dom/client' import { AuthProvider } from 'react-oauth2-code-pkce' +import App from './App' const fullCurrentURL = () => `${window.location.pathname}${window.location.search}${window.location.hash}` @@ -52,12 +53,12 @@ const Content = () => { return ( - - + + - - - + + + ) diff --git a/packages/dm-core-plugins/package.json b/packages/dm-core-plugins/package.json index 7a165464b..a0f21f4ef 100644 --- a/packages/dm-core-plugins/package.json +++ b/packages/dm-core-plugins/package.json @@ -10,7 +10,6 @@ "@equinor/eds-tokens": "^0.9.0", "axios": "^1.4.0", "highlight.js": "^11.8.0", - "lodash": "^4.17.21", "mermaid": "^10.0.0", "react-hook-form": "^7.31.2", "react-toastify": "^9.1.3", @@ -25,7 +24,6 @@ "@types/react-dom": "^18.2.7", "@types/react-router-dom": "^5.3.3", "@types/styled-components": "^5.1.26", - "@types/lodash": "^4.14.199", "jest": "^29.5.0", "jest-environment-jsdom": "^29.5.0", "react-router-dom": ">=5.1.2", diff --git a/packages/dm-core-plugins/src/header/components/UserInfoDialog.tsx b/packages/dm-core-plugins/src/header/components/UserInfoDialog.tsx index f9686e8eb..90027da21 100644 --- a/packages/dm-core-plugins/src/header/components/UserInfoDialog.tsx +++ b/packages/dm-core-plugins/src/header/components/UserInfoDialog.tsx @@ -1,4 +1,4 @@ -import { Dialog, useDMSS } from '@development-framework/dm-core' +import { Dialog, RoleContext, useDMSS } from '@development-framework/dm-core' import { Button, Radio, Typography } from '@equinor/eds-core-react' import { AxiosResponse } from 'axios' import React, { useContext, useState } from 'react' @@ -6,7 +6,6 @@ import { AuthContext } from 'react-oauth2-code-pkce' import { toast } from 'react-toastify' import styled from 'styled-components' import { TApplication } from '../types' -import { useLocalStorage } from '../useLocalStorage' const UnstyledList = styled.ul` margin: 0; @@ -31,14 +30,11 @@ type UserInfoDialogProps = { } export const UserInfoDialog = (props: UserInfoDialogProps) => { - const { isOpen, setIsOpen, applicationEntity } = props + const { isOpen, setIsOpen } = props const [apiKey, setAPIKey] = useState(null) const { tokenData, token, logOut } = useContext(AuthContext) const dmssAPI = useDMSS() - const [checked, updateChecked] = useLocalStorage( - 'impersonateRoles', - null - ) + const { selectedRole, setSelectedRole } = useContext(RoleContext) return ( { {apiKey &&
{apiKey}
} - {tokenData?.roles?.includes(applicationEntity.adminRole) && ( + {tokenData?.roles.length && ( <> - Impersonate a role (UI only) + Chose role (UI only) - {applicationEntity.roles && - applicationEntity.roles.map((role: string) => ( -
  • - updateChecked(e.target.value)} - /> -
  • - ))} + {tokenData.roles.map((role: string) => ( +
  • + setSelectedRole(e.target.value)} + /> +
  • + ))}
    )} diff --git a/packages/dm-core-plugins/src/role_filter/RoleFilterPlugin.tsx b/packages/dm-core-plugins/src/role_filter/RoleFilterPlugin.tsx index 7d7d537cd..3d684a777 100644 --- a/packages/dm-core-plugins/src/role_filter/RoleFilterPlugin.tsx +++ b/packages/dm-core-plugins/src/role_filter/RoleFilterPlugin.tsx @@ -1,7 +1,10 @@ -import { IUIPlugin, ViewCreator } from '@development-framework/dm-core' -import React, { useEffect, useState } from 'react' -import { intersection } from 'lodash' -import { Autocomplete, Banner, Icon } from '@equinor/eds-core-react' +import { + IUIPlugin, + RoleContext, + ViewCreator, +} from '@development-framework/dm-core' +import React, { useContext, useEffect, useState } from 'react' +import { Banner, Icon } from '@equinor/eds-core-react' type FilteredView = { type: string @@ -17,13 +20,8 @@ export const RoleFilterPlugin = (props: IUIPlugin): JSX.Element => { [] ) const [openViewConfigs, setOpenViewConfigs] = useState([]) - const [selectedRole, setSelectedRole] = useState() const [allowedRoles, setAllowedRoles] = useState([]) - - // TODO: Implement real roles when User login is in place - const User = { - roles: ['admin', 'operator'], - } + const { selectedRole } = useContext(RoleContext) useEffect(() => { let roles: string[] = [] @@ -32,12 +30,9 @@ export const RoleFilterPlugin = (props: IUIPlugin): JSX.Element => { viewConfig.viewId = crypto.randomUUID() }) setAllowedRoles(roles) - if (User.roles.length == 1) setSelectedRole(User.roles[0]) }, []) useEffect(() => { - if (!selectedRole) return - const allowedViewConfigs: FilteredView[] = [] const openViewConfigs: FilteredView[] = [] config.viewConfigs.forEach((viewConfig: FilteredView) => { @@ -54,15 +49,8 @@ export const RoleFilterPlugin = (props: IUIPlugin): JSX.Element => { return ( <> - {intersection(User.roles, allowedRoles).length ? ( + {allowedRoles.includes(selectedRole) ? ( <> - {intersection(User.roles, allowedRoles).length > 1 && ( - - )} {allowedViewConfigs?.map((viewConfig) => ( { - {`No views found, since you currently have roles [${User.roles}]. Please switch to one of these roles: [${allowedRoles}]`} + {`No views found, since you currently have role [${selectedRole}]. Please switch to one of these roles: [${allowedRoles}]`} )} diff --git a/packages/dm-core/package.json b/packages/dm-core/package.json index 415c468f1..65847d2c1 100755 --- a/packages/dm-core/package.json +++ b/packages/dm-core/package.json @@ -14,7 +14,6 @@ "@equinor/eds-icons": "^0.19.3", "@equinor/eds-tokens": "^0.9.0", "axios": "^1.4.0", - "lodash": "^4.17.21", "react-icons": "4.10.1", "react-toastify": "^9.1.3", "react-oauth2-code-pkce": "^1.10.1" diff --git a/packages/dm-core/src/context/RoleContext.tsx b/packages/dm-core/src/context/RoleContext.tsx new file mode 100644 index 000000000..61fd669ef --- /dev/null +++ b/packages/dm-core/src/context/RoleContext.tsx @@ -0,0 +1,19 @@ +import React, { createContext, ReactNode, useState } from 'react' + +export const RoleContext = createContext<{ + selectedRole: string + setSelectedRole: any +}>({ + selectedRole: 'anonymous', + setSelectedRole: null, +}) + +export const RoleProvider = (props: { children: ReactNode }) => { + const { children } = props + const [selectedRole, setSelectedRole] = useState('anonymous') + return ( + + {children} + + ) +} diff --git a/packages/dm-core/src/index.tsx b/packages/dm-core/src/index.tsx index cf26871e8..0bb755ac5 100644 --- a/packages/dm-core/src/index.tsx +++ b/packages/dm-core/src/index.tsx @@ -9,6 +9,7 @@ export * from './context/ApplicationContext' export * from './context/DMSSContext' export * from './context/FileSystemTreeContext' export * from './context/UiPluginContext' +export * from './context/RoleContext' export * from './domain/Tree' export * from './services' export * from './services/api/configs/gen-job/models'