From 8b65df39d43337e54422d0159ce51323425fc608 Mon Sep 17 00:00:00 2001 From: Adam Gastineau Date: Thu, 6 Feb 2025 06:01:09 -0800 Subject: [PATCH] fix(ui-mode): display no projects error if bad config provided --- .../src/ui/shared/fullscreenModal.tsx | 38 ++++++++++++++++++ .../src/ui/shared/fullscreenModel.css | 29 ++++++++++++++ packages/trace-viewer/src/ui/uiModeView.tsx | 40 ++++++++++++++++--- 3 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 packages/trace-viewer/src/ui/shared/fullscreenModal.tsx create mode 100644 packages/trace-viewer/src/ui/shared/fullscreenModel.css diff --git a/packages/trace-viewer/src/ui/shared/fullscreenModal.tsx b/packages/trace-viewer/src/ui/shared/fullscreenModal.tsx new file mode 100644 index 0000000000..f811f276ff --- /dev/null +++ b/packages/trace-viewer/src/ui/shared/fullscreenModal.tsx @@ -0,0 +1,38 @@ +/* + Copyright (c) Microsoft Corporation. + + 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 * as React from 'react'; +import './fullscreenModel.css'; + +export interface FullscreenModalProps { + onClose?: () => void; +} + +export const FullscreenModal: React.FC< + React.PropsWithChildren +> = ({ onClose, children }) => { + const ref = React.useRef(null); + + React.useEffect(() => { + ref.current?.showModal(); + }, []); + + return ( + +
{children}
+
+ ); +}; diff --git a/packages/trace-viewer/src/ui/shared/fullscreenModel.css b/packages/trace-viewer/src/ui/shared/fullscreenModel.css new file mode 100644 index 0000000000..44261c0b09 --- /dev/null +++ b/packages/trace-viewer/src/ui/shared/fullscreenModel.css @@ -0,0 +1,29 @@ +/* + Copyright (c) Microsoft Corporation. + + 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. +*/ + +.fullscreen-modal { + padding: 8px; + + outline: none; +} + +.fullscreen-modal-content { + margin: 8px; +} + +.fullscreen-modal::backdrop { + background-color: rgba(0, 0, 0, 0.8); +} \ No newline at end of file diff --git a/packages/trace-viewer/src/ui/uiModeView.tsx b/packages/trace-viewer/src/ui/uiModeView.tsx index 4375018765..cdfe24d734 100644 --- a/packages/trace-viewer/src/ui/uiModeView.tsx +++ b/packages/trace-viewer/src/ui/uiModeView.tsx @@ -37,6 +37,7 @@ import { TestListView } from './uiModeTestListView'; import { TraceView } from './uiModeTraceView'; import { SettingsView } from './settingsView'; import { DefaultSettingsView } from './defaultSettingsView'; +import { FullscreenModal } from './shared/fullscreenModal'; let xtermSize = { cols: 80, rows: 24 }; const xtermDataSource: XtermDataSource = { @@ -98,6 +99,7 @@ export const UIModeView: React.FC<{}> = ({ const [settingsVisible, setSettingsVisible] = React.useState(false); const [testingOptionsVisible, setTestingOptionsVisible] = React.useState(false); const [revealSource, setRevealSource] = React.useState(false); + const [critcalError, setCriticalError] = React.useState(); const onRevealSource = React.useCallback(() => setRevealSource(true), [setRevealSource]); const showTestingOptions = false; @@ -114,6 +116,19 @@ export const UIModeView: React.FC<{}> = ({ }); }, []); + const configProjects = React.useMemo(() => { + if (!testModel) + return; + + const { config } = testModel; + return config.configFile + ? settings.getObject( + config.configFile + ':projects', + undefined, + ) + : undefined; + }, [testModel]); + // Load tests on startup. React.useEffect(() => { inputRef.current?.focus(); @@ -214,8 +229,7 @@ export const UIModeView: React.FC<{}> = ({ if (!testModel) return; - const { config, rootSuite } = testModel; - const selectedProjects = config.configFile ? settings.getObject(config.configFile + ':projects', undefined) : undefined; + const { rootSuite } = testModel; const newFilter = new Map(projectFilters); for (const projectName of newFilter.keys()) { if (!rootSuite.suites.find(s => s.title === projectName)) @@ -223,13 +237,13 @@ export const UIModeView: React.FC<{}> = ({ } for (const projectSuite of rootSuite.suites) { if (!newFilter.has(projectSuite.title)) - newFilter.set(projectSuite.title, !!selectedProjects?.includes(projectSuite.title)); + newFilter.set(projectSuite.title, !!configProjects?.includes(projectSuite.title)); } - if (!selectedProjects && newFilter.size && ![...newFilter.values()].includes(true)) + if (!configProjects && newFilter.size && ![...newFilter.values()].includes(true)) newFilter.set(newFilter.entries().next().value![0], true); if (projectFilters.size !== newFilter.size || [...projectFilters].some(([k, v]) => newFilter.get(k) !== v)) setProjectFilters(newFilter); - }, [projectFilters, testModel]); + }, [projectFilters, configProjects, testModel]); // Update progress. React.useEffect(() => { @@ -239,6 +253,21 @@ export const UIModeView: React.FC<{}> = ({ setProgress(undefined); }, [testModel, isRunningTest]); + React.useEffect(() => { + if (!testModel) + return; + + if (testModel.rootSuite.suites.length === 0) { + let prefix: string; + if (!configProjects || configProjects.length < 1) + prefix = 'No projects matched.'; + else + prefix = `No projects matched. Available projects: ${configProjects.map(p => `"${p}"`).join(', ')}.`; + + setCriticalError(`${prefix} Please check your configuration.`); + } + }, [testModel, configProjects]); + // Test tree is built from the model and filters. const { testTree } = React.useMemo(() => { if (!testModel) @@ -398,6 +427,7 @@ export const UIModeView: React.FC<{}> = ({ }, [closeInstallDialog, testServerConnection]); return
+ {critcalError && {critcalError}} {!hasBrowsers &&
Install browsers