From e9c12c30cf6e1272a344572987149bdeb713c8f1 Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Tue, 28 Nov 2023 16:42:31 -0300 Subject: [PATCH] feat(site): refactor template version editor layout (#10912) --- site/src/AppRouter.tsx | 10 +- .../components/WorkspaceBuildLogs/Logs.tsx | 8 +- .../WorkspaceBuildLogs/WorkspaceBuildLogs.tsx | 5 +- .../TemplateSettingsForm.tsx | 1 - .../FileTreeView.tsx | 3 +- .../MonacoEditor.tsx | 25 +- .../PublishTemplateVersionDialog.tsx | 73 +-- .../TemplateVersionEditor.tsx | 482 +++++++++++------- .../TemplateVersionEditorPage.test.tsx | 14 +- .../TemplateVersionEditorPage.tsx | 20 +- 10 files changed, 389 insertions(+), 252 deletions(-) diff --git a/site/src/AppRouter.tsx b/site/src/AppRouter.tsx index ab61681679..8fa55bd9ef 100644 --- a/site/src/AppRouter.tsx +++ b/site/src/AppRouter.tsx @@ -259,10 +259,6 @@ export const AppRouter: FC = () => { } /> - } - /> @@ -346,13 +342,17 @@ export const AppRouter: FC = () => { - {/* Terminal and CLI auth pages don't have the dashboard layout */} + {/* Pages that don't have the dashboard layout */} } /> } /> } /> + } + /> {/* Using path="*"" means "match anything", so this route diff --git a/site/src/components/WorkspaceBuildLogs/Logs.tsx b/site/src/components/WorkspaceBuildLogs/Logs.tsx index e95999806b..585adf0f97 100644 --- a/site/src/components/WorkspaceBuildLogs/Logs.tsx +++ b/site/src/components/WorkspaceBuildLogs/Logs.tsx @@ -24,10 +24,14 @@ export const Logs: FC> = ({ className = "", }) => { return ( -
+
{lines.map((line, idx) => ( -
+
{!hideTimestamps && ( <> diff --git a/site/src/components/WorkspaceBuildLogs/WorkspaceBuildLogs.tsx b/site/src/components/WorkspaceBuildLogs/WorkspaceBuildLogs.tsx index a0fdba3f9b..c41ad89417 100644 --- a/site/src/components/WorkspaceBuildLogs/WorkspaceBuildLogs.tsx +++ b/site/src/components/WorkspaceBuildLogs/WorkspaceBuildLogs.tsx @@ -77,7 +77,10 @@ export const WorkspaceBuildLogs: FC = ({ return ( -
+
{stage}
{shouldDisplayDuration && (
diff --git a/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsForm.tsx b/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsForm.tsx index 2a6dd37a66..6e5878eba5 100644 --- a/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsForm.tsx +++ b/site/src/pages/TemplateSettingsPage/TemplateGeneralSettingsPage/TemplateSettingsForm.tsx @@ -233,7 +233,6 @@ export const TemplateSettingsForm: FC = ({ diff --git a/site/src/pages/TemplateVersionEditorPage/FileTreeView.tsx b/site/src/pages/TemplateVersionEditorPage/FileTreeView.tsx index eba1649f1d..1922eb9cdb 100644 --- a/site/src/pages/TemplateVersionEditorPage/FileTreeView.tsx +++ b/site/src/pages/TemplateVersionEditorPage/FileTreeView.tsx @@ -62,6 +62,7 @@ export const FileTreeView: FC<{ css={(theme) => css` overflow: hidden; user-select: none; + height: 32px; &:focus:not(.active) > .MuiTreeItem-content { background: ${theme.palette.action.hover}; @@ -92,7 +93,7 @@ export const FileTreeView: FC<{ &.active { & > .MuiTreeItem-content { color: ${theme.palette.text.primary}; - background: ${colors.gray[13]}; + background: ${colors.gray[14]}; pointer-events: none; } } diff --git a/site/src/pages/TemplateVersionEditorPage/MonacoEditor.tsx b/site/src/pages/TemplateVersionEditorPage/MonacoEditor.tsx index cff5950f40..7b3ed9ab29 100644 --- a/site/src/pages/TemplateVersionEditorPage/MonacoEditor.tsx +++ b/site/src/pages/TemplateVersionEditorPage/MonacoEditor.tsx @@ -1,9 +1,8 @@ import { useTheme } from "@emotion/react"; import Editor, { loader } from "@monaco-editor/react"; import * as monaco from "monaco-editor"; -import { FC, useLayoutEffect, useMemo, useState } from "react"; +import { FC, useMemo } from "react"; import { MONOSPACE_FONT_FAMILY } from "theme/constants"; -import type { editor } from "monaco-editor"; loader.config({ monaco }); @@ -13,22 +12,6 @@ export const MonacoEditor: FC<{ onChange?: (value: string) => void; }> = ({ onChange, value, path }) => { const theme = useTheme(); - const [editor, setEditor] = useState(); - useLayoutEffect(() => { - if (!editor) { - return; - } - const resizeListener = () => { - editor.layout({ - height: 0, - width: 0, - }); - }; - window.addEventListener("resize", resizeListener); - return () => { - window.removeEventListener("resize", resizeListener); - }; - }, [editor]); const language = useMemo(() => { if (path?.endsWith(".tf")) { @@ -56,7 +39,7 @@ export const MonacoEditor: FC<{ options={{ automaticLayout: true, fontFamily: MONOSPACE_FONT_FAMILY, - fontSize: 16, + fontSize: 14, wordWrap: "on", padding: { top: 16, @@ -81,8 +64,6 @@ export const MonacoEditor: FC<{ }, ); - setEditor(editor); - document.fonts.ready .then(() => { // Ensures that all text is measured properly. @@ -124,7 +105,7 @@ export const MonacoEditor: FC<{ ], colors: { "editor.foreground": theme.palette.text.primary, - "editor.background": theme.palette.background.default, + "editor.background": theme.palette.background.paper, }, }); editor.updateOptions({ diff --git a/site/src/pages/TemplateVersionEditorPage/PublishTemplateVersionDialog.tsx b/site/src/pages/TemplateVersionEditorPage/PublishTemplateVersionDialog.tsx index 66013982f5..d572bcdef2 100644 --- a/site/src/pages/TemplateVersionEditorPage/PublishTemplateVersionDialog.tsx +++ b/site/src/pages/TemplateVersionEditorPage/PublishTemplateVersionDialog.tsx @@ -68,44 +68,45 @@ export const PublishTemplateVersionDialog: FC< confirmText="Publish" title="Publish new version" description={ - -

You are about to publish a new version of this template.

- - +
+ +

You are about to publish a new version of this template.

+ + - + - { - await form.setFieldValue( - "isActiveVersion", - e.target.checked, - ); - }} - name="isActiveVersion" - /> - } - /> - -
+ { + await form.setFieldValue( + "isActiveVersion", + e.target.checked, + ); + }} + name="isActiveVersion" + /> + } + /> + + + } /> ); diff --git a/site/src/pages/TemplateVersionEditorPage/TemplateVersionEditor.tsx b/site/src/pages/TemplateVersionEditorPage/TemplateVersionEditor.tsx index b07578fe63..2703ae7eb0 100644 --- a/site/src/pages/TemplateVersionEditorPage/TemplateVersionEditor.tsx +++ b/site/src/pages/TemplateVersionEditorPage/TemplateVersionEditor.tsx @@ -1,10 +1,7 @@ -import Button from "@mui/material/Button"; +import Button, { ButtonProps } from "@mui/material/Button"; import IconButton from "@mui/material/IconButton"; -import Link from "@mui/material/Link"; import Tooltip from "@mui/material/Tooltip"; import CreateIcon from "@mui/icons-material/AddOutlined"; -import BuildIcon from "@mui/icons-material/BuildOutlined"; -import PreviewIcon from "@mui/icons-material/VisibilityOutlined"; import { ProvisionerJobLog, Template, @@ -16,11 +13,11 @@ import { import { Link as RouterLink } from "react-router-dom"; import { Alert, AlertDetail } from "components/Alert/Alert"; import { Avatar } from "components/Avatar/Avatar"; -import { AvatarData } from "components/AvatarData/AvatarData"; import { TemplateResourcesTable } from "components/TemplateResourcesTable/TemplateResourcesTable"; import { WorkspaceBuildLogs } from "components/WorkspaceBuildLogs/WorkspaceBuildLogs"; import { PublishVersionData } from "pages/TemplateVersionEditorPage/types"; import { type FC, useCallback, useEffect, useRef, useState } from "react"; +import PlayArrowOutlined from "@mui/icons-material/PlayArrowOutlined"; import { createFile, existsFile, @@ -41,13 +38,13 @@ import { FileTreeView } from "./FileTreeView"; import { MissingTemplateVariablesDialog } from "./MissingTemplateVariablesDialog"; import { MonacoEditor } from "./MonacoEditor"; import { PublishTemplateVersionDialog } from "./PublishTemplateVersionDialog"; -import { - getStatus, - TemplateVersionStatusBadge, -} from "./TemplateVersionStatusBadge"; +import { TemplateVersionStatusBadge } from "./TemplateVersionStatusBadge"; import AlertTitle from "@mui/material/AlertTitle"; -import { DashboardFullPage } from "components/Dashboard/DashboardLayout"; import { type Interpolation, type Theme, useTheme } from "@emotion/react"; +import ArrowBackOutlined from "@mui/icons-material/ArrowBackOutlined"; +import CloseOutlined from "@mui/icons-material/CloseOutlined"; +import { MONOSPACE_FONT_FAMILY } from "theme/constants"; +import { Loader } from "components/Loader/Loader"; type Tab = "logs" | "resources" | undefined; // Undefined is to hide the tab export interface TemplateVersionEditorProps { @@ -74,8 +71,6 @@ export interface TemplateVersionEditorProps { defaultTab?: Tab; } -const topbarHeight = 80; - const findInitialFile = (fileTree: FileTree): string | undefined => { let initialFile: string | undefined; @@ -162,90 +157,196 @@ export const TemplateVersionEditor: FC = ({ ["running", "pending"].includes(previousVersion.current.job.status) && templateVersion.job.status === "succeeded" ) { - setSelectedTab("resources"); setDirty(false); } previousVersion.current = templateVersion; }, [templateVersion]); - const hasIcon = template.icon && template.icon !== ""; - const showBuildLogs = Boolean(buildLogs); const editorValue = getFileContent(activePath ?? "", fileTree) as string; + // Auto scroll + const buildLogsRef = useRef(null); useEffect(() => { - window.dispatchEvent(new Event("resize")); - }, [showBuildLogs]); + if (buildLogsRef.current) { + buildLogsRef.current.scrollTop = buildLogsRef.current.scrollHeight; + } + }, [buildLogs]); return ( <> - -
-
- - - ) - } - /> - +
+
+
+ + + + +
- {publishedVersion && ( - - Create a workspace - - } - > - Successfully published {publishedVersion.name}! - - )} +
+ + + "&:hover": { + textDecoration: "underline", + }, + }} + > + {template.display_name || template.name} + + / + + {templateVersion.name} + +
+ +
{buildLogs && ( )} - + Build + - + Publish +
-
-
-
- Template files -
+
+ {publishedVersion && ( +
+ + Create a workspace + + } + > + Successfully published {publishedVersion.name}! + +
+ )} + +
+
+ + Files + + +
= ({ event.currentTarget.blur(); }} > - +
@@ -326,14 +427,14 @@ export const TemplateVersionEditor: FC = ({
-
+
{activePath ? ( = ({ )}
-
-
- - - {!disableUpdate && ( + + +
+ + {selectedTab && ( + { + setSelectedTab(undefined); + }} + css={{ + marginLeft: "auto", + width: 36, + height: 36, + borderRadius: 0, + }} + > + + )}
{templateVersion.job.error && (
@@ -412,9 +552,39 @@ export const TemplateVersionEditor: FC = ({
)} + {buildLogs && buildLogs.length === 0 && ( + + )} + {buildLogs && buildLogs.length > 0 && ( @@ -422,13 +592,25 @@ export const TemplateVersionEditor: FC = ({
{resources && ( = ({
- +
= ({ ); }; +const TopbarButton = (props: ButtonProps) => { + return ( +