diff --git a/.projen/tasks.json b/.projen/tasks.json index f4bbcba9..5998890d 100644 --- a/.projen/tasks.json +++ b/.projen/tasks.json @@ -134,10 +134,6 @@ "steps": [ { "exec": "yarn install --check-files --frozen-lockfile" - }, - { - "exec": "yarn nx run-many --target=install:ci --output-style=stream --nx-bail", - "receiveArgs": true } ] }, diff --git a/packages/threat-composer-app/.projen/deps.json b/packages/threat-composer-app/.projen/deps.json index 972bb8dc..e769df32 100644 --- a/packages/threat-composer-app/.projen/deps.json +++ b/packages/threat-composer-app/.projen/deps.json @@ -113,10 +113,6 @@ "name": "@cloudscape-design/global-styles", "type": "runtime" }, - { - "name": "@uidotdev/usehooks", - "type": "runtime" - }, { "name": "docx", "type": "runtime" diff --git a/packages/threat-composer-app/.projen/tasks.json b/packages/threat-composer-app/.projen/tasks.json index 816e9526..feacbf98 100644 --- a/packages/threat-composer-app/.projen/tasks.json +++ b/packages/threat-composer-app/.projen/tasks.json @@ -145,13 +145,13 @@ }, "steps": [ { - "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --dep=dev,peer,prod,optional --filter=@cloudscape-design/jest-preset,@testing-library/jest-dom,@testing-library/react,@testing-library/user-event,@types/jest,@types/react,@types/react-dom,@types/react-router-dom,@types/uuid,eslint-import-resolver-typescript,eslint-plugin-import,merge,@aws-northstar/ui,@aws/threat-composer,@cloudscape-design/components,@cloudscape-design/design-tokens,@cloudscape-design/global-styles,@uidotdev/usehooks,docx,react,react-dom,react-router-dom,unist-util-visit,uuid,web-vitals" + "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --dep=dev,peer,prod,optional --filter=@cloudscape-design/jest-preset,@testing-library/jest-dom,@testing-library/react,@testing-library/user-event,@types/jest,@types/react,@types/react-dom,@types/react-router-dom,@types/uuid,eslint-import-resolver-typescript,eslint-plugin-import,merge,@aws-northstar/ui,@aws/threat-composer,@cloudscape-design/components,@cloudscape-design/design-tokens,@cloudscape-design/global-styles,docx,react,react-dom,react-router-dom,unist-util-visit,uuid,web-vitals" }, { "exec": "yarn install --check-files" }, { - "exec": "yarn upgrade @cloudscape-design/jest-preset @testing-library/jest-dom @testing-library/react @testing-library/user-event @types/jest @types/node @types/react @types/react-dom @types/react-router-dom @types/uuid @typescript-eslint/eslint-plugin @typescript-eslint/parser constructs eslint-import-resolver-typescript eslint-plugin-import eslint merge projen typescript @aws-northstar/ui @aws/threat-composer @cloudscape-design/components @cloudscape-design/design-tokens @cloudscape-design/global-styles @uidotdev/usehooks docx react react-dom react-router-dom react-scripts remark-frontmatter remark-gfm remark-parse unified unist-util-visit uuid web-vitals" + "exec": "yarn upgrade @cloudscape-design/jest-preset @testing-library/jest-dom @testing-library/react @testing-library/user-event @types/jest @types/node @types/react @types/react-dom @types/react-router-dom @types/uuid @typescript-eslint/eslint-plugin @typescript-eslint/parser constructs eslint-import-resolver-typescript eslint-plugin-import eslint merge projen typescript @aws-northstar/ui @aws/threat-composer @cloudscape-design/components @cloudscape-design/design-tokens @cloudscape-design/global-styles docx react react-dom react-router-dom react-scripts remark-frontmatter remark-gfm remark-parse unified unist-util-visit uuid web-vitals" }, { "exec": "npx projen" diff --git a/packages/threat-composer-app/package.json b/packages/threat-composer-app/package.json index 052a660d..58b5980b 100644 --- a/packages/threat-composer-app/package.json +++ b/packages/threat-composer-app/package.json @@ -44,7 +44,6 @@ "@cloudscape-design/components": "^3.0.517", "@cloudscape-design/design-tokens": "^3.0.34", "@cloudscape-design/global-styles": "^1.0.23", - "@uidotdev/usehooks": "^2.4.1", "docx": "^8.5.0", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/packages/threat-composer-app/src/components/MarkdownEditorWithPrompt/index.tsx b/packages/threat-composer-app/src/components/MarkdownEditorWithPrompt/index.tsx deleted file mode 100644 index 6704024f..00000000 --- a/packages/threat-composer-app/src/components/MarkdownEditorWithPrompt/index.tsx +++ /dev/null @@ -1,35 +0,0 @@ -/** ******************************************************************************************************************* - Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"). - You may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ******************************************************************************************************************** */ -import { MarkdownEditor, MarkdownEditorProps } from '@aws/threat-composer'; -import { FC, useState } from 'react'; -import { unstable_usePrompt } from 'react-router-dom'; - -const MarkdownEditorWithPrompt: FC = ({ - value, ...props -}) => { - const [previousValue] = useState(value); - - unstable_usePrompt({ - message: 'You have unsaved changes, proceed anyway?', - when: ({ currentLocation, nextLocation }) => - previousValue !== value && - currentLocation.pathname !== nextLocation.pathname, - }); - - return ; -}; - -export default MarkdownEditorWithPrompt; \ No newline at end of file diff --git a/packages/threat-composer-app/src/config/appMode.ts b/packages/threat-composer-app/src/config/appMode.ts deleted file mode 100644 index 765b59d3..00000000 --- a/packages/threat-composer-app/src/config/appMode.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** ******************************************************************************************************************* - Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"). - You may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ******************************************************************************************************************** */ - -import { - APP_MODE_BROWSER_EXTENSION, - APP_MODE_IDE_EXTENSION, -} from '@aws/threat-composer'; - -const appModeEnv = process.env.REACT_APP_APP_MODE; - -export const appMode = appModeEnv === APP_MODE_BROWSER_EXTENSION ? - APP_MODE_BROWSER_EXTENSION : - (appModeEnv === APP_MODE_IDE_EXTENSION ? - APP_MODE_IDE_EXTENSION : undefined); - diff --git a/packages/threat-composer-app/src/config/routes.ts b/packages/threat-composer-app/src/config/routes.ts index 392a6987..ec54da07 100644 --- a/packages/threat-composer-app/src/config/routes.ts +++ b/packages/threat-composer-app/src/config/routes.ts @@ -13,35 +13,17 @@ See the License for the specific language governing permissions and limitations under the License. ******************************************************************************************************************** */ -export const ROUTE_WORKSPACE_PATH = 'workspaces/:workspaceId'; -export const ROUTE_WORKSPACE_HOME_PATH = 'dashboard'; -export const ROUTE_WORKSPACE_HOME = `/${ROUTE_WORKSPACE_PATH}/${ROUTE_WORKSPACE_HOME_PATH}`; -export const ROUTE_THREAT_LIST_PATH = 'threats'; -export const ROUTE_THREAT_LIST = `/${ROUTE_WORKSPACE_PATH}/${ROUTE_THREAT_LIST_PATH}`; -export const ROUTE_THREAT_EDITOR_PATH = 'threats/:threatId'; -export const ROUTE_THREAT_EDITOR = `/${ROUTE_WORKSPACE_PATH}/${ROUTE_THREAT_EDITOR_PATH}`; -export const ROUTE_MITIGATION_LIST_PATH = 'mitigations'; -export const ROUTE_MITIGATION_LIST = `/${ROUTE_WORKSPACE_PATH}/${ROUTE_MITIGATION_LIST_PATH}`; -export const ROUTE_ASSUMPTION_LIST_PATH = 'assumptions'; -export const ROUTE_ASSUMPTION_LIST = `/${ROUTE_WORKSPACE_PATH}/${ROUTE_ASSUMPTION_LIST_PATH}`; -export const ROUTE_APPLICATION_INFO_PATH = 'application'; -export const ROUTE_APPLICATION_INFO = `/${ROUTE_WORKSPACE_PATH}/${ROUTE_APPLICATION_INFO_PATH}`; -export const ROUTE_ARCHITECTURE_INFO_PATH = 'architecture'; -export const ROUTE_ARCHITECTURE_INFO = `/${ROUTE_WORKSPACE_PATH}/${ROUTE_ARCHITECTURE_INFO_PATH}`; -export const ROUTE_DATAFLOW_INFO_PATH = 'dataflow'; -export const ROUTE_DATAFLOW_INFO = `/${ROUTE_WORKSPACE_PATH}/${ROUTE_DATAFLOW_INFO_PATH}`; -export const ROUTE_VIEW_THREAT_MODEL_PATH = 'threatModel'; -export const ROUTE_VIEW_THREAT_MODEL = `/${ROUTE_WORKSPACE_PATH}/${ROUTE_VIEW_THREAT_MODEL_PATH}`; -export const ROUTE_THREAT_PACKS_PATH = 'threatPacks'; -export const ROUTE_THREAT_PACKS = `/${ROUTE_WORKSPACE_PATH}/${ROUTE_THREAT_PACKS_PATH}`; -export const ROUTE_THREAT_PACK_PATH = 'threatPacks/:threatPackId'; -export const ROUTE_THREAT_PACK = `/${ROUTE_WORKSPACE_PATH}/${ROUTE_THREAT_PACK_PATH}`; -export const ROUTE_THREAT_PACK_THREAT_PATH = 'threatPacks/:threatPackId/:threatId'; -export const ROUTE_THREAT_PACK_THREAT = `/${ROUTE_WORKSPACE_PATH}/${ROUTE_THREAT_PACK_THREAT_PATH}`; -export const ROUTE_MITIGATION_PACKS_PATH = 'mitigationPacks'; -export const ROUTE_MITIGATION_PACKS = `/${ROUTE_WORKSPACE_PATH}/${ROUTE_MITIGATION_PACKS_PATH}`; -export const ROUTE_MITIGATION_PACK_PATH = 'mitigationPacks/:mitigationPackId'; -export const ROUTE_MITIGATION_PACK = `/${ROUTE_WORKSPACE_PATH}/${ROUTE_MITIGATION_PACK_PATH}`; -export const ROUTE_PREVIEW_PATH = 'preview/:dataKey'; -export const ROUTE_PREVIEW = `/${ROUTE_PREVIEW_PATH}`; -export const ROUTE_WORKSPACE_DEFAULT = 'workspaces/default'; +export const ROUTE_WORKSPACE_HOME = '/workspaces/:workspaceId/dashboard'; +export const ROUTE_THREAT_LIST = '/workspaces/:workspaceId/threats'; +export const ROUTE_THREAT_EDITOR = '/workspaces/:workspaceId/threats/:threatId'; +export const ROUTE_MITIGATION_LIST = '/workspaces/:workspaceId/mitigations'; +export const ROUTE_ASSUMPTION_LIST = '/workspaces/:workspaceId/assumptions'; +export const ROUTE_APPLICATION_INFO = '/workspaces/:workspaceId/application'; +export const ROUTE_ARCHITECTURE_INFO = '/workspaces/:workspaceId/architecture'; +export const ROUTE_DATAFLOW_INFO = '/workspaces/:workspaceId/dataflow'; +export const ROUTE_VIEW_THREAT_MODEL = '/workspaces/:workspaceId/threatModel'; +export const ROUTE_THREAT_PACKS = '/workspaces/:workspaceId/threatPacks'; +export const ROUTE_THREAT_PACK = '/workspaces/:workspaceId/threatPacks/:threatPackId'; +export const ROUTE_THREAT_PACK_THREAT = '/workspaces/:workspaceId/threatPacks/:threatPackId/:threatId'; +export const ROUTE_MITIGATION_PACKS = '/workspaces/:workspaceId/mitigationPacks'; +export const ROUTE_MITIGATION_PACK = '/workspaces/:workspaceId/mitigationPacks/:mitigationPackId'; diff --git a/packages/threat-composer-app/src/containers/App/components/Full/index.tsx b/packages/threat-composer-app/src/containers/App/components/Full/index.tsx index 895d768a..9c4fe513 100644 --- a/packages/threat-composer-app/src/containers/App/components/Full/index.tsx +++ b/packages/threat-composer-app/src/containers/App/components/Full/index.tsx @@ -13,18 +13,235 @@ See the License for the specific language governing permissions and limitations under the License. ******************************************************************************************************************** */ -import { FC, useState } from 'react'; -import { RouterProvider } from 'react-router-dom'; -import { routerOpts, createRouter, routes } from '../../../../routes'; +import { + ContextAggregator, + DataExchangeFormat, + ThreatStatementListFilter, + WorkspaceSelector, + useWorkspacesContext, + APP_MODE_BROWSER_EXTENSION, + APP_MODE_IDE_EXTENSION, +} from '@aws/threat-composer'; +import { SideNavigationProps } from '@cloudscape-design/components/side-navigation'; +import React, { FC, useMemo, useCallback, useState, useEffect } from 'react'; +import { Routes, Route, RouteProps, useParams, useSearchParams, useNavigate, Navigate } from 'react-router-dom'; +import AppLayout from '../../../../components/FullAppLayout'; +import { + ROUTE_APPLICATION_INFO, + ROUTE_ARCHITECTURE_INFO, + ROUTE_ASSUMPTION_LIST, + ROUTE_DATAFLOW_INFO, + ROUTE_THREAT_PACKS, + ROUTE_MITIGATION_LIST, + ROUTE_THREAT_EDITOR, + ROUTE_THREAT_LIST, + ROUTE_VIEW_THREAT_MODEL, + ROUTE_WORKSPACE_HOME, + ROUTE_MITIGATION_PACKS, +} from '../../../../config/routes'; +import { SEARCH_PARAM_FEATURES } from '../../../../config/searchParams'; +import useNotifications from '../../../../hooks/useNotifications'; +import routes from '../../../../routes'; +import generateUrl from '../../../../utils/generateUrl'; +import ThreatModelReport from '../../../ThreatModelReport'; + +const TEMP_PREVIEW_DATA_KEY = 'ThreatStatementGenerator.TempPreviewData'; + +const defaultHref = process.env.PUBLIC_URL || '/'; +const appModeEnv = process.env.REACT_APP_APP_MODE; + +const appMode = appModeEnv === APP_MODE_BROWSER_EXTENSION ? + APP_MODE_BROWSER_EXTENSION : + (appModeEnv === APP_MODE_IDE_EXTENSION ? + APP_MODE_IDE_EXTENSION : undefined); + +const AppInner: FC<{ + setWorkspaceId: React.Dispatch>; +}> = ({ setWorkspaceId }) => { + const { currentWorkspace } = useWorkspacesContext(); + const [searchParms] = useSearchParams(); + useEffect(() => { + setWorkspaceId(currentWorkspace?.id || 'default'); + }, [currentWorkspace]); + + const workspaceHome = generateUrl(ROUTE_WORKSPACE_HOME, searchParms, currentWorkspace?.id || 'default'); + + return ( + } /> + {routes.map((r: RouteProps, index: number) => )} + } /> + ); +}; const Full: FC = () => { - const [router] = useState(() => { - //Initialize here to ensure the default index loader only call when Full is mount without affecting Standalone mode - return createRouter(routes, routerOpts); + const { workspaceId: initialWorkspaceId } = useParams(); + const [searchParms] = useSearchParams(); + const navigate = useNavigate(); + + const [isPreview] = useState(() => { + const urlParams = new URLSearchParams(window.location.search); + const previewParams = urlParams.get('preview'); + return previewParams === 'true'; }); + const [features] = useState(() => { + const urlParams = new URLSearchParams(window.location.search); + const featureParam = urlParams.get(SEARCH_PARAM_FEATURES); + return featureParam && featureParam.split(',') || []; + }); + + const isThreatPackFeatureOn = useMemo(() => { + return features.includes('threatPacks'); + }, [features]); + + const [workspaceId, setWorkspaceId] = useState(initialWorkspaceId || 'default'); + + const handleWorkspaceChanged = useCallback((newWorkspaceId: string) => { + navigate(generateUrl(ROUTE_WORKSPACE_HOME, searchParms, newWorkspaceId)); + }, [navigate, workspaceId, searchParms]); + + const handleNavigationView = useCallback((route: string) => { + navigate(generateUrl(route, searchParms, workspaceId)); + }, [navigate]); + + const handleThreatListView = useCallback((filter?: ThreatStatementListFilter) => { + navigate(generateUrl(ROUTE_THREAT_LIST, searchParms, workspaceId), { + state: filter ? { + filter, + } : undefined, + }); + }, [navigate, workspaceId, searchParms]); + + const handleThreatEditorView = useCallback((newThreatId: string, idToCopy?: string) => { + navigate(generateUrl(ROUTE_THREAT_EDITOR, searchParms, workspaceId, newThreatId, undefined, idToCopy ? { + idToCopy, + } : undefined), { + state: { + idToCopy, + }, + }); + }, [navigate, workspaceId, searchParms]); + + const navigationItems: SideNavigationProps.Item[] = useMemo(() => { + const navItems: SideNavigationProps.Item[] = [ + { + text: 'Dashboard', + href: generateUrl(ROUTE_WORKSPACE_HOME, searchParms, workspaceId), + type: 'link', + }, + { + text: 'Application info', + href: generateUrl(ROUTE_APPLICATION_INFO, searchParms, workspaceId), + type: 'link', + }, + { + text: 'Architecture', + href: generateUrl(ROUTE_ARCHITECTURE_INFO, searchParms, workspaceId), + type: 'link', + }, + { + text: 'Dataflow', + href: generateUrl(ROUTE_DATAFLOW_INFO, searchParms, workspaceId), + type: 'link', + }, + { + text: 'Assumptions', + href: generateUrl(ROUTE_ASSUMPTION_LIST, searchParms, workspaceId), + type: 'link', + }, + { + text: 'Threats', + href: generateUrl(ROUTE_THREAT_LIST, searchParms, workspaceId), + type: 'link', + }, + { + text: 'Mitigations', + href: generateUrl(ROUTE_MITIGATION_LIST, searchParms, workspaceId), + type: 'link', + }, + { type: 'divider' }, + { + text: 'Threat model', + href: generateUrl(ROUTE_VIEW_THREAT_MODEL, searchParms, workspaceId), + type: 'link', + }, + ]; + return isThreatPackFeatureOn ? navItems.concat([ + { type: 'divider' }, + { + type: 'section', + text: 'Reference packs', + items: [ + { + text: 'Threat packs', + href: generateUrl(ROUTE_THREAT_PACKS, searchParms, workspaceId), + type: 'link', + }, + { + text: 'Mitigation packs', + href: generateUrl(ROUTE_MITIGATION_PACKS, searchParms, workspaceId), + type: 'link', + }, + ], + }, + ]) : navItems; + + }, [searchParms, workspaceId, isThreatPackFeatureOn]); + + const handlePreview = useCallback((data: DataExchangeFormat) => { + const urlParams = new URLSearchParams(window.location.search); + urlParams.set('preview', 'true'); + window.localStorage.setItem(TEMP_PREVIEW_DATA_KEY, JSON.stringify(data)); + urlParams.set('dataKey', TEMP_PREVIEW_DATA_KEY); + window.open(`${window.location.pathname}?${urlParams.toString()}`, '_blank', 'noopener,noreferrer,resizable'); + }, []); + + const handleImported = useCallback(() => { + navigate(generateUrl(ROUTE_VIEW_THREAT_MODEL, searchParms, workspaceId)); + }, [navigate, workspaceId, searchParms]); + + const handleDefineWorkload = useCallback(() => { + navigate(generateUrl(ROUTE_APPLICATION_INFO, searchParms, workspaceId)); + }, [navigate, workspaceId, searchParms]); + + const notifications = useNotifications(); + return ( - + handleNavigationView(ROUTE_APPLICATION_INFO)} + onArchitectureView={() => handleNavigationView(ROUTE_ARCHITECTURE_INFO)} + onDataflowView={() => handleNavigationView(ROUTE_DATAFLOW_INFO)} + onAssumptionListView={() => handleNavigationView(ROUTE_ASSUMPTION_LIST)} + onMitigationListView={() => handleNavigationView(ROUTE_MITIGATION_LIST)} + onThreatListView={handleThreatListView} + onThreatEditorView={handleThreatEditorView} + onPreview={handlePreview} + onImported={handleImported} + onDefineWorkload={handleDefineWorkload} + > + {isPreview ? ( + + ) : ( x.path || '')} + breadcrumbGroup={} + notifications={notifications} + > + + )} + ); }; diff --git a/packages/threat-composer-app/src/containers/App/index.tsx b/packages/threat-composer-app/src/containers/App/index.tsx index 9da3ca26..8bdcf29f 100644 --- a/packages/threat-composer-app/src/containers/App/index.tsx +++ b/packages/threat-composer-app/src/containers/App/index.tsx @@ -14,22 +14,24 @@ limitations under the License. ******************************************************************************************************************** */ import { FC } from 'react'; +import { useSearchParams } from 'react-router-dom'; import Full from './components/Full'; import Standalone from './components/Standalone'; import GithubPagesNavigationHelper from '../../components/GithubPagesNavigationHelper'; -import getComposerMode from '../../utils/getComposerMode'; +import { SEARCH_PARAM_MODE } from '../../config/searchParams'; +const DEFAULT_MODE = process.env.REACT_APP_DEFAULT_MODE; const isGithubPages = process.env.REACT_APP_GITHUB_PAGES === 'true'; /** * Demo app for threat-composer */ const App: FC = () => { - const composerMode = getComposerMode(); + const [searchParams] = useSearchParams(); + const mode = searchParams.get(SEARCH_PARAM_MODE); + const composerMode = mode || DEFAULT_MODE || 'Full'; - console.log('App-ComposerMode', composerMode); - - return (composerMode === 'ThreatsOnly' || composerMode === 'EditorOnly') ? ( + return composerMode === 'ThreatsOnly' || composerMode === 'EditorOnly' ? ( ) : ( isGithubPages ? diff --git a/packages/threat-composer-app/src/containers/AppLayout/index.tsx b/packages/threat-composer-app/src/containers/AppLayout/index.tsx deleted file mode 100644 index 2a91f6a8..00000000 --- a/packages/threat-composer-app/src/containers/AppLayout/index.tsx +++ /dev/null @@ -1,132 +0,0 @@ -/** ******************************************************************************************************************* - Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"). - You may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ******************************************************************************************************************** */ -import { - DEFAULT_WORKSPACE_ID, - useGlobalSetupContext, -} from '@aws/threat-composer'; -import { SideNavigationProps } from '@cloudscape-design/components/side-navigation'; -import { FC, PropsWithChildren, useMemo } from 'react'; -import { useParams, useSearchParams } from 'react-router-dom'; -import AppLayoutComponent from '../../components/FullAppLayout'; -import { - ROUTE_APPLICATION_INFO_PATH, - ROUTE_ARCHITECTURE_INFO_PATH, - ROUTE_ASSUMPTION_LIST_PATH, - ROUTE_DATAFLOW_INFO_PATH, - ROUTE_THREAT_PACKS_PATH, - ROUTE_MITIGATION_LIST_PATH, - ROUTE_THREAT_LIST_PATH, - ROUTE_VIEW_THREAT_MODEL_PATH, - ROUTE_WORKSPACE_HOME_PATH, - ROUTE_MITIGATION_PACKS_PATH, -} from '../../config/routes'; -import useNotifications from '../../hooks/useNotifications'; -import generateUrl from '../../utils/generateUrl'; -import WorkspaceSelector from '../WorkspaceSelector'; - -const defaultHref = process.env.PUBLIC_URL || '/'; - -const AppLayout: FC> = ({ - children, -}) => { - const { workspaceId = DEFAULT_WORKSPACE_ID } = useParams(); - const notifications = useNotifications(); - const [searchParams] = useSearchParams(); - - const { features } = useGlobalSetupContext(); - - const isThreatPackFeatureOn = useMemo(() => { - return features.includes('threatPacks'); - }, [features]); - - const navigationItems: SideNavigationProps.Item[] = useMemo(() => { - const navItems: SideNavigationProps.Item[] = [ - { - text: 'Dashboard', - href: generateUrl(ROUTE_WORKSPACE_HOME_PATH, searchParams, workspaceId), - type: 'link', - }, - { - text: 'Application info', - href: generateUrl(ROUTE_APPLICATION_INFO_PATH, searchParams, workspaceId), - type: 'link', - }, - { - text: 'Architecture', - href: generateUrl(ROUTE_ARCHITECTURE_INFO_PATH, searchParams, workspaceId), - type: 'link', - }, - { - text: 'Dataflow', - href: generateUrl(ROUTE_DATAFLOW_INFO_PATH, searchParams, workspaceId), - type: 'link', - }, - { - text: 'Assumptions', - href: generateUrl(ROUTE_ASSUMPTION_LIST_PATH, searchParams, workspaceId), - type: 'link', - }, - { - text: 'Threats', - href: generateUrl(ROUTE_THREAT_LIST_PATH, searchParams, workspaceId), - type: 'link', - }, - { - text: 'Mitigations', - href: generateUrl(ROUTE_MITIGATION_LIST_PATH, searchParams, workspaceId), - type: 'link', - }, - { type: 'divider' }, - { - text: 'Threat model', - href: generateUrl(ROUTE_VIEW_THREAT_MODEL_PATH, searchParams, workspaceId), - type: 'link', - }, - ]; - return isThreatPackFeatureOn ? navItems.concat([ - { type: 'divider' }, - { - type: 'section', - text: 'Reference packs', - items: [ - { - text: 'Threat packs', - href: generateUrl(ROUTE_THREAT_PACKS_PATH, searchParams, workspaceId), - type: 'link', - }, - { - text: 'Mitigation packs', - href: generateUrl(ROUTE_MITIGATION_PACKS_PATH, searchParams, workspaceId), - type: 'link', - }, - ], - }, - ]) : navItems; - - }, [searchParams, workspaceId, isThreatPackFeatureOn]); - - return (} - notifications={notifications} - > - {children} - ); -}; - -export default AppLayout; diff --git a/packages/threat-composer-app/src/containers/AppRoot/index.tsx b/packages/threat-composer-app/src/containers/AppRoot/index.tsx deleted file mode 100644 index e1e7d408..00000000 --- a/packages/threat-composer-app/src/containers/AppRoot/index.tsx +++ /dev/null @@ -1,33 +0,0 @@ -/** ******************************************************************************************************************* - Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"). - You may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ******************************************************************************************************************** */ - -import { GlobalSetupContext } from '@aws/threat-composer'; -import { FC } from 'react'; -import { Outlet } from 'react-router-dom'; -import { appMode } from '../../config/appMode'; -import useFeatures from '../../hooks/useFeatures'; - -const AppRoot: FC = () => { - const features = useFeatures(); - return ( - - ); -}; - -export default AppRoot; \ No newline at end of file diff --git a/packages/threat-composer-app/src/containers/Application/index.tsx b/packages/threat-composer-app/src/containers/Application/index.tsx index 964001e6..6363aadd 100644 --- a/packages/threat-composer-app/src/containers/Application/index.tsx +++ b/packages/threat-composer-app/src/containers/Application/index.tsx @@ -14,10 +14,9 @@ limitations under the License. ******************************************************************************************************************** */ import { ApplicationInfoComponent } from '@aws/threat-composer'; -import MarkdownEditorWithPrompt from '../../components/MarkdownEditorWithPrompt'; const Application = () => { - return ; + return ; }; export default Application; \ No newline at end of file diff --git a/packages/threat-composer-app/src/containers/Architecture/index.tsx b/packages/threat-composer-app/src/containers/Architecture/index.tsx index 61d6071d..e750e2ea 100644 --- a/packages/threat-composer-app/src/containers/Architecture/index.tsx +++ b/packages/threat-composer-app/src/containers/Architecture/index.tsx @@ -14,10 +14,9 @@ limitations under the License. ******************************************************************************************************************** */ import { ArchitectureInfoComponent } from '@aws/threat-composer'; -import MarkdownEditorWithPrompt from '../../components/MarkdownEditorWithPrompt'; const Architecture = () => { - return ; + return ; }; export default Architecture; \ No newline at end of file diff --git a/packages/threat-composer-app/src/containers/Dataflow/index.tsx b/packages/threat-composer-app/src/containers/Dataflow/index.tsx index d7f3fdeb..123b2b08 100644 --- a/packages/threat-composer-app/src/containers/Dataflow/index.tsx +++ b/packages/threat-composer-app/src/containers/Dataflow/index.tsx @@ -14,10 +14,9 @@ limitations under the License. ******************************************************************************************************************** */ import { DataflowInfoComponent } from '@aws/threat-composer'; -import MarkdownEditorWithPrompt from '../../components/MarkdownEditorWithPrompt'; const Dataflow = () => { - return ; + return ; }; export default Dataflow; \ No newline at end of file diff --git a/packages/threat-composer-app/src/containers/ThreatModelPreview/index.tsx b/packages/threat-composer-app/src/containers/ThreatModelPreview/index.tsx deleted file mode 100644 index f4fb8e63..00000000 --- a/packages/threat-composer-app/src/containers/ThreatModelPreview/index.tsx +++ /dev/null @@ -1,47 +0,0 @@ -/** ******************************************************************************************************************* - Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"). - You may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ******************************************************************************************************************** */ -import { ThreatModelView } from '@aws/threat-composer'; -import Box from '@cloudscape-design/components/box'; -import { FC, useEffect, useMemo } from 'react'; -import { useParams } from 'react-router-dom'; - -const ThreatModelPreview: FC = () => { - const { dataKey } = useParams(); - - const data = useMemo(() => { - const dataStr = dataKey && window.localStorage.getItem(dataKey); - - if (dataStr) { - return JSON.parse(dataStr); - } - - return undefined; - }, []); - - useEffect(() => { - return () => { - dataKey && window.localStorage.removeItem(dataKey); - }; - }, [dataKey]); - - if (!data) { - return No content; - } - - return ; -}; - -export default ThreatModelPreview; \ No newline at end of file diff --git a/packages/threat-composer-app/src/containers/ThreatModelReport/index.tsx b/packages/threat-composer-app/src/containers/ThreatModelReport/index.tsx index 0ce80d0b..0989bddb 100644 --- a/packages/threat-composer-app/src/containers/ThreatModelReport/index.tsx +++ b/packages/threat-composer-app/src/containers/ThreatModelReport/index.tsx @@ -13,34 +13,46 @@ See the License for the specific language governing permissions and limitations under the License. ******************************************************************************************************************** */ -import { ThreatModel } from '@aws/threat-composer'; -import { FC } from 'react'; -import { - ROUTE_APPLICATION_INFO, - ROUTE_ARCHITECTURE_INFO, - ROUTE_ASSUMPTION_LIST, - ROUTE_DATAFLOW_INFO, - ROUTE_MITIGATION_LIST, - ROUTE_THREAT_LIST, -} from '../../config/routes'; -import useNavigateView from '../../hooks/useNavigationView'; -import useOnPreview from '../../hooks/useOnPreview'; +import { ThreatModel, ThreatModelView } from '@aws/threat-composer'; +import { FC, useCallback, useState } from 'react'; import convertToDocx from '../../utils/convertToDocx'; const ThreatModelReport: FC = () => { - const handleNavigationView = useNavigateView(); - const [onPreview] = useOnPreview(); - - return ( handleNavigationView(ROUTE_APPLICATION_INFO)} - onArchitectureView={() => handleNavigationView(ROUTE_ARCHITECTURE_INFO)} - onDataflowView={() => handleNavigationView(ROUTE_DATAFLOW_INFO)} - onAssumptionListView={() => handleNavigationView(ROUTE_ASSUMPTION_LIST)} - onMitigationListView={() => handleNavigationView(ROUTE_MITIGATION_LIST)} - onThreatListView={() => handleNavigationView(ROUTE_THREAT_LIST)} - />); + const [isPreview] = useState(() => { + const urlParams = new URLSearchParams(window.location.search); + const previewParams = urlParams.get('preview'); + return previewParams === 'true'; + }); + + const [data] = useState(() => { + const urlParams = new URLSearchParams(window.location.search); + const dataKey = urlParams.get('dataKey'); + const dataStr = dataKey && window.localStorage.getItem(dataKey); + + if (dataStr) { + return JSON.parse(dataStr); + } + + if (dataKey) { + return {}; + } + + return undefined; + }); + + const handlePrintButtonClick = useCallback(() => { + const urlParams = new URLSearchParams(window.location.search); + urlParams.set('preview', 'true'); + window.open(`${window.location.pathname}?${urlParams.toString()}`, '_blank', 'noopener,noreferrer,resizable'); + }, []); + + return (data + ? () + : ()); }; export default ThreatModelReport; \ No newline at end of file diff --git a/packages/threat-composer-app/src/containers/ThreatStatementEditor/index.tsx b/packages/threat-composer-app/src/containers/ThreatStatementEditor/index.tsx index 75a28156..75ce5148 100644 --- a/packages/threat-composer-app/src/containers/ThreatStatementEditor/index.tsx +++ b/packages/threat-composer-app/src/containers/ThreatStatementEditor/index.tsx @@ -25,14 +25,11 @@ import { } from '@aws/threat-composer'; import { useEffect, useState } from 'react'; import { useLocation, useParams } from 'react-router-dom'; -import { ROUTE_THREAT_LIST } from '../../config/routes'; -import useNavigateView from '../../hooks/useNavigationView'; import isMemoryRouterUsed from '../../utils/isMemoryRouterUsed'; const ThreatStatementEditor = () => { const { threatId } = useParams(); const location = useLocation(); - const handleNavigateView = useNavigateView(); const [idToCopy] = useState(() => { if (isMemoryRouterUsed()) { @@ -101,7 +98,7 @@ const ThreatStatementEditor = () => { setEditingStatement(editingStatement); }, [editingStatement]); - return handleNavigateView(ROUTE_THREAT_LIST)} />; + return ; }; export default ThreatStatementEditor; \ No newline at end of file diff --git a/packages/threat-composer-app/src/containers/ThreatStatementList/index.tsx b/packages/threat-composer-app/src/containers/ThreatStatementList/index.tsx index 5266d91d..355c1a24 100644 --- a/packages/threat-composer-app/src/containers/ThreatStatementList/index.tsx +++ b/packages/threat-composer-app/src/containers/ThreatStatementList/index.tsx @@ -15,22 +15,10 @@ ******************************************************************************************************************** */ import { ThreatStatementList as ThreatStatementListComponent } from '@aws/threat-composer'; import { useLocation } from 'react-router-dom'; -import { ROUTE_THREAT_EDITOR } from '../../config/routes'; -import useNavigateView from '../../hooks/useNavigationView'; const ThreatStatementList = () => { - const handleNavigateView = useNavigateView(); const { state } = useLocation(); - return handleNavigateView(ROUTE_THREAT_EDITOR, threatId, undefined, idToCopy ? { - idToCopy, - } : undefined, { - state: { - idToCopy, - }, - })} - />; + return ; }; export default ThreatStatementList; \ No newline at end of file diff --git a/packages/threat-composer-app/src/containers/WorkspaceHome/index.tsx b/packages/threat-composer-app/src/containers/WorkspaceHome/index.tsx index d014f52d..0dc68879 100644 --- a/packages/threat-composer-app/src/containers/WorkspaceHome/index.tsx +++ b/packages/threat-composer-app/src/containers/WorkspaceHome/index.tsx @@ -13,27 +13,10 @@ See the License for the specific language governing permissions and limitations under the License. ******************************************************************************************************************** */ -import { WorkspaceHome as WorkspaceHomeComponent, ThreatStatementListFilter } from '@aws/threat-composer'; -import { ROUTE_APPLICATION_INFO, ROUTE_THREAT_EDITOR, ROUTE_THREAT_LIST } from '../../config/routes'; -import useNavigateView from '../../hooks/useNavigationView'; +import { WorkspaceHome as WorkspaceHomeComponent } from '@aws/threat-composer'; const WorkspaceHome = () => { - const handleNavigateView = useNavigateView(); - return handleNavigateView(ROUTE_APPLICATION_INFO)} - onThreatEditorView={(threatId: string, idToCopy?: string) => handleNavigateView(ROUTE_THREAT_EDITOR, threatId, undefined, idToCopy ? { - idToCopy, - } : undefined, { - state: { - idToCopy, - }, - })} - onThreatListView={(filter?: ThreatStatementListFilter) => handleNavigateView(ROUTE_THREAT_LIST, undefined, undefined, undefined, { - state: filter ? { - filter, - } : undefined, - })} - />; + return ; }; export default WorkspaceHome; \ No newline at end of file diff --git a/packages/threat-composer-app/src/containers/WorkspaceRoot/index.tsx b/packages/threat-composer-app/src/containers/WorkspaceRoot/index.tsx deleted file mode 100644 index 8c34f26f..00000000 --- a/packages/threat-composer-app/src/containers/WorkspaceRoot/index.tsx +++ /dev/null @@ -1,81 +0,0 @@ -/** ******************************************************************************************************************* - Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"). - You may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ******************************************************************************************************************** */ -import { - DEFAULT_WORKSPACE_ID, - WorkspaceContextAggregator, - WorkspacesContext, - ThreatStatementListFilter, - WorkspaceExamplesContext, -} from '@aws/threat-composer'; -import { useCallback, FC } from 'react'; -import { useNavigate, useParams, useSearchParams, Outlet } from 'react-router-dom'; -import { - ROUTE_THREAT_EDITOR_PATH, - ROUTE_THREAT_LIST_PATH, - ROUTE_WORKSPACE_HOME, -} from '../../config/routes'; -import generateUrl from '../../utils/generateUrl'; -import AppLayout from '../AppLayout'; - -const WorkspaceRoot: FC = () => { - const { workspaceId = DEFAULT_WORKSPACE_ID } = useParams(); - const [searchParams] = useSearchParams(); - const navigate = useNavigate(); - - const handleThreatListView = useCallback((filter?: ThreatStatementListFilter) => { - navigate(generateUrl(ROUTE_THREAT_LIST_PATH, searchParams, workspaceId), { - state: filter ? { - filter, - } : undefined, - }); - }, [navigate, workspaceId, searchParams]); - - const handleThreatEditorView = useCallback((newThreatId: string, idToCopy?: string) => { - navigate(generateUrl(ROUTE_THREAT_EDITOR_PATH, searchParams, workspaceId, newThreatId, undefined, idToCopy ? { - idToCopy, - } : undefined), { - state: { - idToCopy, - }, - }); - }, [navigate, workspaceId, searchParams]); - - const handleWorkspaceChanged = useCallback((newWorkspaceId: string) => { - const url = generateUrl(ROUTE_WORKSPACE_HOME, searchParams, newWorkspaceId); - navigate(url); - }, [navigate, workspaceId, searchParams]); - - return ( - - - {(workspaceIdFromContext) => ( - - - - )} - - ); -}; - -export default WorkspaceRoot; \ No newline at end of file diff --git a/packages/threat-composer-app/src/containers/WorkspaceSelector/index.tsx b/packages/threat-composer-app/src/containers/WorkspaceSelector/index.tsx deleted file mode 100644 index fc262a9e..00000000 --- a/packages/threat-composer-app/src/containers/WorkspaceSelector/index.tsx +++ /dev/null @@ -1,44 +0,0 @@ -/** ******************************************************************************************************************* - Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"). - You may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ******************************************************************************************************************** */ - -import { - WorkspaceSelector as WorkspaceSelectorComponent, - APP_MODE_BROWSER_EXTENSION, - APP_MODE_IDE_EXTENSION, -} from '@aws/threat-composer'; -import { appMode } from '../../config/appMode'; -import { ROUTE_VIEW_THREAT_MODEL } from '../../config/routes'; -import useNavigateView from '../../hooks/useNavigationView'; -import useOnPreview from '../../hooks/useOnPreview'; - - -const WorkspaceSelector = () => { - const [onPreview] = useOnPreview(); - const navigate = useNavigateView(); - - return navigate(ROUTE_VIEW_THREAT_MODEL)} - singletonMode={appMode === APP_MODE_BROWSER_EXTENSION || appMode === APP_MODE_IDE_EXTENSION} - singletonPrimaryActionButtonConfig={appMode === APP_MODE_IDE_EXTENSION ? { - text: 'Save', - eventName: 'save', - } : undefined} - embededMode={false} - />; -}; - -export default WorkspaceSelector; \ No newline at end of file diff --git a/packages/threat-composer-app/src/hooks/useFeatures/index.tsx b/packages/threat-composer-app/src/hooks/useFeatures/index.tsx deleted file mode 100644 index 7610718e..00000000 --- a/packages/threat-composer-app/src/hooks/useFeatures/index.tsx +++ /dev/null @@ -1,27 +0,0 @@ -/** ******************************************************************************************************************* - Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"). - You may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ******************************************************************************************************************** */ - -import { useSearchParams } from 'react-router-dom'; -import { SEARCH_PARAM_FEATURES } from '../../config/searchParams'; - -const useFeatures = () => { - const [searchParams] = useSearchParams(); - - const featureParam = searchParams.get(SEARCH_PARAM_FEATURES); - return featureParam && featureParam.split(',') || []; -}; - -export default useFeatures; \ No newline at end of file diff --git a/packages/threat-composer-app/src/hooks/useNavigationView/index.tsx b/packages/threat-composer-app/src/hooks/useNavigationView/index.tsx deleted file mode 100644 index 51589dd4..00000000 --- a/packages/threat-composer-app/src/hooks/useNavigationView/index.tsx +++ /dev/null @@ -1,39 +0,0 @@ -/** ******************************************************************************************************************* - Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"). - You may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ******************************************************************************************************************** */ - -import { DEFAULT_WORKSPACE_ID } from '@aws/threat-composer'; -import { useCallback } from 'react'; -import { NavigateOptions, useNavigate, useParams, useSearchParams } from 'react-router-dom'; -import generateUrl from '../../utils/generateUrl'; - -const useNavigateView = () => { - const navigate = useNavigate(); - const [searchParams] = useSearchParams(); - const { workspaceId = DEFAULT_WORKSPACE_ID } = useParams(); - - return useCallback((route: string, threatId?: string, - additionalParams?: { - [key: string]: string; - }, additionalSearchParams?: { - [key: string]: string; - }, opts?: NavigateOptions) => - navigate(generateUrl(route, searchParams, workspaceId, threatId, additionalParams, additionalSearchParams), opts), - [ - searchParams, workspaceId, - ]); -}; - -export default useNavigateView; \ No newline at end of file diff --git a/packages/threat-composer-app/src/hooks/useOnPreview/index.ts b/packages/threat-composer-app/src/hooks/useOnPreview/index.ts deleted file mode 100644 index c57a444e..00000000 --- a/packages/threat-composer-app/src/hooks/useOnPreview/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** ******************************************************************************************************************* - Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"). - You may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ******************************************************************************************************************** */ -import { DataExchangeFormat } from '@aws/threat-composer'; -import { useCallback } from 'react'; -import { generatePath } from 'react-router-dom'; -import { ROUTE_PREVIEW } from '../../config/routes'; - -const TEMP_PREVIEW_DATA_KEY = 'ThreatStatementGenerator.TempPreviewData'; -const ROUTE_BASE_PATH = process.env.REACT_APP_ROUTE_BASE_PATH; - -const useOnPreview = () => { - const handlePreview = useCallback((data: DataExchangeFormat) => { - window.localStorage.setItem(TEMP_PREVIEW_DATA_KEY, JSON.stringify(data)); - const url = `${ROUTE_BASE_PATH || ''}${generatePath(ROUTE_PREVIEW, { - dataKey: TEMP_PREVIEW_DATA_KEY, - })}`; - - window.open(url, '_blank', 'noopener,noreferrer,resizable'); - }, []); - - return [handlePreview] as [(data: DataExchangeFormat) => void]; -}; - -export default useOnPreview; \ No newline at end of file diff --git a/packages/threat-composer-app/src/index.tsx b/packages/threat-composer-app/src/index.tsx index ef498be9..d56b2606 100644 --- a/packages/threat-composer-app/src/index.tsx +++ b/packages/threat-composer-app/src/index.tsx @@ -16,11 +16,14 @@ import { ThemeProvider, Mode } from '@aws/threat-composer'; import React from 'react'; import ReactDOM from 'react-dom'; +import { BrowserRouter, MemoryRouter } from 'react-router-dom'; import App from './containers/App'; import reportWebVitals from './reportWebVitals'; import * as serviceWorkerRegistration from './serviceWorkerRegistration'; import isMemoryRouterUsed from './utils/isMemoryRouterUsed'; +const Router = isMemoryRouterUsed() ? MemoryRouter : BrowserRouter; + const initialThemeString = (document.querySelector('meta[name="dark-mode"]') as HTMLMetaElement)?.content; const initialTheme = initialThemeString ? @@ -30,7 +33,9 @@ const initialTheme = initialThemeString ? ReactDOM.render( - + + + , document.getElementById('root'), diff --git a/packages/threat-composer-app/src/routes/index.tsx b/packages/threat-composer-app/src/routes/index.tsx index cff6f4d6..685562d8 100644 --- a/packages/threat-composer-app/src/routes/index.tsx +++ b/packages/threat-composer-app/src/routes/index.tsx @@ -13,130 +13,95 @@ See the License for the specific language governing permissions and limitations under the License. ******************************************************************************************************************** */ -import { createBrowserRouter, createMemoryRouter, redirect } from 'react-router-dom'; -import initialWorkspaceLoader from './initialWorkspaceLoader'; +import { RouteProps } from 'react-router-dom'; import { - ROUTE_WORKSPACE_HOME_PATH, - ROUTE_APPLICATION_INFO_PATH, - ROUTE_ARCHITECTURE_INFO_PATH, - ROUTE_ASSUMPTION_LIST_PATH, - ROUTE_DATAFLOW_INFO_PATH, - ROUTE_MITIGATION_LIST_PATH, - ROUTE_THREAT_EDITOR_PATH, - ROUTE_THREAT_LIST_PATH, - ROUTE_VIEW_THREAT_MODEL_PATH, - ROUTE_THREAT_PACK_PATH, - ROUTE_THREAT_PACKS_PATH, - ROUTE_MITIGATION_PACK_PATH, - ROUTE_MITIGATION_PACKS_PATH, - ROUTE_WORKSPACE_PATH, - ROUTE_PREVIEW_PATH, + ROUTE_WORKSPACE_HOME, + ROUTE_APPLICATION_INFO, + ROUTE_ARCHITECTURE_INFO, + ROUTE_ASSUMPTION_LIST, + ROUTE_DATAFLOW_INFO, + ROUTE_MITIGATION_LIST, + ROUTE_THREAT_EDITOR, + ROUTE_THREAT_LIST, + ROUTE_VIEW_THREAT_MODEL, + ROUTE_THREAT_PACK, + ROUTE_THREAT_PACKS, + ROUTE_MITIGATION_PACK, + ROUTE_MITIGATION_PACKS, } from '../config/routes'; import Application from '../containers/Application'; -import AppRoot from '../containers/AppRoot'; import Architecture from '../containers/Architecture'; import AssumptionList from '../containers/AssumptionList'; import Dataflow from '../containers/Dataflow'; import MitigationList from '../containers/MitigationList'; import MitigationPack from '../containers/MitigationPack'; import MitigationPacks from '../containers/MitigationPacks'; -import ThreatModelPreview from '../containers/ThreatModelPreview'; import ThreatModelReport from '../containers/ThreatModelReport'; import ThreatPack from '../containers/ThreatPack'; import ThreatPacks from '../containers/ThreatPacks'; import ThreatStatementEditor from '../containers/ThreatStatementEditor'; import ThreatStatementList from '../containers/ThreatStatementList'; import WorkspaceHome from '../containers/WorkspaceHome'; -import WorkspaceRoot from '../containers/WorkspaceRoot'; -import isMemoryRouterUsed from '../utils/isMemoryRouterUsed'; -const ROUTE_BASE_PATH = process.env.REACT_APP_ROUTE_BASE_PATH; +const ROUTE_BASE_PATH = process.env.REACT_APP_ROUTE_BASE_PATH || ''; -const workspaceRoutes = [ - { - index: true, - loader: async () => redirect(ROUTE_WORKSPACE_HOME_PATH), - }, +const getRouteWithBasePath = (route: string) => { + return `${ROUTE_BASE_PATH}${route}`; +}; + +const routes: RouteProps[] = [ { - path: ROUTE_WORKSPACE_HOME_PATH, + path: getRouteWithBasePath(ROUTE_WORKSPACE_HOME), element: , }, { - path: ROUTE_APPLICATION_INFO_PATH, + path: getRouteWithBasePath(ROUTE_APPLICATION_INFO), element: , }, { - path: ROUTE_ARCHITECTURE_INFO_PATH, + path: getRouteWithBasePath(ROUTE_ARCHITECTURE_INFO), element: , }, { - path: ROUTE_ASSUMPTION_LIST_PATH, + path: getRouteWithBasePath(ROUTE_ASSUMPTION_LIST), element: , }, { - path: ROUTE_DATAFLOW_INFO_PATH, + path: getRouteWithBasePath(ROUTE_DATAFLOW_INFO), element: , }, { - path: ROUTE_MITIGATION_LIST_PATH, + path: getRouteWithBasePath(ROUTE_MITIGATION_LIST), element: , }, { - path: ROUTE_VIEW_THREAT_MODEL_PATH, + path: getRouteWithBasePath(ROUTE_VIEW_THREAT_MODEL), element: , }, { - path: ROUTE_THREAT_PACK_PATH, + path: getRouteWithBasePath(ROUTE_THREAT_PACK), element: , }, { - path: ROUTE_THREAT_PACKS_PATH, + path: getRouteWithBasePath(ROUTE_THREAT_PACKS), element: , }, { - path: ROUTE_MITIGATION_PACK_PATH, + path: getRouteWithBasePath(ROUTE_MITIGATION_PACK), element: , }, { - path: ROUTE_MITIGATION_PACKS_PATH, + path: getRouteWithBasePath(ROUTE_MITIGATION_PACKS), element: , }, { - path: ROUTE_THREAT_EDITOR_PATH, + path: getRouteWithBasePath(ROUTE_THREAT_EDITOR), element: , }, { - path: ROUTE_THREAT_LIST_PATH, + path: getRouteWithBasePath(ROUTE_THREAT_LIST), element: , }, ]; -export const createRouter = isMemoryRouterUsed() ? createMemoryRouter : createBrowserRouter; - -export const routerOpts = ROUTE_BASE_PATH ? { - basename: ROUTE_BASE_PATH, -} : {}; - -export const routes = [ - { - index: true, - loader: initialWorkspaceLoader, - }, - { - path: '/', - element: , - children: [ - { - path: ROUTE_WORKSPACE_PATH, - element: , - children: [ - ...workspaceRoutes, - ], - }, - { - path: ROUTE_PREVIEW_PATH, - element: , - }, - ], - }, -]; +export default routes; \ No newline at end of file diff --git a/packages/threat-composer-app/src/routes/initialWorkspaceLoader.tsx b/packages/threat-composer-app/src/routes/initialWorkspaceLoader.tsx deleted file mode 100644 index a615b544..00000000 --- a/packages/threat-composer-app/src/routes/initialWorkspaceLoader.tsx +++ /dev/null @@ -1,41 +0,0 @@ -/** ******************************************************************************************************************* - Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"). - You may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ******************************************************************************************************************** */ -import { LOCAL_STORAGE_KEY_CURRENT_WORKSPACE, Workspace } from '@aws/threat-composer'; -import { generatePath, redirect } from 'react-router-dom'; -import { ROUTE_WORKSPACE_DEFAULT, ROUTE_WORKSPACE_PATH } from '../config/routes'; - -const initialWorkspaceLoader = async () => { - const currentWorkspaceValue = window.localStorage.getItem(LOCAL_STORAGE_KEY_CURRENT_WORKSPACE); - - if (currentWorkspaceValue) { - try { - const currentWorkspace = JSON.parse(currentWorkspaceValue) as Workspace | null | undefined; - if (currentWorkspace) { - const redirectUrl = generatePath(ROUTE_WORKSPACE_PATH, { - workspaceId: currentWorkspace.name, - }); - return redirect(redirectUrl); - } - - } catch (e) { - console.log('Error in retrieving current workspace', currentWorkspaceValue); - } - } - - return redirect(ROUTE_WORKSPACE_DEFAULT); -}; - -export default initialWorkspaceLoader; \ No newline at end of file diff --git a/packages/threat-composer-app/src/utils/generateUrl/index.ts b/packages/threat-composer-app/src/utils/generateUrl/index.ts index 584215dc..d6c846b2 100644 --- a/packages/threat-composer-app/src/utils/generateUrl/index.ts +++ b/packages/threat-composer-app/src/utils/generateUrl/index.ts @@ -15,6 +15,9 @@ ******************************************************************************************************************** */ import { generatePath } from 'react-router-dom'; import { SEARCH_PARAM_FEATURES, SEARCH_PARAM_MODE } from '../../config/searchParams'; + +const ROUTE_BASE_PATH = process.env.REACT_APP_ROUTE_BASE_PATH || ''; + const SEARCH_PARAMS_KEPT = [SEARCH_PARAM_MODE, SEARCH_PARAM_FEATURES]; const generateUrl = (path: string, searchParams: URLSearchParams, workspaceId: string, threatId?: string, @@ -23,7 +26,7 @@ const generateUrl = (path: string, searchParams: URLSearchParams, workspaceId: s }, additionalSearchParams?: { [key: string]: string; }) => { - const baseUrl = `${generatePath(path, { + const baseUrl = `${ROUTE_BASE_PATH}${generatePath(path, { workspaceId, threatId, ...additionalParams, diff --git a/packages/threat-composer-app/src/utils/getComposerMode/index.tsx b/packages/threat-composer-app/src/utils/getComposerMode/index.tsx deleted file mode 100644 index 902cadbc..00000000 --- a/packages/threat-composer-app/src/utils/getComposerMode/index.tsx +++ /dev/null @@ -1,28 +0,0 @@ -/** ******************************************************************************************************************* - Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"). - You may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ******************************************************************************************************************** */ - -import { SEARCH_PARAM_MODE } from '../../config/searchParams'; - -const DEFAULT_MODE = process.env.REACT_APP_DEFAULT_MODE; - -const getComposerMode = () => { - const searchParams = new URLSearchParams(window.location.search); - const mode = searchParams.get(SEARCH_PARAM_MODE); - const composerMode = mode || DEFAULT_MODE || 'Full'; - return composerMode; -}; - -export default getComposerMode; \ No newline at end of file diff --git a/packages/threat-composer/src/components/application/ApplicationInfo/index.tsx b/packages/threat-composer/src/components/application/ApplicationInfo/index.tsx index 9e56a5d6..4d83efc5 100644 --- a/packages/threat-composer/src/components/application/ApplicationInfo/index.tsx +++ b/packages/threat-composer/src/components/application/ApplicationInfo/index.tsx @@ -27,7 +27,6 @@ import MarkdownViewer from '../../generic/MarkdownViewer'; const ApplicationInfo: FC = ({ onEditModeChange, - MarkdownEditorComponentType = MarkdownEditor, }) => { const { applicationInfo, setApplicationInfo } = useApplicationInfoContext(); const [editMode, setEditMode] = useState(!applicationInfo.name && !applicationInfo.description ); @@ -75,7 +74,7 @@ const ApplicationInfo: FC = ({ placeholder='Enter application name' /> - = ({ onConfirm, validateData, onEditModeChange, - MarkdownEditorComponentType = MarkdownEditor, }) => { const [editMode, setEditMode] = useState(!entity.description && !entity.image); const [image, setImage] = useState(''); @@ -73,7 +72,7 @@ const BaseDiagramInfo: FC = ({ return ({headerTitle}}> {editMode ? ( - void; +export interface ThreatModelProps { + onPrintButtonClick?: () => void; isPreview?: boolean; convertToDocx?: ThreatModelViewProps['convertToDocx']; } @@ -41,20 +40,28 @@ const ThreatModel: FC = ({ return getExportFileName(composerMode, false, currentWorkspace); }, [composerMode, currentWorkspace]); + const { + onApplicationInfoView, + onArchitectureView, + onDataflowView, + onAssumptionListView, + onThreatListView, + onMitigationListView, + } = useWorkspacesContext(); return onPrintButtonClick?.(getWorkspaceData())} + onPrintButtonClick={onPrintButtonClick} showPrintDownloadButtons={appMode !== APP_MODE_IDE_EXTENSION} composerMode={composerMode} data={getWorkspaceData()} downloadFileName={downloadFileName} hasContentDetails={hasContentDetails} - onApplicationInfoView={props.onApplicationInfoView} - onArchitectureView={props.onArchitectureView} - onDataflowView={props.onDataflowView} - onAssumptionListView={props.onAssumptionListView} - onThreatListView={props.onThreatListView} - onMitigationListView={props.onMitigationListView} + onApplicationInfoView={onApplicationInfoView} + onArchitectureView={onArchitectureView} + onDataflowView={onDataflowView} + onAssumptionListView={onAssumptionListView} + onThreatListView={onThreatListView} + onMitigationListView={onMitigationListView} />; }; diff --git a/packages/threat-composer/src/components/threats/ThreatStatementEditor/index.tsx b/packages/threat-composer/src/components/threats/ThreatStatementEditor/index.tsx index f6b26df6..0c60b46b 100644 --- a/packages/threat-composer/src/components/threats/ThreatStatementEditor/index.tsx +++ b/packages/threat-composer/src/components/threats/ThreatStatementEditor/index.tsx @@ -30,7 +30,7 @@ import { useMitigationLinksContext } from '../../../contexts/MitigationLinksCont import { useMitigationsContext } from '../../../contexts/MitigationsContext/context'; import { useThreatsContext } from '../../../contexts/ThreatsContext/context'; import { useWorkspacesContext } from '../../../contexts/WorkspacesContext/context'; -import { TemplateThreatStatement, ViewNavigationEvent } from '../../../customTypes'; +import { TemplateThreatStatement } from '../../../customTypes'; import { ThreatFieldTypes } from '../../../customTypes/threatFieldTypes'; import threatFieldData from '../../../data/threatFieldData'; import threatStatementExamples from '../../../data/threatStatementExamples.json'; @@ -72,10 +72,6 @@ const styles = { const defaultThreatStatementFormat = threatStatementFormat[63]; -export interface ThreatStatementEditorProps { - onThreatListView?: ViewNavigationEvent['onThreatListView']; -} - const editorMapping: { [key in ThreatFieldTypes]: React.ComponentType }> } = { threat_source: EditorThreatSource, prerequisites: EditorPrerequisites, @@ -85,11 +81,10 @@ const editorMapping: { [key in ThreatFieldTypes]: React.ComponentType = ({ +const ThreatStatementEditorInner: FC<{ editingStatement: TemplateThreatStatement }> = ({ editingStatement, - onThreatListView, }) => { - const { setEditingStatement, saveStatement, addStatement } = useThreatsContext(); + const { setEditingStatement, saveStatement, addStatement, onThreatListView } = useThreatsContext(); const inputRef = useRef<{ focus(): void }>(); const fullExamplesRef = useRef<{ collapse(): void }>(); const { currentWorkspace, workspaceList } = useWorkspacesContext(); @@ -383,10 +378,10 @@ const ThreatStatementEditorInner: FC); }; -const ThreatStatementEditor: FC = (props) => { +const ThreatStatementEditor: FC = () => { const { editingStatement } = useThreatsContext(); - return editingStatement ? : null; + return editingStatement ? : null; }; export default ThreatStatementEditor; \ No newline at end of file diff --git a/packages/threat-composer/src/components/threats/ThreatStatementList/index.tsx b/packages/threat-composer/src/components/threats/ThreatStatementList/index.tsx index 58ae2e5e..55247152 100644 --- a/packages/threat-composer/src/components/threats/ThreatStatementList/index.tsx +++ b/packages/threat-composer/src/components/threats/ThreatStatementList/index.tsx @@ -27,7 +27,7 @@ import { LEVEL_SELECTOR_OPTIONS, DEFAULT_NEW_ENTITY_ID, LEVEL_NOT_SET } from '.. import { useAssumptionLinksContext, useMitigationLinksContext } from '../../../contexts'; import { useGlobalSetupContext } from '../../../contexts/GlobalSetupContext/context'; import { useThreatsContext } from '../../../contexts/ThreatsContext/context'; -import { TemplateThreatStatement, ThreatStatementListFilter, ViewNavigationEvent } from '../../../customTypes'; +import { TemplateThreatStatement, ThreatStatementListFilter } from '../../../customTypes'; import useEditMetadata from '../../../hooks/useEditMetadata'; import { addTagToEntity, removeTagFromEntity } from '../../../utils/entityTag'; import AssetSelector from '../../generic/AssetSelector'; @@ -64,12 +64,10 @@ const styles = { export interface ThreatStatementListProps { initialFilter?: ThreatStatementListFilter; - onThreatEditorView?: ViewNavigationEvent['onThreatEditorView']; } const ThreatStatementList: FC = ({ initialFilter, - onThreatEditorView, }) => { const { statementList, @@ -77,6 +75,7 @@ const ThreatStatementList: FC = ({ addStatement, editStatement, saveStatement, + onThreatEditorView, } = useThreatsContext(); const { diff --git a/packages/threat-composer/src/components/workspaces/EditWorkspace/index.tsx b/packages/threat-composer/src/components/workspaces/EditWorkspace/index.tsx index 3d214df6..3a653e78 100644 --- a/packages/threat-composer/src/components/workspaces/EditWorkspace/index.tsx +++ b/packages/threat-composer/src/components/workspaces/EditWorkspace/index.tsx @@ -32,7 +32,6 @@ export interface EditWorkspaceProps { editMode?: boolean; currentWorkspace?: Workspace; workspaceList: Workspace[]; - exampleWorkspaceList: Workspace[]; } const EditWorkspace: FC = ({ @@ -41,7 +40,6 @@ const EditWorkspace: FC = ({ onConfirm, editMode = false, workspaceList, - exampleWorkspaceList, currentWorkspace, ...props }) => { @@ -57,13 +55,11 @@ const EditWorkspace: FC = ({ setErrorText(''); if (workspaceList.find(x => x.name === value && (!currentWorkspace || currentWorkspace.id !== x.id))) { setErrorText('A workspace already exists with that name'); - } else if (exampleWorkspaceList.find(x => x.name === value)) { - setErrorText('A workspace example already exists with that name'); } else { await onConfirm(value); setVisible(false); } - }, [onConfirm, value, workspaceList, exampleWorkspaceList, currentWorkspace]); + }, [onConfirm, value, workspaceList, currentWorkspace]); useEffect(() => { inputRef.current?.focus(); diff --git a/packages/threat-composer/src/components/workspaces/LandingPage/index.tsx b/packages/threat-composer/src/components/workspaces/LandingPage/index.tsx index 0cd3e818..224c7bfb 100644 --- a/packages/threat-composer/src/components/workspaces/LandingPage/index.tsx +++ b/packages/threat-composer/src/components/workspaces/LandingPage/index.tsx @@ -27,14 +27,8 @@ import HowItWorks from '../../../assets/how-it-works.png'; import SwitchToExample from '../../../assets/switch-to-example-workspace.gif'; import { useGlobalSetupContext } from '../../../contexts'; -export interface LandingPageProps { - onDefineWorkload?: () => void; -} - -const LandingPage: FC = ({ - onDefineWorkload, -}) => { - const { setFileImportModalVisible } = useGlobalSetupContext(); +const LandingPage: FC = () => { + const { setFileImportModalVisible, onDefineWorkload } = useGlobalSetupContext(); return ( = (props) => { +const WorkspaceHome = () => { const [hasContent] = useHasContent(); - return hasContent ? : ; + return hasContent ? : ; }; export default WorkspaceHome; \ No newline at end of file diff --git a/packages/threat-composer/src/components/workspaces/WorkspaceInsights/components/Overview/index.tsx b/packages/threat-composer/src/components/workspaces/WorkspaceInsights/components/Overview/index.tsx index 962b1806..a1ea65f7 100644 --- a/packages/threat-composer/src/components/workspaces/WorkspaceInsights/components/Overview/index.tsx +++ b/packages/threat-composer/src/components/workspaces/WorkspaceInsights/components/Overview/index.tsx @@ -27,7 +27,6 @@ import { useThreatsContext } from '../../../../../contexts/ThreatsContext'; import filterThreatsByMetadata from '../../../../../utils/filterThreatsByMetadata'; import DashboardNumber from '../../../../generic/DashboardNumber'; import useLinkClicked from '../../hooks/useLinkClicked'; -import { WorkspaceInsightsProps } from '../../types'; const styles = { container: css({ @@ -60,9 +59,7 @@ const LabelValuePair: FC<{ ); }; -const Overview: FC = ({ - onThreatListView, -}) => { +const Overview: FC = () => { const { statementList } = useThreatsContext(); const { mitigationLinkList } = useMitigationLinksContext(); const { assumptionLinkList } = useAssumptionLinksContext(); @@ -75,7 +72,7 @@ const Overview: FC = ({ ).length; }, [statementList, mitigationLinkList, assumptionLinkList]); - const handleLinkClicked = useLinkClicked(onThreatListView); + const handleLinkClicked = useLinkClicked(); const missingMitigation = useMemo(() => { return statementList.filter( diff --git a/packages/threat-composer/src/components/workspaces/WorkspaceInsights/components/STRIDEAllocation/index.tsx b/packages/threat-composer/src/components/workspaces/WorkspaceInsights/components/STRIDEAllocation/index.tsx index ea7f32e0..426d87b2 100644 --- a/packages/threat-composer/src/components/workspaces/WorkspaceInsights/components/STRIDEAllocation/index.tsx +++ b/packages/threat-composer/src/components/workspaces/WorkspaceInsights/components/STRIDEAllocation/index.tsx @@ -22,7 +22,7 @@ import { BarChart, BarChartProps, } from '@cloudscape-design/components'; -import { useState, useMemo, useCallback, FC } from 'react'; +import { useState, useMemo, useCallback } from 'react'; import { ALL_LEVELS, LEVEL_NOT_SET, @@ -30,16 +30,14 @@ import { DEFAULT_NEW_ENTITY_ID, } from '../../../../../configs'; import { useThreatsContext } from '../../../../../contexts/ThreatsContext'; +import { useWorkspacesContext } from '../../../../../contexts/WorkspacesContext'; import filterThreatsByMetadata from '../../../../../utils/filterThreatsByMetadata'; import DashboardNumber from '../../../../generic/DashboardNumber'; import useLinkClicked from '../../hooks/useLinkClicked'; -import { WorkspaceInsightsProps } from '../../types'; -const STRIDEAllocation: FC = ({ - onThreatEditorView, - onThreatListView, -}) => { +const STRIDEAllocation = () => { const { statementList, addStatement } = useThreatsContext(); + const { onThreatEditorView } = useWorkspacesContext(); const [selectedPriority, setSelectedPriority] = useState( ALL_LEVELS, @@ -83,7 +81,7 @@ const STRIDEAllocation: FC = ({ [filteredStatementList], ); - const handleLinkClicked = useLinkClicked(onThreatListView); + const handleLinkClicked = useLinkClicked(); const barSeries: BarChartProps['series'] = [ { diff --git a/packages/threat-composer/src/components/workspaces/WorkspaceInsights/components/ThreatGrammar/index.tsx b/packages/threat-composer/src/components/workspaces/WorkspaceInsights/components/ThreatGrammar/index.tsx index f7ae110b..6a890c6f 100644 --- a/packages/threat-composer/src/components/workspaces/WorkspaceInsights/components/ThreatGrammar/index.tsx +++ b/packages/threat-composer/src/components/workspaces/WorkspaceInsights/components/ThreatGrammar/index.tsx @@ -26,21 +26,20 @@ import { colorChartsPaletteCategorical2, colorChartsPaletteCategorical1, } from '@cloudscape-design/design-tokens'; -import { useState, useMemo, useCallback, FC } from 'react'; +import { useState, useMemo, useCallback } from 'react'; import { ALL_LEVELS, LEVEL_SELECTOR_OPTIONS_INCLUDING_ALL, DEFAULT_NEW_ENTITY_ID, } from '../../../../../configs'; import { useThreatsContext } from '../../../../../contexts/ThreatsContext'; +import { useWorkspacesContext } from '../../../../../contexts/WorkspacesContext'; import filterThreatsByMetadata from '../../../../../utils/filterThreatsByMetadata'; import DashboardNumber from '../../../../generic/DashboardNumber'; -import { WorkspaceInsightsProps } from '../../types'; -const ThreatGrammar: FC = ({ - onThreatEditorView, -}) => { +const ThreatGrammar = () => { const { statementList, addStatement } = useThreatsContext(); + const { onThreatEditorView } = useWorkspacesContext(); const [selectedPriority, setSelectedPriority] = useState( ALL_LEVELS, diff --git a/packages/threat-composer/src/components/workspaces/WorkspaceInsights/components/ThreatPrioritization/index.tsx b/packages/threat-composer/src/components/workspaces/WorkspaceInsights/components/ThreatPrioritization/index.tsx index d4b43b46..4507568a 100644 --- a/packages/threat-composer/src/components/workspaces/WorkspaceInsights/components/ThreatPrioritization/index.tsx +++ b/packages/threat-composer/src/components/workspaces/WorkspaceInsights/components/ThreatPrioritization/index.tsx @@ -25,7 +25,7 @@ import { colorChartsStatusHigh, colorChartsStatusNeutral, } from '@cloudscape-design/design-tokens'; -import { useMemo, useCallback, FC } from 'react'; +import { useMemo, useCallback } from 'react'; import { LEVEL_HIGH, LEVEL_LOW, @@ -34,18 +34,16 @@ import { DEFAULT_NEW_ENTITY_ID, } from '../../../../../configs'; import { useThreatsContext } from '../../../../../contexts/ThreatsContext'; +import { useWorkspacesContext } from '../../../../../contexts/WorkspacesContext'; import filterThreatsByMetadata from '../../../../../utils/filterThreatsByMetadata'; import DashboardNumber from '../../../../generic/DashboardNumber'; import useLinkClicked from '../../hooks/useLinkClicked'; -import { WorkspaceInsightsProps } from '../../types'; -const ThreatPrioritization: FC = ({ - onThreatEditorView, - onThreatListView, -}) => { +const ThreatPrioritization = () => { const { statementList, addStatement } = useThreatsContext(); + const { onThreatEditorView } = useWorkspacesContext(); - const handleLinkClicked = useLinkClicked(onThreatListView); + const handleLinkClicked = useLinkClicked(); const missingPriority = useMemo( () => filterThreatsByMetadata(statementList, 'Priority').length, diff --git a/packages/threat-composer/src/components/workspaces/WorkspaceInsights/hooks/useLinkClicked/index.tsx b/packages/threat-composer/src/components/workspaces/WorkspaceInsights/hooks/useLinkClicked/index.tsx index 6056c4c4..cceec1af 100644 --- a/packages/threat-composer/src/components/workspaces/WorkspaceInsights/hooks/useLinkClicked/index.tsx +++ b/packages/threat-composer/src/components/workspaces/WorkspaceInsights/hooks/useLinkClicked/index.tsx @@ -15,9 +15,11 @@ ******************************************************************************************************************** */ import { CancelableEventHandler, BaseNavigationDetail } from '@cloudscape-design/components/internal/events'; import { useCallback } from 'react'; -import { ThreatStatementListFilter, ViewNavigationEvent } from '../../../../../customTypes'; +import { useThreatsContext } from '../../../../../contexts/ThreatsContext'; +import { ThreatStatementListFilter } from '../../../../../customTypes'; -const useLinkClicked = (onThreatListView: ViewNavigationEvent['onThreatListView']) => { +const useLinkClicked = () => { + const { onThreatListView } = useThreatsContext(); return useCallback((filter?: ThreatStatementListFilter): CancelableEventHandler => (event) => { event?.preventDefault?.(); onThreatListView?.(filter); diff --git a/packages/threat-composer/src/components/workspaces/WorkspaceInsights/index.tsx b/packages/threat-composer/src/components/workspaces/WorkspaceInsights/index.tsx index 3f2ce4a5..250759d6 100644 --- a/packages/threat-composer/src/components/workspaces/WorkspaceInsights/index.tsx +++ b/packages/threat-composer/src/components/workspaces/WorkspaceInsights/index.tsx @@ -17,46 +17,43 @@ import Board, { BoardProps } from '@cloudscape-design/board-components/board'; import BoardItem from '@cloudscape-design/board-components/board-item'; import ContentLayout from '@cloudscape-design/components/content-layout'; import Header from '@cloudscape-design/components/header'; -import { useState, ReactNode, useCallback, FC } from 'react'; +import { useState, ReactNode, useCallback } from 'react'; import Overview from './components/Overview'; import STRIDEAllocation from './components/STRIDEAllocation'; import ThreatGrammar from './components/ThreatGrammar'; import ThreatPrioritization from './components/ThreatPrioritization'; -import { WorkspaceInsightsProps } from './types'; import { useApplicationInfoContext } from '../../../contexts/ApplicationContext'; -export * from './types'; - export interface ItemType { title: string; content: ReactNode; } -const WorkspaceInsights: FC = (props) => { +const WorkspaceInsights = () => { const [items, setItems] = useState[]>([ { id: 'overview', rowSpan: 2, columnSpan: 6, - data: { title: 'Threat summary', content: }, + data: { title: 'Threat summary', content: }, }, { id: 'threat-prioritization', rowSpan: 5, columnSpan: 2, - data: { title: 'Threat prioritization', content: }, + data: { title: 'Threat prioritization', content: }, }, { id: 'stride-allocation', rowSpan: 5, columnSpan: 2, - data: { title: 'Threat category distribution', content: }, + data: { title: 'Threat category distribution', content: }, }, { id: 'threat-grammer', rowSpan: 5, columnSpan: 2, - data: { title: 'Threat grammar distribution', content: }, + data: { title: 'Threat grammar distribution', content: }, }, ]); @@ -185,4 +182,4 @@ const WorkspaceInsights: FC = (props) => { />); }; -export default WorkspaceInsights; +export default WorkspaceInsights; \ No newline at end of file diff --git a/packages/threat-composer/src/components/workspaces/WorkspaceInsights/types.tsx b/packages/threat-composer/src/components/workspaces/WorkspaceInsights/types.tsx deleted file mode 100644 index b568569a..00000000 --- a/packages/threat-composer/src/components/workspaces/WorkspaceInsights/types.tsx +++ /dev/null @@ -1,22 +0,0 @@ -/** ******************************************************************************************************************* - Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"). - You may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ******************************************************************************************************************** */ - -import { ViewNavigationEvent } from '../../../customTypes'; - -export interface WorkspaceInsightsProps { - onThreatEditorView?: ViewNavigationEvent['onThreatEditorView']; - onThreatListView?: ViewNavigationEvent['onThreatListView']; -} \ No newline at end of file diff --git a/packages/threat-composer/src/components/workspaces/WorkspaceSelector/index.tsx b/packages/threat-composer/src/components/workspaces/WorkspaceSelector/index.tsx index 9e14c66a..d4034b08 100644 --- a/packages/threat-composer/src/components/workspaces/WorkspaceSelector/index.tsx +++ b/packages/threat-composer/src/components/workspaces/WorkspaceSelector/index.tsx @@ -57,9 +57,6 @@ export interface WorkspaceSelectorProps { eventName?: string; onClick?: (data: DataExchangeFormat) => void; }; - onPreview?: (data: DataExchangeFormat) => void; - onPreviewClose?: () => void; - onImported?: () => void; } const WorkspaceSelector: FC> = ({ @@ -71,9 +68,6 @@ const WorkspaceSelector: FC> = ({ filteredThreats, singletonMode = false, singletonPrimaryActionButtonConfig, - onPreview, - onPreviewClose, - onImported, }) => { const [addWorkspaceModalVisible, setAddWorkspaceModalVisible] = useState(false); @@ -92,6 +86,9 @@ const WorkspaceSelector: FC> = ({ const { appMode, composerMode, + onPreview, + onPreviewClose, + onImported, fileImportModalVisible, setFileImportModalVisible, } = useGlobalSetupContext(); @@ -379,7 +376,6 @@ const WorkspaceSelector: FC> = ({ await addWorkspace(workspaceName); }} workspaceList={workspaceList} - exampleWorkspaceList={workspaceExamples} /> )} {editWorkspaceModalVisible && currentWorkspace && ( @@ -393,7 +389,6 @@ const WorkspaceSelector: FC> = ({ } currentWorkspace={currentWorkspace} workspaceList={workspaceList} - exampleWorkspaceList={workspaceExamples} /> )} {removeDataModalVisible && ( diff --git a/packages/threat-composer/src/contexts/ContextAggregator/index.tsx b/packages/threat-composer/src/contexts/ContextAggregator/index.tsx index 21d50c86..e9c9951f 100644 --- a/packages/threat-composer/src/contexts/ContextAggregator/index.tsx +++ b/packages/threat-composer/src/contexts/ContextAggregator/index.tsx @@ -14,13 +14,13 @@ limitations under the License. ******************************************************************************************************************** */ import { FC, PropsWithChildren } from 'react'; -import { AppMode, ComposerMode, DataExchangeFormat } from '../../customTypes'; +import { AppMode, ComposerMode, DataExchangeFormat, ViewNavigationEvent } from '../../customTypes'; import GlobalSetupContextProvider from '../GlobalSetupContext'; import WorkspaceContextAggregator from '../WorkspaceContextAggregator'; import WorkspaceExamplesContext from '../WorkspaceExamplesContext'; import WorkspacesContextProvider, { WorkspacesContextProviderProps } from '../WorkspacesContext'; -export interface ContextAggregatorProps { +export interface ContextAggregatorProps extends ViewNavigationEvent { composerMode?: ComposerMode; appMode?: AppMode; features?: string[]; @@ -37,11 +37,19 @@ const ContextAggregator: FC> = ({ appMode, composerMode = 'Full', features, + onPreview, + onPreviewClose, + onImported, + onDefineWorkload, ...props }) => { return ( @@ -52,6 +60,8 @@ const ContextAggregator: FC> = ({ {(workspaceId) => ( {children} )} diff --git a/packages/threat-composer/src/contexts/GlobalSetupContext/context.ts b/packages/threat-composer/src/contexts/GlobalSetupContext/context.ts index ad77b19a..a96630fb 100644 --- a/packages/threat-composer/src/contexts/GlobalSetupContext/context.ts +++ b/packages/threat-composer/src/contexts/GlobalSetupContext/context.ts @@ -14,14 +14,18 @@ limitations under the License. ******************************************************************************************************************** */ import React, { useContext, createContext } from 'react'; -import { AppMode, ComposerMode } from '../../customTypes'; +import { AppMode, ComposerMode, DataExchangeFormat } from '../../customTypes'; export interface GlobalSetupContextApi { hasVisitBefore: boolean; showInfoModal: () => void; composerMode: ComposerMode; appMode: AppMode; - features: string[]; + features?: string[]; + onPreview?: (content: DataExchangeFormat) => void; + onPreviewClose?: () => void; + onImported?: () => void; + onDefineWorkload?: () => void; fileImportModalVisible: boolean; setFileImportModalVisible: React.Dispatch>; } diff --git a/packages/threat-composer/src/contexts/GlobalSetupContext/index.tsx b/packages/threat-composer/src/contexts/GlobalSetupContext/index.tsx index bae7fd21..7907fda0 100644 --- a/packages/threat-composer/src/contexts/GlobalSetupContext/index.tsx +++ b/packages/threat-composer/src/contexts/GlobalSetupContext/index.tsx @@ -21,13 +21,17 @@ import { GlobalSetupContext, useGlobalSetupContext } from './context'; import { useThemeContext } from '../../components/generic/ThemeProvider'; import InfoModal from '../../components/global/InfoModal'; import { LOCAL_STORAGE_KEY_NEW_VISIT_FLAG } from '../../configs/localStorageKeys'; -import { ComposerMode, AppMode } from '../../customTypes'; +import { ComposerMode, DataExchangeFormat, AppMode } from '../../customTypes'; import EventController from '../../utils/EventController'; export interface GlobalSetupContextProviderProps { composerMode?: ComposerMode; appMode?: AppMode; features?: string[]; + onPreview?: (content: DataExchangeFormat) => void; + onPreviewClose?: () => void; + onImported?: () => void; + onDefineWorkload?: () => void; } const stringifyWorkspaceData = (data: any) => { @@ -48,6 +52,10 @@ const GlobalSetupContextProvider: FC { const [fileImportModalVisible, setFileImportModalVisible] = useState(false); const { setTheme, setDensity } = useThemeContext(); @@ -80,10 +88,14 @@ const GlobalSetupContextProvider: FC setInfoModalVisible(true), + onPreview, + onPreviewClose, + onImported, fileImportModalVisible, setFileImportModalVisible, + onDefineWorkload, }}> {children} {infoModalVisible && >> = ({ children, initialValue, + onThreatListView, + onThreatEditorView, }) => { const [editingStatement, setEditingStatement] = useState(null); @@ -81,6 +83,8 @@ const ThreatsContextProvider: FC {children} ); diff --git a/packages/threat-composer/src/contexts/ThreatsContext/components/LocalStorageContextProvider/index.tsx b/packages/threat-composer/src/contexts/ThreatsContext/components/LocalStorageContextProvider/index.tsx index f3717138..880382b7 100644 --- a/packages/threat-composer/src/contexts/ThreatsContext/components/LocalStorageContextProvider/index.tsx +++ b/packages/threat-composer/src/contexts/ThreatsContext/components/LocalStorageContextProvider/index.tsx @@ -41,6 +41,8 @@ interface ThreatsContextProviderInnerProps { const ThreatsContextProviderInner: FC> = ({ children, workspaceId: currentWorkspaceId, + onThreatListView, + onThreatEditorView, editingStatement, setEditingStatement, removeEditingStatement, @@ -115,6 +117,8 @@ const ThreatsContextProviderInner: FC {children} ); diff --git a/packages/threat-composer/src/contexts/ThreatsContext/context.ts b/packages/threat-composer/src/contexts/ThreatsContext/context.ts index 6abc0f20..3208c5d0 100644 --- a/packages/threat-composer/src/contexts/ThreatsContext/context.ts +++ b/packages/threat-composer/src/contexts/ThreatsContext/context.ts @@ -14,7 +14,7 @@ limitations under the License. ******************************************************************************************************************** */ import { useContext, createContext } from 'react'; -import { PerFieldExample, TemplateThreatStatement } from '../../customTypes'; +import { PerFieldExample, TemplateThreatStatement, ThreatStatementListFilter } from '../../customTypes'; import threatStatementExamplesData from '../../data/threatStatementExamples.json'; export type View = 'list' | 'editor'; @@ -52,6 +52,8 @@ export interface ThreatsContextApi { saveStatement: (statement: TemplateThreatStatement) => void; removeAllStatements: () => Promise; onDeleteWorkspace: (workspaceId: string) => Promise; + onThreatListView?: (filter?: ThreatStatementListFilter) => void; + onThreatEditorView?: (threatId: string, idToCopied?: string) => void; } const initialState: ThreatsContextApi = { diff --git a/packages/threat-composer/src/contexts/WorkspaceContextAggregator/index.tsx b/packages/threat-composer/src/contexts/WorkspaceContextAggregator/index.tsx index ce5fcda2..b82f671e 100644 --- a/packages/threat-composer/src/contexts/WorkspaceContextAggregator/index.tsx +++ b/packages/threat-composer/src/contexts/WorkspaceContextAggregator/index.tsx @@ -27,7 +27,6 @@ import MitigationPacksContextProvider from '../MitigationPacksContext'; import MitigationsContextProvider from '../MitigationsContext'; import ThreatPacksContextProvider from '../ThreatPacksContext'; import ThreatsContextProvider from '../ThreatsContext'; - export interface WorkspaceContextAggregatorProps extends ViewNavigationEvent { workspaceId: string | null; composerMode?: ComposerMode; @@ -40,10 +39,15 @@ export interface WorkspaceContextAggregatorProps extends ViewNavigationEvent { const WorkspaceContextInnerAggregator: FC> = ({ children, workspaceId, + onThreatEditorView, + onThreatListView, }) => { return ( + @@ -81,7 +85,11 @@ const WorkspaceContextAggregator: FC { return requiredGlobalSetupContext ? ( - + {children} diff --git a/packages/threat-composer/src/contexts/WorkspacesContext/components/LocalStateContextProvider/index.tsx b/packages/threat-composer/src/contexts/WorkspacesContext/components/LocalStateContextProvider/index.tsx index 6d7a92fa..02e5aaaf 100644 --- a/packages/threat-composer/src/contexts/WorkspacesContext/components/LocalStateContextProvider/index.tsx +++ b/packages/threat-composer/src/contexts/WorkspacesContext/components/LocalStateContextProvider/index.tsx @@ -13,44 +13,23 @@ See the License for the specific language governing permissions and limitations under the License. ******************************************************************************************************************** */ -import { FC, useState } from 'react'; +import { FC, useEffect, useState } from 'react'; import { DEFAULT_WORKSPACE_ID } from '../../../../configs/constants'; import { Workspace } from '../../../../customTypes'; -import { useWorkspaceExamplesContext } from '../../../WorkspaceExamplesContext'; import { WorkspacesContext } from '../../context'; import { WorkspacesContextProviderProps } from '../../types'; import useWorkspaces from '../../useWorkspaces'; const WorkspacesLocalStateContextProvider: FC = ({ children, - workspaceName, + workspaceId, onWorkspaceChanged, ...props }) => { - const { workspaceExamples } = useWorkspaceExamplesContext(); + const [currentWorkspace, setCurrentWorkspace] = useState(null); const [workspaceList, setWorkspaceList] = useState([]); - const [currentWorkspace, setCurrentWorkspace] = useState(() => { - if (workspaceName) { // If the workspaceName is specified by outside scope (e.g. Url), return the workspace specified by the id - if (workspaceName === DEFAULT_WORKSPACE_ID) { - return null; - } - - const foundWorkspace = workspaceList.find(x => x.name === workspaceName); - if (foundWorkspace) { - return foundWorkspace; - } - - const foundWorkspaceExample = workspaceExamples.find(x => x.name === workspaceName); - if (foundWorkspaceExample) { - return foundWorkspaceExample; - } - } - - return null; - }); - const { handleSwitchWorkspace, handleAddWorkspace, @@ -58,6 +37,21 @@ const WorkspacesLocalStateContextProvider: FC = handleRenameWorkspace, } = useWorkspaces(workspaceList, setWorkspaceList, currentWorkspace, setCurrentWorkspace, onWorkspaceChanged); + useEffect(() => { + if (workspaceId) { + if (workspaceId === DEFAULT_WORKSPACE_ID && currentWorkspace !== null) { + setCurrentWorkspace(null); + } else if (workspaceId !== currentWorkspace?.id) { + const foundWorkspace = workspaceList.find(x => x.id === workspaceId); + if (foundWorkspace) { + setCurrentWorkspace(foundWorkspace); + } else { + setCurrentWorkspace(null); + } + } + } + }, [workspaceId, workspaceList, currentWorkspace]); + return ( = ({ children, - workspaceName, + workspaceId, onWorkspaceChanged, ...props }) => { - const [workspaceList, setWorkspaceList] = useLocalStorageState(LOCAL_STORAGE_KEY_WORKSPACE_LIST, { - defaultValue: [], - }); - - const [lastWorkspace, setCurrentWorkspace] = useLocalStorageState(LOCAL_STORAGE_KEY_CURRENT_WORKSPACE, { + const [currentWorkspace, setCurrentWorkspace] = useLocalStorageState(LOCAL_STORAGE_KEY_CURRENT_WORKSPACE, { defaultValue: null, }); - const { workspaceExamples } = useWorkspaceExamplesContext(); - - const currentWorkspace = useMemo(() => { - if (workspaceName) { // If the workspaceName is specified by outside scope (e.g. Url), return the workspace specified by the id - if (workspaceName === DEFAULT_WORKSPACE_ID) { - return null; - } - - const foundWorkspace = workspaceList.find(x => x.name === workspaceName); - if (foundWorkspace) { - return foundWorkspace; - } - - const foundWorkspaceExample = workspaceExamples.find(x => x.name === workspaceName); - if (foundWorkspaceExample) { - return foundWorkspaceExample; - } - } - - return lastWorkspace; - }, [lastWorkspace, workspaceName, workspaceExamples, workspaceList]); + const [workspaceList, setWorkspaceList] = useLocalStorageState(LOCAL_STORAGE_KEY_WORKSPACE_LIST, { + defaultValue: [], + }); const { handleSwitchWorkspace, @@ -67,6 +44,21 @@ const WorkspacesLocalStorageContextProvider: FC handleRenameWorkspace, } = useWorkspaces(workspaceList, setWorkspaceList, currentWorkspace, setCurrentWorkspace, onWorkspaceChanged); + useEffect(() => { + if (workspaceId) { + if (workspaceId === DEFAULT_WORKSPACE_ID && currentWorkspace !== null) { + setCurrentWorkspace(null); + } else if (workspaceId !== currentWorkspace?.id) { + const foundWorkspace = workspaceList.find(x => x.id === workspaceId); + if (foundWorkspace) { + setCurrentWorkspace(foundWorkspace); + } else { + setCurrentWorkspace(null); + } + } + } + }, [workspaceId, workspaceList, currentWorkspace]); + return ( void; currentWorkspace: Workspace | null; diff --git a/packages/threat-composer/src/contexts/WorkspacesContext/index.tsx b/packages/threat-composer/src/contexts/WorkspacesContext/index.tsx index 8823f070..badd36a4 100644 --- a/packages/threat-composer/src/contexts/WorkspacesContext/index.tsx +++ b/packages/threat-composer/src/contexts/WorkspacesContext/index.tsx @@ -18,7 +18,7 @@ import WorkspacesLocalStateContextProvider from './components/LocalStateContextP import WorkspacesLocalStorageContextProvider from './components/LocalStorageContextProvider'; import { useWorkspacesContext } from './context'; import { WorkspacesContextProviderProps } from './types'; -import { APP_MODE_IDE_EXTENSION, DEFAULT_WORKSPACE_ID } from '../../configs'; +import { APP_MODE_IDE_EXTENSION } from '../../configs'; import { useGlobalSetupContext } from '../GlobalSetupContext'; const WorkspacesContextProvider: FC = (props) => { @@ -26,9 +26,9 @@ const WorkspacesContextProvider: FC = (props) => return appMode === APP_MODE_IDE_EXTENSION ? () : - (); + (); }; export default WorkspacesContextProvider; diff --git a/packages/threat-composer/src/contexts/WorkspacesContext/types.ts b/packages/threat-composer/src/contexts/WorkspacesContext/types.ts index 634754b0..e5596ecc 100644 --- a/packages/threat-composer/src/contexts/WorkspacesContext/types.ts +++ b/packages/threat-composer/src/contexts/WorkspacesContext/types.ts @@ -16,7 +16,7 @@ import { ReactElement } from 'react'; export interface WorkspacesContextProviderProps { - workspaceName?: string; // The name is used in url + workspaceId?: string; onWorkspaceChanged?: (workspaceId: string) => void; children: (workspace: string | null) => ReactElement<{ workspaceId: string | null }>; } diff --git a/packages/threat-composer/src/contexts/WorkspacesContext/useWorkspaces.ts b/packages/threat-composer/src/contexts/WorkspacesContext/useWorkspaces.ts index 049e3c05..50a8b0c3 100644 --- a/packages/threat-composer/src/contexts/WorkspacesContext/useWorkspaces.ts +++ b/packages/threat-composer/src/contexts/WorkspacesContext/useWorkspaces.ts @@ -26,7 +26,7 @@ const useWorkspaces = ( setWorkspaceList: React.Dispatch>, currentWorkspace: Workspace | null, setCurrentWorkspace: React.Dispatch>, - onWorkspaceChanged?: (workspaceName: string) => void, + onWorkspaceChanged?: (workspaceId: string) => void, ) => { const { workspaceExamples } = useWorkspaceExamplesContext(); @@ -49,7 +49,7 @@ const useWorkspaces = ( const handleSwitchWorkspace = useCallback((toBeSwitchedWorkspaceId: string | null) => { const workspace = getWorkspace(toBeSwitchedWorkspaceId); setCurrentWorkspace(workspace); - onWorkspaceChanged?.(workspace?.name || DEFAULT_WORKSPACE_ID); + onWorkspaceChanged?.(workspace?.id || DEFAULT_WORKSPACE_ID); }, [onWorkspaceChanged, getWorkspace]); const handleAddWorkspace = useCallback(async (workspaceName: string, @@ -63,7 +63,7 @@ const useWorkspaces = ( }; setWorkspaceList(prev => [...prev, newWorkspace]); setCurrentWorkspace(newWorkspace); - onWorkspaceChanged?.(newWorkspace.name); + onWorkspaceChanged?.(newWorkspace.id); return newWorkspace; }, [onWorkspaceChanged]); diff --git a/packages/threat-composer/src/contexts/index.ts b/packages/threat-composer/src/contexts/index.ts index 00d14683..c36dcadb 100644 --- a/packages/threat-composer/src/contexts/index.ts +++ b/packages/threat-composer/src/contexts/index.ts @@ -39,4 +39,3 @@ export { default as MitigationPacksContext } from './MitigationPacksContext'; export { useMitigationPacksContext } from './MitigationPacksContext/context'; export { default as WorkspaceContextAggregator } from './WorkspaceContextAggregator'; export { default as ContextAggregator } from './ContextAggregator'; -export { default as WorkspaceExamplesContext } from './WorkspaceExamplesContext'; diff --git a/packages/threat-composer/src/customTypes/components.ts b/packages/threat-composer/src/customTypes/components.ts index 23181f00..00b66cc6 100644 --- a/packages/threat-composer/src/customTypes/components.ts +++ b/packages/threat-composer/src/customTypes/components.ts @@ -13,10 +13,6 @@ See the License for the specific language governing permissions and limitations under the License. ******************************************************************************************************************** */ -import { ComponentType } from 'react'; -import { MarkdownEditorProps } from '../components/generic/MarkdownEditor'; - export interface EditableComponentBaseProps { onEditModeChange?: (editMode: boolean) => void; - MarkdownEditorComponentType?: ComponentType; } \ No newline at end of file diff --git a/packages/threat-composer/src/customTypes/events.ts b/packages/threat-composer/src/customTypes/events.ts index 55b1f821..da7fdba3 100644 --- a/packages/threat-composer/src/customTypes/events.ts +++ b/packages/threat-composer/src/customTypes/events.ts @@ -22,5 +22,5 @@ export interface ViewNavigationEvent { onAssumptionListView?: () => void; onMitigationListView?: () => void; onThreatListView?: (filter?: ThreatStatementListFilter) => void; - onThreatEditorView?: (threatId: string, idToCopy?: string) => void; + onThreatEditorView?: (threatId: string) => void; } \ No newline at end of file diff --git a/projenrc/app.ts b/projenrc/app.ts index 1ad75e0d..477590a8 100644 --- a/projenrc/app.ts +++ b/projenrc/app.ts @@ -15,7 +15,6 @@ class ThreatComposerReactAppProject extends ReactTypeScriptProject { "@cloudscape-design/global-styles", "@cloudscape-design/design-tokens", "@aws-northstar/ui", - "@uidotdev/usehooks", "react-router-dom", "uuid", "docx", diff --git a/yarn.lock b/yarn.lock index f8e8d6dc..1c0e62b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7796,11 +7796,6 @@ "@typescript-eslint/types" "6.21.0" eslint-visitor-keys "^3.4.1" -"@uidotdev/usehooks@^2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@uidotdev/usehooks/-/usehooks-2.4.1.tgz#4b733eaeae09a7be143c6c9ca158b56cc1ea75bf" - integrity sha512-1I+RwWyS+kdv3Mv0Vmc+p0dPYH0DTRAo04HLyXReYBL9AeseDWUJyi4THuksBJcu9F0Pih69Ak150VDnqbVnXg== - "@vitejs/plugin-react@^4.2.1": version "4.2.1" resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz#744d8e4fcb120fc3dbaa471dadd3483f5a304bb9"