From a629b28194c2e2e2ddcdd962482da98cbbda2607 Mon Sep 17 00:00:00 2001 From: Mike Sawka Date: Mon, 14 Oct 2024 14:57:12 -0700 Subject: [PATCH] implement a config error button + message modal that shows the errors (#1030) --- frontend/app/modals/messagemodal.less | 6 +++ frontend/app/modals/messagemodal.tsx | 24 +++++++++ frontend/app/modals/modalregistry.tsx | 2 + frontend/app/tab/tabbar.less | 17 +++++++ frontend/app/tab/tabbar.tsx | 71 ++++++++++++++++++++++++++- frontend/app/tab/updatebanner.tsx | 3 +- pkg/util/utilfn/utilfn.go | 14 ++++++ pkg/wconfig/settingsconfig.go | 51 ++++++++++++++++++- 8 files changed, 183 insertions(+), 5 deletions(-) create mode 100644 frontend/app/modals/messagemodal.less create mode 100644 frontend/app/modals/messagemodal.tsx diff --git a/frontend/app/modals/messagemodal.less b/frontend/app/modals/messagemodal.less new file mode 100644 index 000000000..41113f25b --- /dev/null +++ b/frontend/app/modals/messagemodal.less @@ -0,0 +1,6 @@ +// Copyright 2024, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +.message-modal { + min-width: 400px; +} diff --git a/frontend/app/modals/messagemodal.tsx b/frontend/app/modals/messagemodal.tsx new file mode 100644 index 000000000..c781d19a7 --- /dev/null +++ b/frontend/app/modals/messagemodal.tsx @@ -0,0 +1,24 @@ +// Copyright 2024, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { Modal } from "@/app/modals/modal"; +import { modalsModel } from "@/app/store/modalmodel"; + +import { ReactNode } from "react"; +import "./messagemodal.less"; + +const MessageModal = ({ children }: { children: ReactNode }) => { + function closeModal() { + modalsModel.popModal(); + } + + return ( + closeModal()} onClose={() => closeModal()}> + {children} + + ); +}; + +MessageModal.displayName = "MessageModal"; + +export { MessageModal }; diff --git a/frontend/app/modals/modalregistry.tsx b/frontend/app/modals/modalregistry.tsx index f77d790f2..c07f762c1 100644 --- a/frontend/app/modals/modalregistry.tsx +++ b/frontend/app/modals/modalregistry.tsx @@ -1,6 +1,7 @@ // Copyright 2024, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 +import { MessageModal } from "@/app/modals/messagemodal"; import { AboutModal } from "./about"; import { TosModal } from "./tos"; import { UserInputModal } from "./userinputmodal"; @@ -9,6 +10,7 @@ const modalRegistry: { [key: string]: React.ComponentType } = { [TosModal.displayName || "TosModal"]: TosModal, [UserInputModal.displayName || "UserInputModal"]: UserInputModal, [AboutModal.displayName || "AboutModal"]: AboutModal, + [MessageModal.displayName || "MessageModal"]: MessageModal, }; export const getModalComponent = (key: string): React.ComponentType | undefined => { diff --git a/frontend/app/tab/tabbar.less b/frontend/app/tab/tabbar.less index 01d674ce1..dd0f0a3e6 100644 --- a/frontend/app/tab/tabbar.less +++ b/frontend/app/tab/tabbar.less @@ -12,6 +12,16 @@ } } +.config-error-message { + max-width: 500px; + + h3 { + margin-bottom: 10px; + } + + margin-bottom: 20px; +} + .tab-bar-wrapper { position: relative; user-select: none; @@ -53,6 +63,13 @@ color: var(--accent-color); } + .config-error-button { + height: 80%; + margin: auto 4px; + color: black; + flex: 0 0 fit-content; + } + .add-tab-btn { width: 22px; height: 100%; diff --git a/frontend/app/tab/tabbar.tsx b/frontend/app/tab/tabbar.tsx index f5111f2dc..eb5b7d863 100644 --- a/frontend/app/tab/tabbar.tsx +++ b/frontend/app/tab/tabbar.tsx @@ -1,6 +1,8 @@ // Copyright 2024, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 +import { Button } from "@/app/element/button"; +import { modalsModel } from "@/app/store/modalmodel"; import { WindowDrag } from "@/element/windowdrag"; import { deleteLayoutModelForTab } from "@/layout/index"; import { atoms, getApi, isDev, PLATFORM } from "@/store/global"; @@ -37,6 +39,69 @@ interface TabBarProps { workspace: Workspace; } +const ConfigErrorMessage = () => { + const fullConfig = useAtomValue(atoms.fullConfigAtom); + + if (fullConfig?.configerrors == null || fullConfig?.configerrors.length == 0) { + return ( +
+

Configuration Clean

+

There are no longer any errors detected in your config.

+
+ ); + } + if (fullConfig?.configerrors.length == 1) { + const singleError = fullConfig.configerrors[0]; + return ( +
+

Configuration Error

+
+ {singleError.file}: {singleError.err} +
+
+ ); + } + return ( +
+

Configuration Error

+
    + {fullConfig.configerrors.map((error, index) => ( +
  • + {error.file}: {error.err} +
  • + ))} +
+
+ ); +}; + +const ConfigErrorIcon = ({ buttonRef }: { buttonRef: React.RefObject }) => { + const fullConfig = useAtomValue(atoms.fullConfigAtom); + + function handleClick() { + modalsModel.pushModal("MessageModal", { children: }); + } + + if (fullConfig?.configerrors == null || fullConfig?.configerrors.length == 0) { + return null; + } + return ( + + ); + return ( +
}> + +
+ ); +}; + const TabBar = React.memo(({ workspace }: TabBarProps) => { const [tabIds, setTabIds] = useState([]); const [dragStartPositions, setDragStartPositions] = useState([]); @@ -67,6 +132,7 @@ const TabBar = React.memo(({ workspace }: TabBarProps) => { const tabWidthRef = useRef(TAB_DEFAULT_WIDTH); const scrollableRef = useRef(false); const updateStatusButtonRef = useRef(null); + const configErrorButtonRef = useRef(null); const prevAllLoadedRef = useRef(false); const windowData = useAtomValue(atoms.waveWindow); @@ -124,8 +190,10 @@ const TabBar = React.memo(({ workspace }: TabBarProps) => { const windowDragLeftWidth = draggerLeftRef.current.getBoundingClientRect().width; const addBtnWidth = addBtnRef.current.getBoundingClientRect().width; const updateStatusLabelWidth = updateStatusButtonRef.current?.getBoundingClientRect().width ?? 0; + const configErrorWidth = configErrorButtonRef.current?.getBoundingClientRect().width ?? 0; const spaceForTabs = - tabbarWrapperWidth - (windowDragLeftWidth + DRAGGER_RIGHT_MIN_WIDTH + addBtnWidth + updateStatusLabelWidth); + tabbarWrapperWidth - + (windowDragLeftWidth + DRAGGER_RIGHT_MIN_WIDTH + addBtnWidth + updateStatusLabelWidth + configErrorWidth); const numberOfTabs = tabIds.length; const totalDefaultTabWidth = numberOfTabs * TAB_DEFAULT_WIDTH; @@ -510,6 +578,7 @@ const TabBar = React.memo(({ workspace }: TabBarProps) => { + ); }); diff --git a/frontend/app/tab/updatebanner.tsx b/frontend/app/tab/updatebanner.tsx index 189871fd4..94b780b19 100644 --- a/frontend/app/tab/updatebanner.tsx +++ b/frontend/app/tab/updatebanner.tsx @@ -6,7 +6,7 @@ import "./updatebanner.less"; const UpdateStatusBannerComponent = ({ buttonRef }: { buttonRef: React.RefObject }) => { const appUpdateStatus = useAtomValue(atoms.updaterStatusAtom); - const [updateStatusMessage, setUpdateStatusMessage] = useState(); + let [updateStatusMessage, setUpdateStatusMessage] = useState(); const [dismissBannerTimeout, setDismissBannerTimeout] = useState(); useEffect(() => { @@ -52,7 +52,6 @@ const UpdateStatusBannerComponent = ({ buttonRef }: { buttonRef: React.RefObject function onClick() { getApi().installAppUpdate(); } - if (updateStatusMessage) { return (