From 0764df39829fa6d12c6ec583d43ead8174b462cd Mon Sep 17 00:00:00 2001 From: Bruno Date: Wed, 25 May 2022 16:54:22 +0000 Subject: [PATCH 01/10] Add basic template page --- site/package.json | 1 + site/src/AppRouter.tsx | 10 + site/src/api/api.ts | 5 + site/src/components/Resources/Resources.tsx | 11 +- .../TemplateResourcesTable.tsx | 109 ++++ .../TemplateStats/TemplateStats.tsx | 87 ++++ site/src/hooks/useOrganizationID.ts | 15 + .../CreateWorkspacePage.tsx | 20 +- site/src/pages/TemplatePage/TemplatePage.tsx | 138 +++++ .../pages/TemplatesPage/TemplatesPageView.tsx | 6 +- .../xServices/template/templateXService.ts | 110 ++++ site/yarn.lock | 492 +++++++++++++++++- 12 files changed, 981 insertions(+), 23 deletions(-) create mode 100644 site/src/components/TemplateResourcesTable/TemplateResourcesTable.tsx create mode 100644 site/src/components/TemplateStats/TemplateStats.tsx create mode 100644 site/src/hooks/useOrganizationID.ts create mode 100644 site/src/pages/TemplatePage/TemplatePage.tsx create mode 100644 site/src/xServices/template/templateXService.ts diff --git a/site/package.json b/site/package.json index 7f3b818262d42..5b45531c2cbcd 100644 --- a/site/package.json +++ b/site/package.json @@ -41,6 +41,7 @@ "history": "5.3.0", "react": "17.0.2", "react-dom": "17.0.2", + "react-markdown": "^8.0.3", "react-router-dom": "6.3.0", "sourcemapped-stacktrace": "1.1.11", "swr": "1.2.2", diff --git a/site/src/AppRouter.tsx b/site/src/AppRouter.tsx index 4ec0f463cae26..afb639358b128 100644 --- a/site/src/AppRouter.tsx +++ b/site/src/AppRouter.tsx @@ -12,6 +12,7 @@ import { OrgsPage } from "./pages/OrgsPage/OrgsPage" import { SettingsPage } from "./pages/SettingsPage/SettingsPage" import { AccountPage } from "./pages/SettingsPages/AccountPage/AccountPage" import { SSHKeysPage } from "./pages/SettingsPages/SSHKeysPage/SSHKeysPage" +import { TemplatePage } from "./pages/TemplatePage/TemplatePage" import TemplatesPage from "./pages/TemplatesPage/TemplatesPage" import { CreateUserPage } from "./pages/UsersPage/CreateUserPage/CreateUserPage" import { UsersPage } from "./pages/UsersPage/UsersPage" @@ -95,6 +96,15 @@ export const AppRouter: React.FC = () => ( } /> + + + + + } + /> diff --git a/site/src/api/api.ts b/site/src/api/api.ts index 8b763bb644595..6d9fd6099faf6 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -101,6 +101,11 @@ export const getTemplateVersionSchema = async (versionId: string): Promise => { + const response = await axios.get(`/api/v2/templateversions/${versionId}/resources`) + return response.data +} + export const getWorkspace = async (workspaceId: string): Promise => { const response = await axios.get(`/api/v2/workspaces/${workspaceId}`) return response.data diff --git a/site/src/components/Resources/Resources.tsx b/site/src/components/Resources/Resources.tsx index feb752e2e4113..1a4c6aa24e74d 100644 --- a/site/src/components/Resources/Resources.tsx +++ b/site/src/components/Resources/Resources.tsx @@ -79,7 +79,8 @@ export const Resources: React.FC = ({ resources, getResourcesErr )} - {agent.name} + {agent.name} + {agent.operating_system} @@ -143,4 +144,12 @@ const useStyles = makeStyles((theme) => ({ marginRight: theme.spacing(1.5), }, }, + + operatingSystem: { + fontSize: 14, + color: theme.palette.text.secondary, + marginTop: theme.spacing(0.5), + display: "block", + textTransform: "capitalize", + }, })) diff --git a/site/src/components/TemplateResourcesTable/TemplateResourcesTable.tsx b/site/src/components/TemplateResourcesTable/TemplateResourcesTable.tsx new file mode 100644 index 0000000000000..8c65f82da9089 --- /dev/null +++ b/site/src/components/TemplateResourcesTable/TemplateResourcesTable.tsx @@ -0,0 +1,109 @@ +import { makeStyles } from "@material-ui/core/styles" +import Table from "@material-ui/core/Table" +import TableBody from "@material-ui/core/TableBody" +import TableCell from "@material-ui/core/TableCell" +import TableHead from "@material-ui/core/TableHead" +import TableRow from "@material-ui/core/TableRow" +import React from "react" +import { WorkspaceResource } from "../../api/typesGenerated" +import { TableHeaderRow } from "../TableHeaders/TableHeaders" + +const Language = { + resourceLabel: "Resource", + agentLabel: "Agent", +} + +interface TemplateResourcesProps { + resources: WorkspaceResource[] +} + +export const TemplateResourcesTable: React.FC = ({ resources }) => { + const styles = useStyles() + + return ( + + + + {Language.resourceLabel} + {Language.agentLabel} + + + + {resources.map((resource) => { + { + /* We need to initialize the agents to display the resource */ + } + const agents = resource.agents ?? [null] + return agents.map((agent, agentIndex) => { + { + /* If there is no agent, just display the resource name */ + } + if (!agent) { + return ( + + + {resource.name} + {resource.type} + + + + ) + } + + return ( + + {/* We only want to display the name in the first row because we are using rowSpan */} + {/* The rowspan should be the same than the number of agents */} + {agentIndex === 0 && ( + + {resource.name} + {resource.type} + + )} + + + {agent.name} + {agent.operating_system} + + + ) + }) + })} + +
+ ) +} + +const useStyles = makeStyles((theme) => ({ + sectionContents: { + margin: 0, + }, + + table: { + border: 0, + }, + + resourceNameCell: { + borderRight: `1px solid ${theme.palette.divider}`, + }, + + resourceType: { + fontSize: 14, + color: theme.palette.text.secondary, + marginTop: theme.spacing(0.5), + display: "block", + }, + + // Adds some left spacing + agentColumn: { + paddingLeft: `${theme.spacing(2)}px !important`, + }, + + operatingSystem: { + fontSize: 14, + color: theme.palette.text.secondary, + marginTop: theme.spacing(0.5), + display: "block", + textTransform: "capitalize", + }, +})) diff --git a/site/src/components/TemplateStats/TemplateStats.tsx b/site/src/components/TemplateStats/TemplateStats.tsx new file mode 100644 index 0000000000000..d34be9e266122 --- /dev/null +++ b/site/src/components/TemplateStats/TemplateStats.tsx @@ -0,0 +1,87 @@ +import { makeStyles } from "@material-ui/core/styles" +import dayjs from "dayjs" +import React from "react" +import { Template, TemplateVersion } from "../../api/typesGenerated" +import { CardRadius, MONOSPACE_FONT_FAMILY } from "../../theme/constants" + +const Language = { + usedByLabel: "Used by", + activeVersionLabel: "Active version", + lastUpdateLabel: "Last updated", + userPlural: "users", + userSingular: "user", +} + +export interface TemplateStatsProps { + template: Template + activeVersion: TemplateVersion +} + +export const TemplateStats: React.FC = ({ template, activeVersion }) => { + const styles = useStyles() + + return ( +
+
+ {Language.usedByLabel} + + + {template.workspace_owner_count}{" "} + {template.workspace_owner_count === 1 ? Language.userSingular : Language.userPlural} + +
+
+
+ {Language.activeVersionLabel} + {activeVersion.name} +
+
+
+ {Language.lastUpdateLabel} + + {dayjs().to(dayjs(template.updated_at))} + +
+
+ ) +} + +const useStyles = makeStyles((theme) => ({ + stats: { + paddingLeft: theme.spacing(2), + paddingRight: theme.spacing(2), + backgroundColor: theme.palette.background.paper, + borderRadius: CardRadius, + display: "flex", + alignItems: "center", + color: theme.palette.text.secondary, + fontFamily: MONOSPACE_FONT_FAMILY, + border: `1px solid ${theme.palette.divider}`, + }, + + statItem: { + minWidth: theme.spacing(20), + padding: theme.spacing(2), + paddingTop: theme.spacing(1.75), + }, + + statsLabel: { + fontSize: 12, + textTransform: "uppercase", + display: "block", + fontWeight: 600, + }, + + statsValue: { + fontSize: 16, + marginTop: theme.spacing(0.25), + display: "inline-block", + }, + + statsDivider: { + width: 1, + height: theme.spacing(5), + backgroundColor: theme.palette.divider, + marginRight: theme.spacing(2), + }, +})) diff --git a/site/src/hooks/useOrganizationID.ts b/site/src/hooks/useOrganizationID.ts new file mode 100644 index 0000000000000..202e10bbfbbb0 --- /dev/null +++ b/site/src/hooks/useOrganizationID.ts @@ -0,0 +1,15 @@ +import { useActor } from "@xstate/react" +import { useContext } from "react" +import { XServiceContext } from "../xServices/StateContext" + +export const useOrganizationID = (): string => { + const xServices = useContext(XServiceContext) + const [authState] = useActor(xServices.authXService) + const organizationId = authState.context.me?.organization_ids[0] + + if (!organizationId) { + throw new Error("No organization ID found") + } + + return organizationId +} diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx index ae71dd5cf4319..a0e3bc1207dd7 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx @@ -1,25 +1,13 @@ -import { useActor, useMachine } from "@xstate/react" -import React, { useContext } from "react" +import { useMachine } from "@xstate/react" +import React from "react" import { useNavigate, useSearchParams } from "react-router-dom" import { Template } from "../../api/typesGenerated" +import { useOrganizationID } from "../../hooks/useOrganizationID" import { createWorkspaceMachine } from "../../xServices/createWorkspace/createWorkspaceXService" -import { XServiceContext } from "../../xServices/StateContext" import { CreateWorkspacePageView } from "./CreateWorkspacePageView" -const useOrganizationId = () => { - const xServices = useContext(XServiceContext) - const [authState] = useActor(xServices.authXService) - const organizationId = authState.context.me?.organization_ids[0] - - if (!organizationId) { - throw new Error("No organization ID found") - } - - return organizationId -} - const CreateWorkspacePage: React.FC = () => { - const organizationId = useOrganizationId() + const organizationId = useOrganizationID() const [searchParams] = useSearchParams() const preSelectedTemplateName = searchParams.get("template") const navigate = useNavigate() diff --git a/site/src/pages/TemplatePage/TemplatePage.tsx b/site/src/pages/TemplatePage/TemplatePage.tsx new file mode 100644 index 0000000000000..05fa2caf2cbd8 --- /dev/null +++ b/site/src/pages/TemplatePage/TemplatePage.tsx @@ -0,0 +1,138 @@ +import Button from "@material-ui/core/Button" +import Link from "@material-ui/core/Link" +import { makeStyles } from "@material-ui/core/styles" +import Typography from "@material-ui/core/Typography" +import AddCircleOutline from "@material-ui/icons/AddCircleOutline" +import { useMachine } from "@xstate/react" +import React from "react" +import ReactMarkdown from "react-markdown" +import { Link as RouterLink, useParams } from "react-router-dom" +import { WorkspaceResource } from "../../api/typesGenerated" +import { Loader } from "../../components/Loader/Loader" +import { Margins } from "../../components/Margins/Margins" +import { Stack } from "../../components/Stack/Stack" +import { TemplateResourcesTable } from "../../components/TemplateResourcesTable/TemplateResourcesTable" +import { TemplateStats } from "../../components/TemplateStats/TemplateStats" +import { WorkspaceSection } from "../../components/WorkspaceSection/WorkspaceSection" +import { useOrganizationID } from "../../hooks/useOrganizationID" +import { MONOSPACE_FONT_FAMILY } from "../../theme/constants" +import { templateMachine } from "../../xServices/template/templateXService" + +const Language = { + createButton: "Create workspace", +} + +const useTemplateName = () => { + const { template } = useParams() + + if (!template) { + throw new Error("No template found in the URL") + } + + return template +} + +export const TemplatePage: React.FC = () => { + const organizationId = useOrganizationID() + const templateName = useTemplateName() + const [templateState] = useMachine(templateMachine, { + context: { + templateName, + organizationId, + }, + }) + const { template, activeTemplateVersion, templateResources } = templateState.context + const isLoading = !template || !activeTemplateVersion || !templateResources + const styles = useStyles() + + const getStartedResources = (resources: WorkspaceResource[]) => { + return resources.filter((resource) => resource.workspace_transition === "start") + } + + if (isLoading) { + return + } + + return ( + +
+
+ + {template.name} + + + + {template.description === "" ? "No description" : template.description} + +
+ +
+ + + +
+
+ + + + + + + +
+ {activeTemplateVersion.readme} +
+
+
+
+ ) +} + +export const useStyles = makeStyles((theme) => { + return { + root: { + display: "flex", + flexDirection: "column", + }, + header: { + paddingTop: theme.spacing(5), + paddingBottom: theme.spacing(5), + fontFamily: MONOSPACE_FONT_FAMILY, + display: "flex", + alignItems: "center", + }, + headerActions: { + marginLeft: "auto", + }, + title: { + fontWeight: 600, + fontFamily: "inherit", + }, + subtitle: { + fontFamily: "inherit", + marginTop: theme.spacing(0.5), + }, + layout: { + alignItems: "flex-start", + }, + main: { + width: "100%", + }, + sidebar: { + width: theme.spacing(32), + flexShrink: 0, + }, + readmeContents: { + margin: 0, + }, + markdownWrapper: { + whiteSpace: "pre-wrap", + background: theme.palette.background.paper, + padding: theme.spacing(6), + lineHeight: "180%", + }, + resourcesTableContents: { + margin: 0, + }, + } +}) diff --git a/site/src/pages/TemplatesPage/TemplatesPageView.tsx b/site/src/pages/TemplatesPage/TemplatesPageView.tsx index 66efe0945a6ce..6180231de440d 100644 --- a/site/src/pages/TemplatesPage/TemplatesPageView.tsx +++ b/site/src/pages/TemplatesPage/TemplatesPageView.tsx @@ -83,11 +83,7 @@ export const TemplatesPageView: React.FC = (props) => { {firstLetter(template.name)} - + {template.name} {template.description} diff --git a/site/src/xServices/template/templateXService.ts b/site/src/xServices/template/templateXService.ts new file mode 100644 index 0000000000000..3561c013b292c --- /dev/null +++ b/site/src/xServices/template/templateXService.ts @@ -0,0 +1,110 @@ +import { assign, createMachine } from "xstate" +import { getTemplateByName, getTemplateVersion, getTemplateVersionResources } from "../../api/api" +import { Template, TemplateVersion, WorkspaceResource } from "../../api/typesGenerated" + +interface TemplateContext { + organizationId: string + templateName: string + template?: Template + activeTemplateVersion?: TemplateVersion + templateResources?: WorkspaceResource[] +} + +export const templateMachine = createMachine( + { + schema: { + context: {} as TemplateContext, + services: {} as { + getTemplate: { + data: Template + } + getActiveTemplateVersion: { + data: TemplateVersion + } + getTemplateResources: { + data: WorkspaceResource[] + } + }, + }, + tsTypes: {} as import("./templateXService.typegen").Typegen0, + initial: "gettingTemplate", + states: { + gettingTemplate: { + invoke: { + src: "getTemplate", + onDone: { + actions: ["assignTemplate"], + target: "initialInfo", + }, + }, + }, + initialInfo: { + type: "parallel", + onDone: "loaded", + states: { + activeTemplateVersion: { + initial: "gettingActiveTemplateVersion", + states: { + gettingActiveTemplateVersion: { + invoke: { + src: "getActiveTemplateVersion", + onDone: { + actions: ["assignActiveTemplateVersion"], + target: "success", + }, + }, + }, + success: { type: "final" }, + }, + }, + templateResources: { + initial: "gettingTemplateResources", + states: { + gettingTemplateResources: { + invoke: { + src: "getTemplateResources", + onDone: { + actions: ["assignTemplateResources"], + target: "success", + }, + }, + }, + success: { type: "final" }, + }, + }, + }, + }, + loaded: {}, + }, + }, + { + services: { + getTemplate: (ctx) => getTemplateByName(ctx.organizationId, ctx.templateName), + getActiveTemplateVersion: (ctx) => { + if (!ctx.template) { + throw new Error("Template not loaded") + } + + return getTemplateVersion(ctx.template.active_version_id) + }, + getTemplateResources: (ctx) => { + if (!ctx.template) { + throw new Error("Template not loaded") + } + + return getTemplateVersionResources(ctx.template.active_version_id) + }, + }, + actions: { + assignTemplate: assign({ + template: (_, event) => event.data, + }), + assignActiveTemplateVersion: assign({ + activeTemplateVersion: (_, event) => event.data, + }), + assignTemplateResources: assign({ + templateResources: (_, event) => event.data, + }), + }, + }, +) diff --git a/site/yarn.lock b/site/yarn.lock index 0ab541c8bc229..7b774d3d74df8 100644 --- a/site/yarn.lock +++ b/site/yarn.lock @@ -2783,6 +2783,13 @@ resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.2.tgz#66ad9331f63fe8a3d3d9d8c6e3906dd10f6446e8" integrity sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog== +"@types/debug@^4.0.0": + version "4.1.7" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82" + integrity sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg== + dependencies: + "@types/ms" "*" + "@types/eslint-scope@^3.7.3": version "3.7.3" resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.3.tgz#125b88504b61e3c8bc6f870882003253005c3224" @@ -2934,6 +2941,11 @@ dependencies: "@types/unist" "*" +"@types/mdurl@^1.0.0": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.2.tgz#e2ce9d83a613bacf284c7be7d491945e39e1f8e9" + integrity sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA== + "@types/mime@^1": version "1.3.2" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" @@ -2944,6 +2956,11 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== +"@types/ms@*": + version "0.7.31" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" + integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== + "@types/node-fetch@^2.5.7": version "2.5.12" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.12.tgz#8a6f779b1d4e60b7a57fb6fd48d84fb545b9cc66" @@ -3002,6 +3019,11 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== +"@types/prop-types@^15.0.0": + version "15.7.5" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" + integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== + "@types/qs@*", "@types/qs@^6.9.5": version "6.9.7" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" @@ -4285,6 +4307,11 @@ bail@^1.0.0: resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ== +bail@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d" + integrity sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw== + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -4789,6 +4816,11 @@ character-entities@^1.0.0: resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== +character-entities@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.1.tgz#98724833e1e27990dee0bd0f2b8a859c3476aac7" + integrity sha512-OzmutCf2Kmc+6DrFrrPS8/tDh2+DpnrfzdICHWhcVC9eOd0N1PXmQEE1a8iM4IziIAG+8tmTq3K+oo0ubH6RRQ== + character-reference-invalid@^1.0.0: version "1.1.4" resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" @@ -5043,6 +5075,11 @@ comma-separated-tokens@^1.0.0: resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== +comma-separated-tokens@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.2.tgz#d4c25abb679b7751c880be623c1179780fe1dd98" + integrity sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg== + commander@^2.19.0, commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -5587,7 +5624,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: +debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -5606,6 +5643,13 @@ decimal.js@^10.2.1: resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== +decode-named-character-reference@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.0.1.tgz#57b2bd9112659cacbc449d3577d7dadb8e1f3d1b" + integrity sha512-YV/0HQHreRwKb7uBopyIkLG17jG6Sv2qUchk9qSoVJ2f+flwRsPNBO0hAnjt6mTNYUT+vw9Gy2ihXg4sUWPi2w== + dependencies: + character-entities "^2.0.0" + decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" @@ -5699,6 +5743,11 @@ depd@~1.1.2: resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= +dequal@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.2.tgz#85ca22025e3a87e65ef75a7a437b35284a7e319d" + integrity sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug== + des.js@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" @@ -5747,6 +5796,11 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +diff@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40" + integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw== + diffie-hellman@^5.0.0: version "5.0.3" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" @@ -7376,6 +7430,11 @@ hast-util-to-parse5@^6.0.0: xtend "^4.0.0" zwitch "^1.0.0" +hast-util-whitespace@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-2.0.0.tgz#4fc1086467cc1ef5ba20673cb6b03cec3a970f1c" + integrity sha512-Pkw+xBHuV6xFeJprJe2BBEoDV+AvQySaz3pPDRUs5PNZEMQjpXJJueqrpcHIXxnWTcAGi/UOCgVShlkY6kLoqg== + hastscript@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-6.0.0.tgz#e8768d7eac56c3fdeac8a92830d58e811e5bf640" @@ -8048,6 +8107,11 @@ is-plain-obj@^3.0.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== +is-plain-obj@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.0.0.tgz#06c0999fd7574edf5a906ba5644ad0feb3a84d22" + integrity sha512-NXRbBtUdBioI73y/HmOhogw/U5msYPC9DAtGkJXeFcFWSFZw0mCUsPxk/snTuJHzNKA8kLBK4rH97RMB1BfCXw== + is-plain-object@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" @@ -8992,6 +9056,11 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== +kleur@^4.0.3: + version "4.1.4" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.4.tgz#8c202987d7e577766d039a8cd461934c01cda04d" + integrity sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA== + klona@^2.0.4: version "2.0.5" resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc" @@ -9274,6 +9343,33 @@ mdast-util-definitions@^4.0.0: dependencies: unist-util-visit "^2.0.0" +mdast-util-definitions@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-5.1.0.tgz#b6d10ef00a3c4cf191e8d9a5fa58d7f4a366f817" + integrity sha512-5hcR7FL2EuZ4q6lLMUK5w4lHT2H3vqL9quPvYZ/Ku5iifrirfMHiGdhxdXMUbUkDmz5I+TYMd7nbaxUhbQkfpQ== + dependencies: + "@types/mdast" "^3.0.0" + "@types/unist" "^2.0.0" + unist-util-visit "^3.0.0" + +mdast-util-from-markdown@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz#84df2924ccc6c995dec1e2368b2b208ad0a76268" + integrity sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q== + dependencies: + "@types/mdast" "^3.0.0" + "@types/unist" "^2.0.0" + decode-named-character-reference "^1.0.0" + mdast-util-to-string "^3.1.0" + micromark "^3.0.0" + micromark-util-decode-numeric-character-reference "^1.0.0" + micromark-util-decode-string "^1.0.0" + micromark-util-normalize-identifier "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + unist-util-stringify-position "^3.0.0" + uvu "^0.5.0" + mdast-util-to-hast@10.0.1: version "10.0.1" resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz#0cfc82089494c52d46eb0e3edb7a4eb2aea021eb" @@ -9288,11 +9384,32 @@ mdast-util-to-hast@10.0.1: unist-util-position "^3.0.0" unist-util-visit "^2.0.0" +mdast-util-to-hast@^12.1.0: + version "12.1.1" + resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-12.1.1.tgz#89a2bb405eaf3b05eb8bf45157678f35eef5dbca" + integrity sha512-qE09zD6ylVP14jV4mjLIhDBOrpFdShHZcEsYvvKGABlr9mGbV7mTlRWdoFxL/EYSTNDiC9GZXy7y8Shgb9Dtzw== + dependencies: + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + "@types/mdurl" "^1.0.0" + mdast-util-definitions "^5.0.0" + mdurl "^1.0.0" + micromark-util-sanitize-uri "^1.0.0" + unist-builder "^3.0.0" + unist-util-generated "^2.0.0" + unist-util-position "^4.0.0" + unist-util-visit "^4.0.0" + mdast-util-to-string@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz#27055500103f51637bd07d01da01eb1967a43527" integrity sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A== +mdast-util-to-string@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz#56c506d065fbf769515235e577b5a261552d56e9" + integrity sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA== + mdn-data@2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" @@ -9363,6 +9480,201 @@ microevent.ts@~0.1.1: resolved "https://registry.yarnpkg.com/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0" integrity sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g== +micromark-core-commonmark@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz#edff4c72e5993d93724a3c206970f5a15b0585ad" + integrity sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA== + dependencies: + decode-named-character-reference "^1.0.0" + micromark-factory-destination "^1.0.0" + micromark-factory-label "^1.0.0" + micromark-factory-space "^1.0.0" + micromark-factory-title "^1.0.0" + micromark-factory-whitespace "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-chunked "^1.0.0" + micromark-util-classify-character "^1.0.0" + micromark-util-html-tag-name "^1.0.0" + micromark-util-normalize-identifier "^1.0.0" + micromark-util-resolve-all "^1.0.0" + micromark-util-subtokenize "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.1" + uvu "^0.5.0" + +micromark-factory-destination@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz#fef1cb59ad4997c496f887b6977aa3034a5a277e" + integrity sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-factory-label@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz#6be2551fa8d13542fcbbac478258fb7a20047137" + integrity sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-factory-space@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz#cebff49968f2b9616c0fcb239e96685cb9497633" + integrity sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-factory-title@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz#7e09287c3748ff1693930f176e1c4a328382494f" + integrity sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A== + dependencies: + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-factory-whitespace@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz#e991e043ad376c1ba52f4e49858ce0794678621c" + integrity sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A== + dependencies: + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-util-character@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-1.1.0.tgz#d97c54d5742a0d9611a68ca0cd4124331f264d86" + integrity sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg== + dependencies: + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-util-chunked@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz#5b40d83f3d53b84c4c6bce30ed4257e9a4c79d06" + integrity sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g== + dependencies: + micromark-util-symbol "^1.0.0" + +micromark-util-classify-character@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz#cbd7b447cb79ee6997dd274a46fc4eb806460a20" + integrity sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-util-combine-extensions@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz#91418e1e74fb893e3628b8d496085639124ff3d5" + integrity sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA== + dependencies: + micromark-util-chunked "^1.0.0" + micromark-util-types "^1.0.0" + +micromark-util-decode-numeric-character-reference@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz#dcc85f13b5bd93ff8d2868c3dba28039d490b946" + integrity sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w== + dependencies: + micromark-util-symbol "^1.0.0" + +micromark-util-decode-string@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz#942252ab7a76dec2dbf089cc32505ee2bc3acf02" + integrity sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q== + dependencies: + decode-named-character-reference "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-decode-numeric-character-reference "^1.0.0" + micromark-util-symbol "^1.0.0" + +micromark-util-encode@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz#2c1c22d3800870ad770ece5686ebca5920353383" + integrity sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA== + +micromark-util-html-tag-name@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.0.0.tgz#75737e92fef50af0c6212bd309bc5cb8dbd489ed" + integrity sha512-NenEKIshW2ZI/ERv9HtFNsrn3llSPZtY337LID/24WeLqMzeZhBEE6BQ0vS2ZBjshm5n40chKtJ3qjAbVV8S0g== + +micromark-util-normalize-identifier@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz#4a3539cb8db954bbec5203952bfe8cedadae7828" + integrity sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg== + dependencies: + micromark-util-symbol "^1.0.0" + +micromark-util-resolve-all@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz#a7c363f49a0162e931960c44f3127ab58f031d88" + integrity sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw== + dependencies: + micromark-util-types "^1.0.0" + +micromark-util-sanitize-uri@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.0.0.tgz#27dc875397cd15102274c6c6da5585d34d4f12b2" + integrity sha512-cCxvBKlmac4rxCGx6ejlIviRaMKZc0fWm5HdCHEeDWRSkn44l6NdYVRyU+0nT1XC72EQJMZV8IPHF+jTr56lAg== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-encode "^1.0.0" + micromark-util-symbol "^1.0.0" + +micromark-util-subtokenize@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz#ff6f1af6ac836f8bfdbf9b02f40431760ad89105" + integrity sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA== + dependencies: + micromark-util-chunked "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + +micromark-util-symbol@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz#b90344db62042ce454f351cf0bebcc0a6da4920e" + integrity sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ== + +micromark-util-types@^1.0.0, micromark-util-types@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-1.0.2.tgz#f4220fdb319205812f99c40f8c87a9be83eded20" + integrity sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w== + +micromark@^3.0.0: + version "3.0.10" + resolved "https://registry.yarnpkg.com/micromark/-/micromark-3.0.10.tgz#1eac156f0399d42736458a14b0ca2d86190b457c" + integrity sha512-ryTDy6UUunOXy2HPjelppgJ2sNfcPz1pLlMdA6Rz9jPzhLikWXv/irpWV/I2jd68Uhmny7hHxAlAhk4+vWggpg== + dependencies: + "@types/debug" "^4.0.0" + debug "^4.0.0" + decode-named-character-reference "^1.0.0" + micromark-core-commonmark "^1.0.1" + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-chunked "^1.0.0" + micromark-util-combine-extensions "^1.0.0" + micromark-util-decode-numeric-character-reference "^1.0.0" + micromark-util-encode "^1.0.0" + micromark-util-normalize-identifier "^1.0.0" + micromark-util-resolve-all "^1.0.0" + micromark-util-sanitize-uri "^1.0.0" + micromark-util-subtokenize "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.1" + uvu "^0.5.0" + micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -9562,6 +9874,11 @@ move-concurrently@^1.0.1: rimraf "^2.5.4" run-queue "^1.0.3" +mri@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" + integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== + mrmime@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.0.tgz#14d387f0585a5233d291baba339b063752a2398b" @@ -10827,6 +11144,11 @@ property-information@^5.0.0, property-information@^5.3.0: dependencies: xtend "^4.0.0" +property-information@^6.0.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.1.1.tgz#5ca85510a3019726cb9afed4197b7b8ac5926a22" + integrity sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w== + proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -11085,11 +11407,37 @@ react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-is@^18.0.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.1.0.tgz#61aaed3096d30eacf2a2127118b5b41387d32a67" + integrity sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg== + react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== +react-markdown@^8.0.3: + version "8.0.3" + resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-8.0.3.tgz#e8aba0d2f5a1b2124d476ee1fff9448a2f57e4b3" + integrity sha512-We36SfqaKoVNpN1QqsZwWSv/OZt5J15LNgTLWynwAN5b265hrQrsjMtlRNwUvS+YyR3yDM8HpTNc4pK9H/Gc0A== + dependencies: + "@types/hast" "^2.0.0" + "@types/prop-types" "^15.0.0" + "@types/unist" "^2.0.0" + comma-separated-tokens "^2.0.0" + hast-util-whitespace "^2.0.0" + prop-types "^15.0.0" + property-information "^6.0.0" + react-is "^18.0.0" + remark-parse "^10.0.0" + remark-rehype "^10.0.0" + space-separated-tokens "^2.0.0" + style-to-object "^0.3.0" + unified "^10.0.0" + unist-util-visit "^4.0.0" + vfile "^5.0.0" + react-popper-tooltip@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/react-popper-tooltip/-/react-popper-tooltip-3.1.1.tgz#329569eb7b287008f04fcbddb6370452ad3f9eac" @@ -11382,6 +11730,25 @@ remark-parse@8.0.3: vfile-location "^3.0.0" xtend "^4.0.1" +remark-parse@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-10.0.1.tgz#6f60ae53edbf0cf38ea223fe643db64d112e0775" + integrity sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw== + dependencies: + "@types/mdast" "^3.0.0" + mdast-util-from-markdown "^1.0.0" + unified "^10.0.0" + +remark-rehype@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-10.1.0.tgz#32dc99d2034c27ecaf2e0150d22a6dcccd9a6279" + integrity sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw== + dependencies: + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + mdast-util-to-hast "^12.1.0" + unified "^10.0.0" + remark-slug@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/remark-slug/-/remark-slug-6.1.0.tgz#0503268d5f0c4ecb1f33315c00465ccdd97923ce" @@ -11570,6 +11937,13 @@ rxjs@^7.5.5: dependencies: tslib "^2.1.0" +sade@^1.7.3: + version "1.8.1" + resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.1.tgz#0a78e81d658d394887be57d2a409bf703a3b2701" + integrity sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A== + dependencies: + mri "^1.1.0" + safe-buffer@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" @@ -12023,6 +12397,11 @@ space-separated-tokens@^1.0.0: resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA== +space-separated-tokens@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.1.tgz#43193cec4fb858a2ce934b7f98b7f2c18107098b" + integrity sha512-ekwEbFp5aqSPKaqeY1PGrlGQxPNaq+Cnx4+bE2D8sciBQrHpbwoBbawqTN2+6jPs9IdWxxiUcN0K2pkczD3zmw== + spdx-correct@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" @@ -12701,6 +13080,11 @@ trough@^1.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== +trough@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/trough/-/trough-2.1.0.tgz#0f7b511a4fde65a46f18477ab38849b22c554876" + integrity sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g== + ts-dedent@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5" @@ -12918,6 +13302,19 @@ unified@9.2.0: trough "^1.0.0" vfile "^4.0.0" +unified@^10.0.0: + version "10.1.2" + resolved "https://registry.yarnpkg.com/unified/-/unified-10.1.2.tgz#b1d64e55dafe1f0b98bb6c719881103ecf6c86df" + integrity sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q== + dependencies: + "@types/unist" "^2.0.0" + bail "^2.0.0" + extend "^3.0.0" + is-buffer "^2.0.0" + is-plain-obj "^4.0.0" + trough "^2.0.0" + vfile "^5.0.0" + union-value@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" @@ -12947,21 +13344,45 @@ unist-builder@2.0.3, unist-builder@^2.0.0: resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-2.0.3.tgz#77648711b5d86af0942f334397a33c5e91516436" integrity sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw== +unist-builder@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-3.0.0.tgz#728baca4767c0e784e1e64bb44b5a5a753021a04" + integrity sha512-GFxmfEAa0vi9i5sd0R2kcrI9ks0r82NasRq5QHh2ysGngrc6GiqD5CDf1FjPenY4vApmFASBIIlk/jj5J5YbmQ== + dependencies: + "@types/unist" "^2.0.0" + unist-util-generated@^1.0.0: version "1.1.6" resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-1.1.6.tgz#5ab51f689e2992a472beb1b35f2ce7ff2f324d4b" integrity sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg== +unist-util-generated@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-2.0.0.tgz#86fafb77eb6ce9bfa6b663c3f5ad4f8e56a60113" + integrity sha512-TiWE6DVtVe7Ye2QxOVW9kqybs6cZexNwTwSMVgkfjEReqy/xwGpAXb99OxktoWwmL+Z+Epb0Dn8/GNDYP1wnUw== + unist-util-is@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.1.0.tgz#976e5f462a7a5de73d94b706bac1b90671b57797" integrity sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg== +unist-util-is@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-5.1.1.tgz#e8aece0b102fa9bc097b0fef8f870c496d4a6236" + integrity sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ== + unist-util-position@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-3.1.0.tgz#1c42ee6301f8d52f47d14f62bbdb796571fa2d47" integrity sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA== +unist-util-position@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-4.0.3.tgz#5290547b014f6222dff95c48d5c3c13a88fadd07" + integrity sha512-p/5EMGIa1qwbXjA+QgcBXaPWjSnZfQ2Sc3yBEEfgPwsEmJd8Qh+DSk3LGnmOM4S1bY2C0AjmMnB8RuEYxpPwXQ== + dependencies: + "@types/unist" "^2.0.0" + unist-util-remove-position@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz#5d19ca79fdba712301999b2b73553ca8f3b352cc" @@ -12983,6 +13404,13 @@ unist-util-stringify-position@^2.0.0: dependencies: "@types/unist" "^2.0.2" +unist-util-stringify-position@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz#5c6aa07c90b1deffd9153be170dce628a869a447" + integrity sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg== + dependencies: + "@types/unist" "^2.0.0" + unist-util-visit-parents@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz#65a6ce698f78a6b0f56aa0e88f13801886cdaef6" @@ -12991,6 +13419,22 @@ unist-util-visit-parents@^3.0.0: "@types/unist" "^2.0.0" unist-util-is "^4.0.0" +unist-util-visit-parents@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-4.1.1.tgz#e83559a4ad7e6048a46b1bdb22614f2f3f4724f2" + integrity sha512-1xAFJXAKpnnJl8G7K5KgU7FY55y3GcLIXqkzUj5QF/QVP7biUm0K0O2oqVkYsdjzJKifYeWn9+o6piAK2hGSHw== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^5.0.0" + +unist-util-visit-parents@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-5.1.0.tgz#44bbc5d25f2411e7dfc5cecff12de43296aa8521" + integrity sha512-y+QVLcY5eR/YVpqDsLf/xh9R3Q2Y4HxkZTp7ViLDU6WtJCEcPmRzW1gpdWDCDIqIlhuPDXOgttqPlykrHYDekg== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^5.0.0" + unist-util-visit@2.0.3, unist-util-visit@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-2.0.3.tgz#c3703893146df47203bb8a9795af47d7b971208c" @@ -13000,6 +13444,24 @@ unist-util-visit@2.0.3, unist-util-visit@^2.0.0: unist-util-is "^4.0.0" unist-util-visit-parents "^3.0.0" +unist-util-visit@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-3.1.0.tgz#9420d285e1aee938c7d9acbafc8e160186dbaf7b" + integrity sha512-Szoh+R/Ll68QWAyQyZZpQzZQm2UPbxibDvaY8Xc9SUtYgPsDzx5AWSk++UUt2hJuow8mvwR+rG+LQLw+KsuAKA== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^5.0.0" + unist-util-visit-parents "^4.0.0" + +unist-util-visit@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-4.1.0.tgz#f41e407a9e94da31594e6b1c9811c51ab0b3d8f5" + integrity sha512-n7lyhFKJfVZ9MnKtqbsqkQEk5P1KShj0+//V7mAcoI6bpbUjh3C/OG8HVD+pBihfh6Ovl01m8dkcv9HNqYajmQ== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^5.0.0" + unist-util-visit-parents "^5.0.0" + universalify@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -13136,6 +13598,16 @@ uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +uvu@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/uvu/-/uvu-0.5.3.tgz#3d83c5bc1230f153451877bfc7f4aea2392219ae" + integrity sha512-brFwqA3FXzilmtnIyJ+CxdkInkY/i4ErvP7uV0DnUVxQcQ55reuHphorpF+tZoVHK2MniZ/VJzI7zJQoc9T9Yw== + dependencies: + dequal "^2.0.0" + diff "^5.0.0" + kleur "^4.0.3" + sade "^1.7.3" + v8-compile-cache-lib@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz#0582bcb1c74f3a2ee46487ceecf372e46bce53e8" @@ -13181,6 +13653,14 @@ vfile-message@^2.0.0: "@types/unist" "^2.0.0" unist-util-stringify-position "^2.0.0" +vfile-message@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-3.1.2.tgz#a2908f64d9e557315ec9d7ea3a910f658ac05f7d" + integrity sha512-QjSNP6Yxzyycd4SVOtmKKyTsSvClqBPJcd00Z0zuPj3hOIjg0rUPG6DbFGPvUKRgYyaIWLPKpuEclcuvb3H8qA== + dependencies: + "@types/unist" "^2.0.0" + unist-util-stringify-position "^3.0.0" + vfile@^4.0.0: version "4.2.1" resolved "https://registry.yarnpkg.com/vfile/-/vfile-4.2.1.tgz#03f1dce28fc625c625bc6514350fbdb00fa9e624" @@ -13191,6 +13671,16 @@ vfile@^4.0.0: unist-util-stringify-position "^2.0.0" vfile-message "^2.0.0" +vfile@^5.0.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-5.3.2.tgz#b499fbc50197ea50ad3749e9b60beb16ca5b7c54" + integrity sha512-w0PLIugRY3Crkgw89TeMvHCzqCs/zpreR31hl4D92y6SOE07+bfJe+dK5Q2akwS+i/c801kzjoOr9gMcTe6IAA== + dependencies: + "@types/unist" "^2.0.0" + is-buffer "^2.0.0" + unist-util-stringify-position "^3.0.0" + vfile-message "^3.0.0" + vm-browserify@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" From b8ff946651e0a62080f3ee4967f0aab5a299bf5c Mon Sep 17 00:00:00 2001 From: Bruno Date: Wed, 25 May 2022 17:06:20 +0000 Subject: [PATCH 02/10] Add template stats storybook --- .../TemplateStats/TemplateStats.stories.tsx | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 site/src/components/TemplateStats/TemplateStats.stories.tsx diff --git a/site/src/components/TemplateStats/TemplateStats.stories.tsx b/site/src/components/TemplateStats/TemplateStats.stories.tsx new file mode 100644 index 0000000000000..8ae21da32f5e5 --- /dev/null +++ b/site/src/components/TemplateStats/TemplateStats.stories.tsx @@ -0,0 +1,26 @@ +import { Story } from "@storybook/react" +import React from "react" +import * as Mocks from "../../testHelpers/renderHelpers" +import { TemplateStats, TemplateStatsProps } from "../TemplateStats/TemplateStats" + +export default { + title: "components/TemplateStats", + component: TemplateStats, +} + +const Template: Story = (args) => + +export const Example = Template.bind({}) +Example.args = { + template: Mocks.MockTemplate, + activeVersion: Mocks.MockTemplateVersion, +} + +export const UsedByMany = Template.bind({}) +UsedByMany.args = { + template: { + ...Mocks.MockTemplate, + workspace_owner_count: 15, + }, + activeVersion: Mocks.MockTemplateVersion, +} From 02747cfe451b29e5fb5d9e6c182f8ed8a00b5c5c Mon Sep 17 00:00:00 2001 From: Bruno Date: Wed, 25 May 2022 17:18:34 +0000 Subject: [PATCH 03/10] Add storybook for the template page view --- site/src/pages/TemplatePage/TemplatePage.tsx | 110 ++-------------- .../TemplatePage/TemplatePageView.stories.tsx | 18 +++ .../pages/TemplatePage/TemplatePageView.tsx | 118 ++++++++++++++++++ site/src/testHelpers/entities.ts | 2 +- 4 files changed, 144 insertions(+), 104 deletions(-) create mode 100644 site/src/pages/TemplatePage/TemplatePageView.stories.tsx create mode 100644 site/src/pages/TemplatePage/TemplatePageView.tsx diff --git a/site/src/pages/TemplatePage/TemplatePage.tsx b/site/src/pages/TemplatePage/TemplatePage.tsx index 05fa2caf2cbd8..b5be16927cf51 100644 --- a/site/src/pages/TemplatePage/TemplatePage.tsx +++ b/site/src/pages/TemplatePage/TemplatePage.tsx @@ -1,26 +1,10 @@ -import Button from "@material-ui/core/Button" -import Link from "@material-ui/core/Link" -import { makeStyles } from "@material-ui/core/styles" -import Typography from "@material-ui/core/Typography" -import AddCircleOutline from "@material-ui/icons/AddCircleOutline" import { useMachine } from "@xstate/react" import React from "react" -import ReactMarkdown from "react-markdown" -import { Link as RouterLink, useParams } from "react-router-dom" -import { WorkspaceResource } from "../../api/typesGenerated" +import { useParams } from "react-router-dom" import { Loader } from "../../components/Loader/Loader" -import { Margins } from "../../components/Margins/Margins" -import { Stack } from "../../components/Stack/Stack" -import { TemplateResourcesTable } from "../../components/TemplateResourcesTable/TemplateResourcesTable" -import { TemplateStats } from "../../components/TemplateStats/TemplateStats" -import { WorkspaceSection } from "../../components/WorkspaceSection/WorkspaceSection" import { useOrganizationID } from "../../hooks/useOrganizationID" -import { MONOSPACE_FONT_FAMILY } from "../../theme/constants" import { templateMachine } from "../../xServices/template/templateXService" - -const Language = { - createButton: "Create workspace", -} +import { TemplatePageView } from "./TemplatePageView" const useTemplateName = () => { const { template } = useParams() @@ -43,96 +27,16 @@ export const TemplatePage: React.FC = () => { }) const { template, activeTemplateVersion, templateResources } = templateState.context const isLoading = !template || !activeTemplateVersion || !templateResources - const styles = useStyles() - - const getStartedResources = (resources: WorkspaceResource[]) => { - return resources.filter((resource) => resource.workspace_transition === "start") - } if (isLoading) { return } return ( - -
-
- - {template.name} - - - - {template.description === "" ? "No description" : template.description} - -
- -
- - - -
-
- - - - - - - -
- {activeTemplateVersion.readme} -
-
-
-
+ ) } - -export const useStyles = makeStyles((theme) => { - return { - root: { - display: "flex", - flexDirection: "column", - }, - header: { - paddingTop: theme.spacing(5), - paddingBottom: theme.spacing(5), - fontFamily: MONOSPACE_FONT_FAMILY, - display: "flex", - alignItems: "center", - }, - headerActions: { - marginLeft: "auto", - }, - title: { - fontWeight: 600, - fontFamily: "inherit", - }, - subtitle: { - fontFamily: "inherit", - marginTop: theme.spacing(0.5), - }, - layout: { - alignItems: "flex-start", - }, - main: { - width: "100%", - }, - sidebar: { - width: theme.spacing(32), - flexShrink: 0, - }, - readmeContents: { - margin: 0, - }, - markdownWrapper: { - whiteSpace: "pre-wrap", - background: theme.palette.background.paper, - padding: theme.spacing(6), - lineHeight: "180%", - }, - resourcesTableContents: { - margin: 0, - }, - } -}) diff --git a/site/src/pages/TemplatePage/TemplatePageView.stories.tsx b/site/src/pages/TemplatePage/TemplatePageView.stories.tsx new file mode 100644 index 0000000000000..cd649f73fb5fc --- /dev/null +++ b/site/src/pages/TemplatePage/TemplatePageView.stories.tsx @@ -0,0 +1,18 @@ +import { Story } from "@storybook/react" +import React from "react" +import * as Mocks from "../../testHelpers/renderHelpers" +import { TemplatePageView, TemplatePageViewProps } from "./TemplatePageView" + +export default { + title: "pages/TemplatePageView", + component: TemplatePageView, +} + +const Template: Story = (args) => + +export const Example = Template.bind({}) +Example.args = { + template: Mocks.MockTemplate, + activeTemplateVersion: Mocks.MockTemplateVersion, + templateResources: [Mocks.MockWorkspaceResource, Mocks.MockWorkspaceResource2], +} diff --git a/site/src/pages/TemplatePage/TemplatePageView.tsx b/site/src/pages/TemplatePage/TemplatePageView.tsx new file mode 100644 index 0000000000000..3ec2e5bde8b37 --- /dev/null +++ b/site/src/pages/TemplatePage/TemplatePageView.tsx @@ -0,0 +1,118 @@ +import Button from "@material-ui/core/Button" +import Link from "@material-ui/core/Link" +import { makeStyles } from "@material-ui/core/styles" +import Typography from "@material-ui/core/Typography" +import AddCircleOutline from "@material-ui/icons/AddCircleOutline" +import React from "react" +import ReactMarkdown from "react-markdown" +import { Link as RouterLink } from "react-router-dom" +import { Template, TemplateVersion, WorkspaceResource } from "../../api/typesGenerated" +import { Margins } from "../../components/Margins/Margins" +import { Stack } from "../../components/Stack/Stack" +import { TemplateResourcesTable } from "../../components/TemplateResourcesTable/TemplateResourcesTable" +import { TemplateStats } from "../../components/TemplateStats/TemplateStats" +import { WorkspaceSection } from "../../components/WorkspaceSection/WorkspaceSection" +import { MONOSPACE_FONT_FAMILY } from "../../theme/constants" + +const Language = { + createButton: "Create workspace", +} + +export interface TemplatePageViewProps { + template: Template + activeTemplateVersion: TemplateVersion + templateResources: WorkspaceResource[] +} + +export const TemplatePageView: React.FC = ({ + template, + activeTemplateVersion, + templateResources, +}) => { + const styles = useStyles() + + const getStartedResources = (resources: WorkspaceResource[]) => { + return resources.filter((resource) => resource.workspace_transition === "start") + } + + return ( + +
+
+ + {template.name} + + + + {template.description === "" ? "No description" : template.description} + +
+ +
+ + + +
+
+ + + + + + + +
+ {activeTemplateVersion.readme} +
+
+
+
+ ) +} + +export const useStyles = makeStyles((theme) => { + return { + root: { + display: "flex", + flexDirection: "column", + }, + header: { + paddingTop: theme.spacing(5), + paddingBottom: theme.spacing(5), + fontFamily: MONOSPACE_FONT_FAMILY, + display: "flex", + alignItems: "center", + }, + headerActions: { + marginLeft: "auto", + }, + title: { + fontWeight: 600, + fontFamily: "inherit", + }, + subtitle: { + fontFamily: "inherit", + marginTop: theme.spacing(0.5), + }, + layout: { + alignItems: "flex-start", + }, + main: { + width: "100%", + }, + sidebar: { + width: theme.spacing(32), + flexShrink: 0, + }, + readmeContents: { + margin: 0, + }, + markdownWrapper: { + background: theme.palette.background.paper, + padding: theme.spacing(3.5), + }, + resourcesTableContents: { + margin: 0, + }, + } +}) diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index 06bd8201c414e..fe314967f2773 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -88,7 +88,7 @@ export const MockTemplateVersion: TypesGen.TemplateVersion = { updated_at: "", job: MockProvisionerJob, name: "test-version", - readme: "", + readme: "## Instructions\nYou can add instructions here", } export const MockTemplate: TypesGen.Template = { From f63f04c902e80704e18382243f6d69d288ec5ec6 Mon Sep 17 00:00:00 2001 From: Bruno Date: Wed, 25 May 2022 18:46:19 +0000 Subject: [PATCH 04/10] Add tests --- site/src/__mocks__/react-markdown.tsx | 7 +++++++ site/src/components/TemplateStats/TemplateStats.tsx | 3 +++ site/src/pages/TemplatePage/TemplatePage.test.tsx | 13 +++++++++++++ site/src/testHelpers/handlers.ts | 3 +++ 4 files changed, 26 insertions(+) create mode 100644 site/src/__mocks__/react-markdown.tsx create mode 100644 site/src/pages/TemplatePage/TemplatePage.test.tsx diff --git a/site/src/__mocks__/react-markdown.tsx b/site/src/__mocks__/react-markdown.tsx new file mode 100644 index 0000000000000..14385e612c826 --- /dev/null +++ b/site/src/__mocks__/react-markdown.tsx @@ -0,0 +1,7 @@ +import React from "react" + +const ReactMarkdown: React.FC = ({ children }) => { + return
{children}
+} + +export default ReactMarkdown diff --git a/site/src/components/TemplateStats/TemplateStats.tsx b/site/src/components/TemplateStats/TemplateStats.tsx index d34be9e266122..5410113ff4aa3 100644 --- a/site/src/components/TemplateStats/TemplateStats.tsx +++ b/site/src/components/TemplateStats/TemplateStats.tsx @@ -1,9 +1,12 @@ import { makeStyles } from "@material-ui/core/styles" import dayjs from "dayjs" +import relativeTime from "dayjs/plugin/relativeTime" import React from "react" import { Template, TemplateVersion } from "../../api/typesGenerated" import { CardRadius, MONOSPACE_FONT_FAMILY } from "../../theme/constants" +dayjs.extend(relativeTime) + const Language = { usedByLabel: "Used by", activeVersionLabel: "Active version", diff --git a/site/src/pages/TemplatePage/TemplatePage.test.tsx b/site/src/pages/TemplatePage/TemplatePage.test.tsx new file mode 100644 index 0000000000000..5c342f20e2a9d --- /dev/null +++ b/site/src/pages/TemplatePage/TemplatePage.test.tsx @@ -0,0 +1,13 @@ +import { screen } from "@testing-library/react" +import React from "react" +import { MockTemplate, MockWorkspaceResource, renderWithAuth } from "../../testHelpers/renderHelpers" +import { TemplatePage } from "./TemplatePage" + +describe("TemplatePage", () => { + it("shows the template name, readme and resources", async () => { + renderWithAuth(, { route: `/templates/${MockTemplate.id}`, path: "/templates/:template" }) + await screen.findByText(MockTemplate.name) + screen.getByTestId("markdown") + screen.getByText(MockWorkspaceResource.name) + }) +}) diff --git a/site/src/testHelpers/handlers.ts b/site/src/testHelpers/handlers.ts index 1870e7b4bfbdf..c95d0ad25d107 100644 --- a/site/src/testHelpers/handlers.ts +++ b/site/src/testHelpers/handlers.ts @@ -31,6 +31,9 @@ export const handlers = [ rest.get("/api/v2/templateversions/:templateVersionId/schema", async (req, res, ctx) => { return res(ctx.status(200), ctx.json([])) }), + rest.get("/api/v2/templateversions/:templateVersionId/resources", async (req, res, ctx) => { + return res(ctx.status(200), ctx.json([M.MockWorkspaceResource, M.MockWorkspaceResource2])) + }), // users rest.get("/api/v2/users", async (req, res, ctx) => { From fac8e3e3a180843585d2b91afafe1ed861f19baf Mon Sep 17 00:00:00 2001 From: Bruno Date: Thu, 26 May 2022 15:44:12 +0000 Subject: [PATCH 05/10] Remove unecessary brackets --- .vscode/settings.json | 1 + .../TemplateResourcesTable/TemplateResourcesTable.tsx | 8 ++------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 2ea7220cd50ab..e14c039bb7457 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -60,6 +60,7 @@ "TCGETS", "tcpip", "TCSETS", + "templateversions", "testid", "tfexec", "tfjson", diff --git a/site/src/components/TemplateResourcesTable/TemplateResourcesTable.tsx b/site/src/components/TemplateResourcesTable/TemplateResourcesTable.tsx index 8c65f82da9089..4b340e36cb807 100644 --- a/site/src/components/TemplateResourcesTable/TemplateResourcesTable.tsx +++ b/site/src/components/TemplateResourcesTable/TemplateResourcesTable.tsx @@ -30,14 +30,10 @@ export const TemplateResourcesTable: React.FC = ({ resou {resources.map((resource) => { - { - /* We need to initialize the agents to display the resource */ - } + // We need to initialize the agents to display the resource const agents = resource.agents ?? [null] return agents.map((agent, agentIndex) => { - { - /* If there is no agent, just display the resource name */ - } + // If there is no agent, just display the resource name if (!agent) { return ( From 792ee737c3ee63a4b75733845ec426e458c98766 Mon Sep 17 00:00:00 2001 From: Bruno Date: Thu, 26 May 2022 15:55:35 +0000 Subject: [PATCH 06/10] Fix links on readme --- site/src/pages/TemplatePage/TemplatePageView.tsx | 12 +++++++++++- site/src/testHelpers/entities.ts | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/site/src/pages/TemplatePage/TemplatePageView.tsx b/site/src/pages/TemplatePage/TemplatePageView.tsx index 3ec2e5bde8b37..6c2690d08acd8 100644 --- a/site/src/pages/TemplatePage/TemplatePageView.tsx +++ b/site/src/pages/TemplatePage/TemplatePageView.tsx @@ -62,7 +62,17 @@ export const TemplatePageView: React.FC = ({
- {activeTemplateVersion.readme} + ( + + {children} + + ), + }} + > + {activeTemplateVersion.readme} +
diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index fe314967f2773..ab11f734f06b0 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -88,7 +88,7 @@ export const MockTemplateVersion: TypesGen.TemplateVersion = { updated_at: "", job: MockProvisionerJob, name: "test-version", - readme: "## Instructions\nYou can add instructions here", + readme: "## Instructions\nYou can add instructions here\n\n[Some link info](https://coder.com)", } export const MockTemplate: TypesGen.Template = { From 2822db08af58b3d51663ab49008aaefe89b964b0 Mon Sep 17 00:00:00 2001 From: Bruno Date: Thu, 26 May 2022 15:59:52 +0000 Subject: [PATCH 07/10] Use Id instead of ID --- site/src/hooks/{useOrganizationID.ts => useOrganizationId.ts} | 2 +- site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx | 4 ++-- site/src/pages/TemplatePage/TemplatePage.tsx | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename site/src/hooks/{useOrganizationID.ts => useOrganizationId.ts} (89%) diff --git a/site/src/hooks/useOrganizationID.ts b/site/src/hooks/useOrganizationId.ts similarity index 89% rename from site/src/hooks/useOrganizationID.ts rename to site/src/hooks/useOrganizationId.ts index 202e10bbfbbb0..4e7af3b411ce7 100644 --- a/site/src/hooks/useOrganizationID.ts +++ b/site/src/hooks/useOrganizationId.ts @@ -2,7 +2,7 @@ import { useActor } from "@xstate/react" import { useContext } from "react" import { XServiceContext } from "../xServices/StateContext" -export const useOrganizationID = (): string => { +export const useOrganizationId = (): string => { const xServices = useContext(XServiceContext) const [authState] = useActor(xServices.authXService) const organizationId = authState.context.me?.organization_ids[0] diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx index a0e3bc1207dd7..8bc1914a9c615 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx @@ -2,12 +2,12 @@ import { useMachine } from "@xstate/react" import React from "react" import { useNavigate, useSearchParams } from "react-router-dom" import { Template } from "../../api/typesGenerated" -import { useOrganizationID } from "../../hooks/useOrganizationID" +import { useOrganizationId } from "../../hooks/useOrganizationId" import { createWorkspaceMachine } from "../../xServices/createWorkspace/createWorkspaceXService" import { CreateWorkspacePageView } from "./CreateWorkspacePageView" const CreateWorkspacePage: React.FC = () => { - const organizationId = useOrganizationID() + const organizationId = useOrganizationId() const [searchParams] = useSearchParams() const preSelectedTemplateName = searchParams.get("template") const navigate = useNavigate() diff --git a/site/src/pages/TemplatePage/TemplatePage.tsx b/site/src/pages/TemplatePage/TemplatePage.tsx index b5be16927cf51..d777733f00176 100644 --- a/site/src/pages/TemplatePage/TemplatePage.tsx +++ b/site/src/pages/TemplatePage/TemplatePage.tsx @@ -2,7 +2,7 @@ import { useMachine } from "@xstate/react" import React from "react" import { useParams } from "react-router-dom" import { Loader } from "../../components/Loader/Loader" -import { useOrganizationID } from "../../hooks/useOrganizationID" +import { useOrganizationId } from "../../hooks/useOrganizationId" import { templateMachine } from "../../xServices/template/templateXService" import { TemplatePageView } from "./TemplatePageView" @@ -17,7 +17,7 @@ const useTemplateName = () => { } export const TemplatePage: React.FC = () => { - const organizationId = useOrganizationID() + const organizationId = useOrganizationId() const templateName = useTemplateName() const [templateState] = useMachine(templateMachine, { context: { From b42f3e9ea868fe4857b0bc8749b40d56c83a664a Mon Sep 17 00:00:00 2001 From: Bruno Date: Thu, 26 May 2022 16:03:18 +0000 Subject: [PATCH 08/10] Use selector to get the organization Id --- site/src/hooks/useOrganizationId.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/site/src/hooks/useOrganizationId.ts b/site/src/hooks/useOrganizationId.ts index 4e7af3b411ce7..93712a19dad5b 100644 --- a/site/src/hooks/useOrganizationId.ts +++ b/site/src/hooks/useOrganizationId.ts @@ -1,11 +1,11 @@ -import { useActor } from "@xstate/react" +import { useSelector } from "@xstate/react" import { useContext } from "react" +import { selectOrgId } from "../xServices/auth/authSelectors" import { XServiceContext } from "../xServices/StateContext" export const useOrganizationId = (): string => { const xServices = useContext(XServiceContext) - const [authState] = useActor(xServices.authXService) - const organizationId = authState.context.me?.organization_ids[0] + const organizationId = useSelector(xServices.authXService, selectOrgId) if (!organizationId) { throw new Error("No organization ID found") From 728c2709d35d4994f308dc2d75b3343c8a80a6e5 Mon Sep 17 00:00:00 2001 From: Bruno Date: Thu, 26 May 2022 16:04:49 +0000 Subject: [PATCH 09/10] Pin react-markdown dependency --- site/package.json | 2 +- site/yarn.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/site/package.json b/site/package.json index 5b45531c2cbcd..0739ee932741d 100644 --- a/site/package.json +++ b/site/package.json @@ -41,7 +41,7 @@ "history": "5.3.0", "react": "17.0.2", "react-dom": "17.0.2", - "react-markdown": "^8.0.3", + "react-markdown": "8.0.3", "react-router-dom": "6.3.0", "sourcemapped-stacktrace": "1.1.11", "swr": "1.2.2", diff --git a/site/yarn.lock b/site/yarn.lock index 7b774d3d74df8..d6849cff02878 100644 --- a/site/yarn.lock +++ b/site/yarn.lock @@ -11417,7 +11417,7 @@ react-lifecycles-compat@^3.0.4: resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== -react-markdown@^8.0.3: +react-markdown@8.0.3: version "8.0.3" resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-8.0.3.tgz#e8aba0d2f5a1b2124d476ee1fff9448a2f57e4b3" integrity sha512-We36SfqaKoVNpN1QqsZwWSv/OZt5J15LNgTLWynwAN5b265hrQrsjMtlRNwUvS+YyR3yDM8HpTNc4pK9H/Gc0A== From 5eb55cc7885d2cc3a0e0edcd82990b9dd0375e42 Mon Sep 17 00:00:00 2001 From: Bruno Date: Thu, 26 May 2022 16:08:35 +0000 Subject: [PATCH 10/10] Add missing language --- site/src/pages/TemplatePage/TemplatePageView.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/site/src/pages/TemplatePage/TemplatePageView.tsx b/site/src/pages/TemplatePage/TemplatePageView.tsx index 6c2690d08acd8..dcc0b4dca8904 100644 --- a/site/src/pages/TemplatePage/TemplatePageView.tsx +++ b/site/src/pages/TemplatePage/TemplatePageView.tsx @@ -16,6 +16,9 @@ import { MONOSPACE_FONT_FAMILY } from "../../theme/constants" const Language = { createButton: "Create workspace", + noDescription: "No description", + readmeTitle: "README", + resourcesTitle: "Resources", } export interface TemplatePageViewProps { @@ -44,7 +47,7 @@ export const TemplatePageView: React.FC = ({ - {template.description === "" ? "No description" : template.description} + {template.description === "" ? Language.noDescription : template.description}
@@ -57,10 +60,10 @@ export const TemplatePageView: React.FC = ({ - + - +