diff --git a/.vscode/settings.json b/.vscode/settings.json
index dddc071a..70f705e7 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,5 @@
{
- "editor.formatOnSave": false,
+ "editor.formatOnSave": true,
"editor.codeActionsOnSave": ["source.formatDocument", "source.fixAll.eslint"],
"search.exclude": {
"**/.yarn": true,
diff --git a/next.config.js b/next.config.js
index c74920ca..bf53b999 100644
--- a/next.config.js
+++ b/next.config.js
@@ -1,16 +1,14 @@
/* eslint-disable @typescript-eslint/no-var-requires */
// eslint-disable-next-line function-paren-newline
-const withMarkdoc = require('@markdoc/next.js')(
- /* config: https://markdoc.io/docs/nextjs#options */ {
- schemaPath: './src/markdoc',
- })
-const withTM = require('next-transpile-modules')(['@pluralsh/design-system', 'honorable', 'honorable-theme-default'],
+const withTM = require('next-transpile-modules')(
+ ['@pluralsh/design-system', 'honorable', 'honorable-theme-default'],
{
debug: false,
- })
+ }
+)
module.exports = () => {
- const plugins = [withMarkdoc, withTM]
+ const plugins = [withTM]
return plugins.reduce((acc, next) => next(acc), {
reactStrictMode: false,
@@ -23,7 +21,14 @@ module.exports = () => {
locales: ['en-US'],
defaultLocale: 'en-US',
},
- pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdoc'],
+ pageExtensions: ['js', 'jsx', 'ts', 'tsx'],
+ webpack: (config) => {
+ config.module.rules.push({
+ test: /\.md$/,
+ use: 'raw-loader',
+ })
+ return config
+ },
async redirects() {
return [
{
@@ -53,12 +58,14 @@ module.exports = () => {
},
{
source: '/getting-started/getting-started-with-runbooks/runbook-yaml',
- destination: '/adding-new-application/getting-started-with-runbooks/runbook-yaml',
+ destination:
+ '/adding-new-application/getting-started-with-runbooks/runbook-yaml',
permanent: true,
},
{
source: '/basic-setup-and-deployment/setting-up-gitops',
- destination: '/getting-started/managing-git-repository/setting-up-gitops',
+ destination:
+ '/getting-started/managing-git-repository/setting-up-gitops',
permanent: true,
},
{
@@ -87,7 +94,8 @@ module.exports = () => {
permanent: true,
},
{
- source: '/reference/operator-guides/adding-kubecost-for-cost-analysis',
+ source:
+ '/reference/operator-guides/adding-kubecost-for-cost-analysis',
destination: '/repositories/kubecost',
permanent: true,
},
@@ -132,8 +140,10 @@ module.exports = () => {
permanent: true,
},
{
- source: '/advanced-topics/dns-setup/creating-dns-zone-in-your-cloud-provider-console',
- destination: '/operations/dns-setup/creating-dns-zone-in-your-cloud-provider-console',
+ source:
+ '/advanced-topics/dns-setup/creating-dns-zone-in-your-cloud-provider-console',
+ destination:
+ '/operations/dns-setup/creating-dns-zone-in-your-cloud-provider-console',
permanent: true,
},
{
@@ -143,7 +153,8 @@ module.exports = () => {
},
{
source: '/advanced-topics/security/secret-management',
- destination: '/getting-started/manage-git-repositories/sharing-git-repositories',
+ destination:
+ '/getting-started/manage-git-repositories/sharing-git-repositories',
permanent: true,
},
{
@@ -172,12 +183,14 @@ module.exports = () => {
permanent: true,
},
{
- source: '/advanced-topics/identity-and-access-management/introduction',
+ source:
+ '/advanced-topics/identity-and-access-management/introduction',
destination: '/operations/auth-access-control',
permanent: true,
},
{
- source: '/advanced-topics/identity-and-access-management/openid-connect',
+ source:
+ '/advanced-topics/identity-and-access-management/openid-connect',
destination: '/operations/auth-access-control/openid-connect',
permanent: true,
},
@@ -187,28 +200,37 @@ module.exports = () => {
permanent: true,
},
{
- source: '/advanced-topics/identity-and-access-management/identity-and-installations',
- destination: '/operations/auth-access-control/identity-and-installations',
+ source:
+ '/advanced-topics/identity-and-access-management/identity-and-installations',
+ destination:
+ '/operations/auth-access-control/identity-and-installations',
permanent: true,
},
{
- source: '/advanced-topics/identity-and-access-management/identity-and-installations/audit-logging',
- destination: '/operations/auth-access-control/identity-and-installations/audit-logging',
+ source:
+ '/advanced-topics/identity-and-access-management/identity-and-installations/audit-logging',
+ destination:
+ '/operations/auth-access-control/identity-and-installations/audit-logging',
permanent: true,
},
{
- source: '/advanced-topics/identity-and-access-management/identity-and-installations/service-accounts',
- destination: '/operations/auth-access-control/identity-and-installations/service-accounts',
+ source:
+ '/advanced-topics/identity-and-access-management/identity-and-installations/service-accounts',
+ destination:
+ '/operations/auth-access-control/identity-and-installations/service-accounts',
permanent: true,
},
{
- source: '/advanced-topics/identity-and-access-management/identity-and-installations/sharing-existing-repos',
- destination: '/getting-started/manage-git-repositories/sharing-git-repository',
+ source:
+ '/advanced-topics/identity-and-access-management/identity-and-installations/sharing-existing-repos',
+ destination:
+ '/getting-started/manage-git-repositories/sharing-git-repository',
permanent: true,
},
{
source: '/reference/workspaces',
- destination: '/getting-started/manage-git-repositories/your-plural-workspace',
+ destination:
+ '/getting-started/manage-git-repositories/your-plural-workspace',
permanent: true,
},
]
diff --git a/package.json b/package.json
index 82929d4f..3b17a710 100644
--- a/package.json
+++ b/package.json
@@ -48,6 +48,7 @@
"graphql": "16.6.0",
"honorable": "0.194.0",
"honorable-theme-default": "0.77.0",
+ "htmlparser2": "9.1.0",
"immer": "10.0.2",
"js-yaml": "4.1.0",
"lodash": "4.17.21",
diff --git a/pages/[...slug].tsx b/pages/[...slug].tsx
new file mode 100644
index 00000000..f6fcd1e8
--- /dev/null
+++ b/pages/[...slug].tsx
@@ -0,0 +1,100 @@
+import fs from 'fs'
+import path from 'path'
+import { type ParsedUrlQuery } from 'querystring'
+
+import { type GetStaticPaths, type GetStaticProps } from 'next'
+
+import MarkdocComponent from '@src/components/MarkdocContent'
+import { readMdFileCached } from '@src/markdoc/mdParser'
+import { type MarkdocPage } from '@src/markdoc/mdSchema'
+
+interface Params extends ParsedUrlQuery {
+ slug: string[]
+}
+
+export default function MarkdocContent({
+ markdoc,
+}: {
+ markdoc: MarkdocPage | null
+}) {
+ return markdoc &&
+}
+
+// Start of Selection
+export const getStaticPaths: GetStaticPaths = async () => {
+ const pagesDirectory = path.join('pages')
+
+ // Recursively get all .md files in the 'pages/' directory
+ function getAllMarkdownFiles(dir: string, files: string[] = []): string[] {
+ const entries = fs.readdirSync(dir, { withFileTypes: true })
+
+ for (const entry of entries) {
+ const fullPath = path.join(dir, entry.name)
+
+ if (entry.isDirectory()) {
+ getAllMarkdownFiles(fullPath, files)
+ } else if (entry.isFile() && entry.name.endsWith('.md')) {
+ files.push(fullPath)
+ }
+ }
+
+ return files
+ }
+
+ const markdownFiles = getAllMarkdownFiles(pagesDirectory)
+
+ const paths = markdownFiles.map((file) => {
+ const relativePath = path.relative(pagesDirectory, file)
+ const parsedPath = path.parse(relativePath)
+
+ // Split the directory into segments
+ const dirSegments = parsedPath.dir ? parsedPath.dir.split(path.sep) : []
+
+ let slug: string[]
+
+ if (parsedPath.name === 'index') slug = dirSegments
+ else slug = [...dirSegments, parsedPath.name]
+
+ return {
+ params: {
+ slug,
+ },
+ }
+ })
+
+ return {
+ paths,
+ fallback: 'blocking',
+ }
+}
+
+export const getStaticProps: GetStaticProps<
+ { markdoc: MarkdocPage | null },
+ Params
+> = async ({ params }) => {
+ if (!params?.slug) {
+ return { notFound: true }
+ }
+
+ const slugPath = params.slug.join('/')
+
+ // check for index.md if slugPath is a
+ const filePath =
+ [
+ path.join('pages', slugPath, 'index.md'),
+ path.join('pages', `${slugPath}.md`),
+ ].find(fs.existsSync) || null
+
+ if (!filePath) {
+ return { notFound: true }
+ }
+ const markdoc = await readMdFileCached(filePath)
+
+ return {
+ props: {
+ displayTitle: markdoc?.frontmatter?.title ?? '',
+ displayDescription: markdoc?.frontmatter?.description ?? '',
+ markdoc,
+ },
+ }
+}
diff --git a/pages/how-to/set-up/mgmt-cluster.md b/pages/how-to/set-up/mgmt-cluster.md
index 935c1300..7c197777 100644
--- a/pages/how-to/set-up/mgmt-cluster.md
+++ b/pages/how-to/set-up/mgmt-cluster.md
@@ -46,4 +46,4 @@ There are a few reasons you'd consider using this over Plural Cloud:
* Integration - Oftentimes resources needed by Plural are themselves hosted on private networks, for instance Git Repositories. In that case, it's logistically easier to self-host and place it in an integrated network.
* Scaling - you want complete control as to how Plural Scales for your enterprise. `dedicated` cloud hosting does this perfectly well too, but some orgs want their own hands on the wheel.
-Plural is meant to be architecturally simple and efficient. Most organizations that do chose to self-host are shocked at how streamlined managing it is, especially compared to some more bloated CNCF projects, so it is a surprisingly viable way to manage the software if that is what your organization desires.
+Plural is meant to be architecturally simple and efficient. Most organizations that do choose to self-host are shocked at how streamlined managing it is, especially compared to some more bloated CNCF projects, so it is a surprisingly viable way to manage the software if that is what your organization desires.
diff --git a/src/generated/graphql.ts b/src/generated/graphql.ts
index 43e155f6..c94cf853 100644
--- a/src/generated/graphql.ts
+++ b/src/generated/graphql.ts
@@ -577,6 +577,8 @@ export type ConsoleInstance = {
status: ConsoleInstanceStatus;
/** the subdomain this instance lives under */
subdomain: Scalars['String']['output'];
+ /** whether this is a shared or dedicated console */
+ type: ConsoleInstanceType;
updatedAt?: Maybe;
/** full console url of this instance */
url: Scalars['String']['output'];
@@ -591,6 +593,8 @@ export type ConsoleInstanceAttributes = {
region: Scalars['String']['input'];
/** a heuristic size of this instance */
size: ConsoleSize;
+ /** the type of console instance */
+ type: ConsoleInstanceType;
};
export type ConsoleInstanceConnection = {
@@ -611,7 +615,14 @@ export enum ConsoleInstanceStatus {
DeploymentCreated = 'DEPLOYMENT_CREATED',
DeploymentDeleted = 'DEPLOYMENT_DELETED',
Pending = 'PENDING',
- Provisioned = 'PROVISIONED'
+ Provisioned = 'PROVISIONED',
+ StackCreated = 'STACK_CREATED',
+ StackDeleted = 'STACK_DELETED'
+}
+
+export enum ConsoleInstanceType {
+ Dedicated = 'DEDICATED',
+ Shared = 'SHARED'
}
export type ConsoleInstanceUpdateAttributes = {
@@ -3390,6 +3401,7 @@ export type RootMutationTypeLinkPublisherArgs = {
export type RootMutationTypeLoginArgs = {
+ captcha?: InputMaybe;
deviceToken?: InputMaybe;
email: Scalars['String']['input'];
password: Scalars['String']['input'];
@@ -4965,6 +4977,7 @@ export type User = {
id: Scalars['ID']['output'];
impersonationPolicy?: Maybe;
insertedAt?: Maybe;
+ intercomId?: Maybe;
invites?: Maybe>>;
jwt?: Maybe;
loginMethod?: Maybe;
diff --git a/src/markdoc/mdParser.ts b/src/markdoc/mdParser.ts
index e6ed96d5..4d2cd6c9 100644
--- a/src/markdoc/mdParser.ts
+++ b/src/markdoc/mdParser.ts
@@ -2,6 +2,7 @@ import { promises as fs } from 'fs'
import path from 'path'
import Markdoc from '@markdoc/markdoc'
+import { Parser } from 'htmlparser2'
import yaml from 'js-yaml'
import { config as schemaConfig } from './mdSchema'
@@ -13,7 +14,7 @@ const fileCache = new Map()
export const readMdFileCached = async (
filePath: string
): Promise => {
- if (!filePath.startsWith('/pages')) {
+ if (!filePath.startsWith('pages')) {
return null
}
function cacheAndReturn(val: MarkdocPage | null) {
@@ -36,10 +37,15 @@ export const readMdFileCached = async (
return cacheAndReturn(null)
}
- const ast = Markdoc.parse(file)
+ const tokenizer = new Markdoc.Tokenizer({ html: true })
+ const tokens = tokenizer.tokenize(file)
+ const processed = processHtmlTokens(tokens)
+ const ast = Markdoc.parse(processed)
+
const frontmatter = ast.attributes.frontmatter
? yaml.load(ast.attributes.frontmatter)
: {}
+
const content = Markdoc.transform(ast, schemaConfig)
const ret: MarkdocPage = JSON.parse(
@@ -47,7 +53,7 @@ export const readMdFileCached = async (
content,
frontmatter,
file: {
- path: filePath.replace(/^\/pages/g, ''),
+ path: filePath.replace(/^pages/g, ''),
},
})
)
@@ -59,3 +65,52 @@ export const readMdFileCached = async (
return cacheAndReturn(null)
}
}
+
+// see https://github.com/markdoc/markdoc/issues/10
+// https://gist.github.com/rpaul-stripe/941eb22c4779ea87b1adf7715d76ca08
+function processHtmlTokens(tokens) {
+ const output: any[] = []
+
+ const parser = new Parser({
+ onopentag(name, attrs) {
+ output.push({
+ type: 'tag_open',
+ nesting: 1,
+ meta: {
+ tag: 'html-tag',
+ attributes: [
+ { type: 'attribute', name: 'name', value: name },
+ { type: 'attribute', name: 'attrs', value: attrs },
+ ],
+ },
+ })
+ },
+
+ ontext(content) {
+ if (typeof content === 'string' && content.trim().length > 0)
+ output.push({ type: 'text', content })
+ },
+
+ onclosetag() {
+ output.push({
+ type: 'tag_close',
+ nesting: -1,
+ meta: { tag: 'html-tag' },
+ })
+ },
+ })
+
+ for (const token of tokens) {
+ if (token.type.startsWith('html')) {
+ parser.write(token.content)
+ continue
+ }
+
+ if (token.type === 'inline')
+ token.children = processHtmlTokens(token.children)
+
+ output.push(token)
+ }
+
+ return output
+}
diff --git a/src/markdoc/mdSchema.ts b/src/markdoc/mdSchema.ts
index 767af09e..1b0e7a28 100644
--- a/src/markdoc/mdSchema.ts
+++ b/src/markdoc/mdSchema.ts
@@ -3,8 +3,8 @@ import merge from 'lodash/merge'
import * as config from './config'
import * as functions from './functions'
-import * as nodes from './nodes'
-import * as tags from './tags'
+import { nodes } from './nodes'
+import { tags } from './tags'
import type { MarkdocNextJsPageProps } from '@markdoc/next.js'
diff --git a/src/markdoc/nodes/index.ts b/src/markdoc/nodes/index.ts
index bb542b91..187c6119 100644
--- a/src/markdoc/nodes/index.ts
+++ b/src/markdoc/nodes/index.ts
@@ -1,2 +1,56 @@
/* Markdoc nodes must be exported from this file to work with markdoc/nextjs plugin */
-export * from '@pluralsh/design-system/dist/markdoc/nodes'
+
+import { Tag } from '@markdoc/markdoc'
+import { Table } from '@pluralsh/design-system/dist/markdoc/components'
+import * as designSystemNodes from '@pluralsh/design-system/dist/markdoc/nodes'
+import { isTag } from '@pluralsh/design-system/dist/markdoc/types'
+
+export const nodes = {
+ ...designSystemNodes,
+ // slight fork of old DS version
+ table: {
+ render: Table,
+ description: 'Display horizontal tabs in a box',
+ children: ['tab'],
+ attributes: {},
+ transform(node, config) {
+ const children = node.transformChildren(config)
+
+ const thead = children
+ .find(
+ (child): child is Tag =>
+ isTag(child) && child?.name.toLowerCase() === 'thead'
+ )
+ ?.children.find(
+ (tr): tr is Tag => isTag(tr) && tr?.name.toLowerCase() === 'tr'
+ )
+ ?.children.filter(
+ (th): th is Tag => isTag(th) && th?.name.toLowerCase() === 'th'
+ )
+ .map((th) => th.children)
+
+ const tbody = children
+ .find(
+ (child): child is Tag =>
+ isTag(child) && child?.name.toLowerCase() === 'tbody'
+ )
+ ?.children.filter(
+ (tr): tr is Tag => isTag(tr) && tr?.name.toLowerCase() === 'tr'
+ )
+ ?.map((tr) =>
+ tr.children
+ .filter(
+ (trChild): trChild is Tag =>
+ isTag(trChild) && trChild?.name.toLowerCase() === 'td'
+ )
+ .map((td) => td.children)
+ )
+
+ return new Tag(
+ this.render as any,
+ { thead, tbody, children },
+ node.transformChildren(config)
+ )
+ },
+ },
+}
diff --git a/src/markdoc/tags/htmlTag.markdoc.js b/src/markdoc/tags/htmlTag.markdoc.js
new file mode 100644
index 00000000..6e284fd4
--- /dev/null
+++ b/src/markdoc/tags/htmlTag.markdoc.js
@@ -0,0 +1,14 @@
+import Markdoc from '@markdoc/markdoc'
+
+export const htmlTag = {
+ attributes: {
+ name: { type: String, required: true },
+ attrs: { type: Object },
+ },
+ transform(node, config) {
+ const { name, attrs } = node.attributes
+ const children = node.transformChildren(config)
+
+ return new Markdoc.Tag(name, attrs, children)
+ },
+}
diff --git a/src/markdoc/tags/index.ts b/src/markdoc/tags/index.ts
index 1a3c70c4..ea6a351f 100644
--- a/src/markdoc/tags/index.ts
+++ b/src/markdoc/tags/index.ts
@@ -1,5 +1,13 @@
-/* Markdoc tags must be exported from this file to work with markdoc/nextjs plugin */
-/* Use this file to export your markdoc tags */
+import * as designSystemTags from '@pluralsh/design-system/dist/markdoc/tags'
-export * from '@pluralsh/design-system/dist/markdoc/tags'
-export { comment, head, script, link } from './nextjs.markdoc'
+import { htmlTag } from './htmlTag.markdoc'
+import { comment, head, link, script } from './nextjs.markdoc'
+
+export const tags = {
+ ...designSystemTags,
+ comment,
+ head,
+ script,
+ link,
+ 'html-tag': htmlTag,
+}
diff --git a/yarn.lock b/yarn.lock
index 05021be5..d010752f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6950,6 +6950,44 @@ __metadata:
languageName: node
linkType: hard
+"dom-serializer@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "dom-serializer@npm:2.0.0"
+ dependencies:
+ domelementtype: ^2.3.0
+ domhandler: ^5.0.2
+ entities: ^4.2.0
+ checksum: cd1810544fd8cdfbd51fa2c0c1128ec3a13ba92f14e61b7650b5de421b88205fd2e3f0cc6ace82f13334114addb90ed1c2f23074a51770a8e9c1273acbc7f3e6
+ languageName: node
+ linkType: hard
+
+"domelementtype@npm:^2.3.0":
+ version: 2.3.0
+ resolution: "domelementtype@npm:2.3.0"
+ checksum: ee837a318ff702622f383409d1f5b25dd1024b692ef64d3096ff702e26339f8e345820f29a68bcdcea8cfee3531776b3382651232fbeae95612d6f0a75efb4f6
+ languageName: node
+ linkType: hard
+
+"domhandler@npm:^5.0.2, domhandler@npm:^5.0.3":
+ version: 5.0.3
+ resolution: "domhandler@npm:5.0.3"
+ dependencies:
+ domelementtype: ^2.3.0
+ checksum: 0f58f4a6af63e6f3a4320aa446d28b5790a009018707bce2859dcb1d21144c7876482b5188395a188dfa974238c019e0a1e610d2fc269a12b2c192ea2b0b131c
+ languageName: node
+ linkType: hard
+
+"domutils@npm:^3.1.0":
+ version: 3.1.0
+ resolution: "domutils@npm:3.1.0"
+ dependencies:
+ dom-serializer: ^2.0.0
+ domelementtype: ^2.3.0
+ domhandler: ^5.0.3
+ checksum: e5757456ddd173caa411cfc02c2bb64133c65546d2c4081381a3bafc8a57411a41eed70494551aa58030be9e58574fcc489828bebd673863d39924fb4878f416
+ languageName: node
+ linkType: hard
+
"dot-case@npm:^3.0.4":
version: 3.0.4
resolution: "dot-case@npm:3.0.4"
@@ -7037,6 +7075,13 @@ __metadata:
languageName: node
linkType: hard
+"entities@npm:^4.2.0, entities@npm:^4.5.0":
+ version: 4.5.0
+ resolution: "entities@npm:4.5.0"
+ checksum: 853f8ebd5b425d350bffa97dd6958143179a5938352ccae092c62d1267c4e392a039be1bae7d51b6e4ffad25f51f9617531fedf5237f15df302ccfb452cbf2d7
+ languageName: node
+ linkType: hard
+
"env-paths@npm:^2.2.0":
version: 2.2.1
resolution: "env-paths@npm:2.2.1"
@@ -8539,6 +8584,18 @@ __metadata:
languageName: node
linkType: hard
+"htmlparser2@npm:9.1.0":
+ version: 9.1.0
+ resolution: "htmlparser2@npm:9.1.0"
+ dependencies:
+ domelementtype: ^2.3.0
+ domhandler: ^5.0.3
+ domutils: ^3.1.0
+ entities: ^4.5.0
+ checksum: e5f8d5193967e4a500226f37bdf2c0f858cecb39dde14d0439f24bf2c461a4342778740d988fbaba652b0e4cb6052f7f2e99e69fc1a329a86c629032bb76e7c8
+ languageName: node
+ linkType: hard
+
"http-cache-semantics@npm:^4.1.0":
version: 4.1.0
resolution: "http-cache-semantics@npm:4.1.0"
@@ -12069,6 +12126,7 @@ __metadata:
graphql: 16.6.0
honorable: 0.194.0
honorable-theme-default: 0.77.0
+ htmlparser2: 9.1.0
husky: 8.0.3
immer: 10.0.2
js-yaml: 4.1.0