Skip to content

feat: add template editor to the ui #5963

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Feb 7, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Hide timestamps in build logs
  • Loading branch information
kylecarbs committed Feb 1, 2023
commit 78e35d64adb230c1c6c43af3815a03b88d0f06bc
10 changes: 8 additions & 2 deletions site/src/AppRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,10 @@ const TemplateVersionPage = lazy(
() => import("./pages/TemplateVersionPage/TemplateVersionPage"),
)
const TemplateVersionEditorPage = lazy(
() => import("./pages/TemplateVersionPage/TemplateVersionEditorPage/TemplateVersionEditorPage"),
() =>
import(
"./pages/TemplateVersionPage/TemplateVersionEditorPage/TemplateVersionEditorPage"
),
)
const StarterTemplatesPage = lazy(
() => import("./pages/StarterTemplatesPage/StarterTemplatesPage"),
Expand Down Expand Up @@ -159,7 +162,10 @@ export const AppRouter: FC = () => {
<Route path="versions">
<Route path=":version">
<Route index element={<TemplateVersionPage />} />
<Route path="edit" element={<TemplateVersionEditorPage />} />
<Route
path="edit"
element={<TemplateVersionEditorPage />}
/>
</Route>
</Route>
</Route>
Expand Down
2 changes: 1 addition & 1 deletion site/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ export const cancelWorkspaceBuild = async (
}

export const cancelTemplateVersionBuild = async (
templateVersionId: TypesGen.TemplateVersion["id"]
templateVersionId: TypesGen.TemplateVersion["id"],
): Promise<Types.Message> => {
const response = await axios.patch(
`/api/v2/templateversions/${templateVersionId}/cancel`,
Expand Down
14 changes: 10 additions & 4 deletions site/src/components/Logs/Logs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ interface Line {

export interface LogsProps {
lines: Line[]
hideTimestamps?: boolean
className?: string
}

export const Logs: FC<React.PropsWithChildren<LogsProps>> = ({
hideTimestamps,
lines,
className = "",
}) => {
Expand All @@ -27,10 +29,14 @@ export const Logs: FC<React.PropsWithChildren<LogsProps>> = ({
<div className={styles.scrollWrapper}>
{lines.map((line, idx) => (
<div className={combineClasses([styles.line, line.level])} key={idx}>
<span className={styles.time}>
{dayjs(line.time).format(`HH:mm:ss.SSS`)}
</span>
<span className={styles.space}>&nbsp;&nbsp;&nbsp;&nbsp;</span>
{!hideTimestamps && (
<>
<span className={styles.time}>
{dayjs(line.time).format(`HH:mm:ss.SSS`)}
</span>
<span className={styles.space}>&nbsp;&nbsp;&nbsp;&nbsp;</span>
</>
)}
<span>{line.output}</span>
</div>
))}
Expand Down
11 changes: 11 additions & 0 deletions site/src/components/TemplateVersionEditor/FileTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ export const FileTree: FC<{
if (file.path.endsWith(".md")) {
icon = <FileTypeMarkdown />
}
if (file.path.endsWith("Dockerfile")) {
icon = <FileTypeDockerfile />
}

return (
<TreeItem
Expand Down Expand Up @@ -173,3 +176,11 @@ const FileTypeMarkdown = () => (
<polygon points="22.955 20.636 18.864 16.136 21.591 16.136 21.591 11.364 24.318 11.364 24.318 16.136 27.045 16.136 22.955 20.636" />
</svg>
)

const FileTypeDockerfile = () => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="#0db7ed">
<path d="M16,2A14,14,0,1,0,30,16,14,14,0,0,0,16,2Zm0,26A12,12,0,1,1,28,16,12,12,0,0,1,16,28Z" />
<path d="M16,6a10,10,0,0,0-9.9,9.1H6.1A8,8,0,0,1,16,8a8,8,0,0,1,8,8,8,8,0,0,1-8,8,8,8,0,0,1-7.9-6.1H6.1A10,10,0,0,0,16,26a10,10,0,0,0,0-20Z" />
<path d="M16,10a6,6,0,0,0-6,6,6,6,0,0,0,6,6,6,6,0,0,0,6-6A6,6,0,0,0,16,10Zm0,10a4,4,0,0,1-4-4,4,4,0,0,1,4-4,4,4,0,0,1,4,4A4,4,0,0,1,16,20Z" />
</svg>
)
37 changes: 29 additions & 8 deletions site/src/components/TemplateVersionEditor/MonacoEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { useTheme } from "@material-ui/core/styles"
import Editor from "@monaco-editor/react"
import { FC, useLayoutEffect, useState } from "react"
import { FC, useLayoutEffect, useMemo, useState } from "react"
import { MONOSPACE_FONT_FAMILY } from "theme/constants"
import { hslToHex } from "util/colors"
import type { editor } from "monaco-editor"

export const MonacoEditor: FC<{
value?: string
path?: string
language?: string
onChange?: (value: string) => void
}> = ({ onChange, value, language, path }) => {
}> = ({ onChange, value, path }) => {
const theme = useTheme()
const [editor, setEditor] = useState<editor.IStandaloneCodeEditor>()
useLayoutEffect(() => {
Expand All @@ -29,15 +28,33 @@ export const MonacoEditor: FC<{
}
}, [editor])

const language = useMemo(() => {
if (path?.endsWith(".tf")) {
return "hcl"
}
if (path?.endsWith(".md")) {
return "markdown"
}
if (path?.endsWith(".json")) {
return "json"
}
if (path?.endsWith(".yaml")) {
return "yaml"
}
if (path?.endsWith("Dockerfile")) {
return "dockerfile"
}
}, [path])

return (
<Editor
value={value}
language={language || "hcl"}
language={language}
theme="vs-dark"
options={{
automaticLayout: true,
fontFamily: MONOSPACE_FONT_FAMILY,
fontSize: 14,
fontSize: 16,
wordWrap: "on",
}}
path={path}
Expand All @@ -50,9 +67,13 @@ export const MonacoEditor: FC<{
// This jank allows for Ctrl + Enter to work outside the editor.
// We use this keybind to trigger a build.
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Private type in Monaco!
;(editor as any)._standaloneKeybindingService.addDynamicKeybinding(`-editor.action.insertLineAfter`, undefined, () => {
//
})
;(editor as any)._standaloneKeybindingService.addDynamicKeybinding(
`-editor.action.insertLineAfter`,
undefined,
() => {
//
},
)

setEditor(editor)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { Story } from "@storybook/react"
import { TemplateVersionEditor, TemplateVersionEditorProps } from "./TemplateVersionEditor"
import {
TemplateVersionEditor,
TemplateVersionEditorProps,
} from "./TemplateVersionEditor"

export default {
title: "components/TemplateEditor",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,21 +181,32 @@ export const TemplateVersionEditor: FC<TemplateVersionEditorProps> = ({
onChange={(_, value) => {
setSelectedTab(value)
}}
className={styles.tabs}
>
<Tab label="Build Logs" />
<Tab disabled={disableUpdate} label="Resources" />
</Tabs>

<div className={`${styles.panel} ${styles.buildLogs} ${selectedTab === 0 ? "" : "hidden"}`}>
{buildLogs && <WorkspaceBuildLogs logs={buildLogs} />}
<div
className={`${styles.panel} ${styles.buildLogs} ${
selectedTab === 0 ? "" : "hidden"
}`}
>
{buildLogs && (
<WorkspaceBuildLogs hideTimestamps logs={buildLogs} />
)}
{templateVersion.job.error && (
<div className={styles.buildLogError}>
{templateVersion.job.error}
</div>
)}
</div>

<div className={`${styles.panel} ${styles.resources} ${selectedTab === 1 ? "" : "hidden"}`}>
<div
className={`${styles.panel} ${styles.resources} ${
selectedTab === 1 ? "" : "hidden"
}`}
>
{resources && (
<TemplateResourcesTable
resources={resources.filter(
Expand Down Expand Up @@ -278,6 +289,9 @@ const useStyles = makeStyles<
display: "none",
},
},
tabs: {
borderBottom: `1px solid ${theme.palette.divider}`,
},
tabBar: {
padding: "8px 16px",
position: "sticky",
Expand Down
8 changes: 6 additions & 2 deletions site/src/components/WorkspaceBuildLogs/WorkspaceBuildLogs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,13 @@ const getStageDurationInSeconds = (logs: ProvisionerJobLog[]) => {

export interface WorkspaceBuildLogsProps {
logs: ProvisionerJobLog[]
hideTimestamps?: boolean
}

export const WorkspaceBuildLogs: FC<WorkspaceBuildLogsProps> = ({ logs }) => {
export const WorkspaceBuildLogs: FC<WorkspaceBuildLogsProps> = ({
hideTimestamps,
logs,
}) => {
const groupedLogsByStage = groupLogsByStage(logs)
const stages = Object.keys(groupedLogsByStage)
const styles = useStyles()
Expand Down Expand Up @@ -69,7 +73,7 @@ export const WorkspaceBuildLogs: FC<WorkspaceBuildLogsProps> = ({ logs }) => {
</div>
)}
</div>
{!isEmpty && <Logs lines={lines} />}
{!isEmpty && <Logs hideTimestamps={hideTimestamps} lines={lines} />}
</Fragment>
)
})}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { useMachine } from "@xstate/react"
import { TemplateEditor } from "components/TemplateVersionEditor/TemplateEditor"
import { TemplateVersionEditor } from "components/TemplateVersionEditor/TemplateVersionEditor"
import { useOrganizationId } from "hooks/useOrganizationId"
import { FC } from "react"
import { Helmet } from "react-helmet-async"
import { useTranslation } from "react-i18next"
import { useParams } from "react-router-dom"
import { pageTitle } from "util/page"
import { templateVersionMachine } from "xServices/templateVersion/templateVersionXService"
Expand All @@ -24,14 +22,11 @@ export const TemplateVersionEditorPage: FC = () => {
const [editorState, sendEvent] = useMachine(templateVersionEditorMachine, {
context: { orgId },
})
const { t } = useTranslation("templateVersionPage")

return (
<>
<Helmet>
<title>
{pageTitle(`${t("title")} ${versionName} · ${templateName}`)}
</title>
<title>{pageTitle(`${templateName} · Template Editor`)}</title>
</Helmet>

{versionState.context.template &&
Expand Down
8 changes: 4 additions & 4 deletions site/src/xServices/templateVersion/templateVersionXService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ export const templateVersionMachine = createMachine(
loadTemplate: {
data: {
template: Template
},
},
}
}
loadFiles: {
data: {
currentFiles: TemplateVersionFiles
Expand All @@ -66,7 +66,7 @@ export const templateVersionMachine = createMachine(
{
actions: "assignVersions",
target: "success",
}
},
],
},
},
Expand All @@ -85,7 +85,7 @@ export const templateVersionMachine = createMachine(
{
actions: "assignTemplate",
target: "success",
}
},
],
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ export const templateVersionEditorMachine = createMachine(
schema: {
context: {} as TemplateVersionEditorMachineContext,
events: {} as
| { type: "CREATE_BUILD"; files: TemplateVersionFiles, templateId: string }
| {
type: "CREATE_BUILD"
files: TemplateVersionFiles
templateId: string
}
| { type: "CANCEL_BUILD" }
| { type: "ADD_BUILD_LOG"; log: ProvisionerJobLog }
| { type: "UPDATE_ACTIVE" },
Expand Down