279 lines
9.7 KiB
TypeScript
279 lines
9.7 KiB
TypeScript
import { XCircleIcon } from '@heroicons/react/solid';
|
|
import { getSchemaFromReference } from '@nrwl/nx-dev/data-access-packages';
|
|
import { JsonSchema1, NxSchema } from '@nrwl/nx-dev/models-package';
|
|
import { renderMarkdown } from '@nrwl/nx-dev/ui-markdoc';
|
|
import Link from 'next/link';
|
|
import { useRouter } from 'next/router';
|
|
import React, { ReactNode, useState } from 'react';
|
|
import { generateJsonExampleFor, isErrors } from './examples';
|
|
import { SchemaViewModel } from './get-schema-view-model';
|
|
import { SchemaEditor } from './schema-editor';
|
|
import { SchemaViewer } from './schema-viewer';
|
|
import { Heading2, Heading3 } from './ui/headings';
|
|
|
|
function pathCleaner(path: string): string {
|
|
return path.split('?')[0];
|
|
}
|
|
|
|
export function Content({
|
|
schemaViewModel,
|
|
}: {
|
|
schemaViewModel: SchemaViewModel;
|
|
}) {
|
|
if (!schemaViewModel.currentSchema)
|
|
throw new Error(
|
|
'A valid schema has to be defined for the "currentSchema" property'
|
|
);
|
|
|
|
const router = useRouter();
|
|
const [presets, setPresets] = useState<string[]>([]);
|
|
const filterWithPresets = (
|
|
data: Record<string, any>,
|
|
wantedProperties: string[]
|
|
): Record<string, any> => {
|
|
const result: Record<string, any> = {};
|
|
|
|
if (!wantedProperties.length) return data;
|
|
|
|
for (const p in data) {
|
|
if (wantedProperties.includes(p)) {
|
|
result[p] = data[p];
|
|
}
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
const vm = {
|
|
get fullExample(): Record<string, any> {
|
|
const examples = generateJsonExampleFor(
|
|
schemaViewModel.currentSchema as NxSchema,
|
|
schemaViewModel.lookup,
|
|
'both'
|
|
);
|
|
return isErrors(examples) ? {} : examples.value;
|
|
},
|
|
get pages(): { name: string; href: string; current: boolean }[] {
|
|
return [
|
|
{
|
|
name: schemaViewModel.packageName,
|
|
href: schemaViewModel.packageUrl,
|
|
current: false,
|
|
},
|
|
{
|
|
name: schemaViewModel.schemaMetadata.name,
|
|
href: pathCleaner(router.asPath),
|
|
current: !schemaViewModel.subReference,
|
|
},
|
|
!!schemaViewModel.subReference
|
|
? {
|
|
name: schemaViewModel.subReference.split('/')[2],
|
|
href: pathCleaner(router.asPath),
|
|
current: true,
|
|
}
|
|
: void 0,
|
|
].filter(
|
|
(x): x is { name: string; href: string; current: boolean } => !!x
|
|
);
|
|
},
|
|
get markdown(): ReactNode {
|
|
return renderMarkdown({
|
|
content: getMarkdown({
|
|
type: schemaViewModel.type,
|
|
packageName: schemaViewModel.packageName,
|
|
schemaName: schemaViewModel.schemaMetadata.name,
|
|
schemaAlias: schemaViewModel.schemaMetadata.aliases[0] ?? '',
|
|
schema: schemaViewModel.currentSchema as NxSchema,
|
|
}),
|
|
filePath: '',
|
|
data: {},
|
|
});
|
|
},
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<div className="min-w-0 flex-auto pt-8 pb-24 lg:pb-16">
|
|
<div className="mb-8 flex w-full items-center space-x-2">
|
|
<div className="w-full flex-grow">
|
|
<div
|
|
aria-hidden="true"
|
|
data-tooltip="Schema type"
|
|
className="relative inline-flex rounded-md border border-gray-200 bg-white px-4 py-2 text-xs font-medium uppercase text-gray-600"
|
|
>
|
|
{schemaViewModel.type}
|
|
</div>
|
|
</div>
|
|
<div className="relative z-0 inline-flex flex-shrink-0 rounded-md shadow-sm">
|
|
<Link href={schemaViewModel.packageUrl}>
|
|
<a
|
|
title="See package information"
|
|
className="focus:ring-blue-nx-base focus:border-blue-nx-base relative inline-flex items-center rounded-l-md border border-gray-200 bg-white px-4 py-2 text-xs font-medium text-gray-600 hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-1"
|
|
>
|
|
{schemaViewModel.packageName}
|
|
</a>
|
|
</Link>
|
|
<a
|
|
href={schemaViewModel.schemaGithubUrl}
|
|
target="_blank"
|
|
rel="noreferrer"
|
|
title="See this schema on Github"
|
|
className="focus:ring-blue-nx-base focus:border-blue-nx-base relative -ml-px inline-flex items-center rounded-r-md border border-gray-200 bg-white px-4 py-2 text-xs font-medium text-gray-600 hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-1"
|
|
>
|
|
See schema on Github
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
{/* We remove the top description on sub property lookup */}
|
|
{!schemaViewModel.subReference && (
|
|
<>
|
|
<div className="prose max-w-none">{vm.markdown}</div>
|
|
<div className="h-12">{/* SPACER */}</div>
|
|
</>
|
|
)}
|
|
|
|
{/*TODO@ben: create new component*/}
|
|
{schemaViewModel.type === 'executors' && !schemaViewModel.subReference && (
|
|
<div className="mt-8 hidden md:block">
|
|
<Heading2 title="Options playground" />
|
|
<p className="my-6">
|
|
Try out this interactive editor of the configuration object.
|
|
Values are validated as you type and hovering over labels will
|
|
give you more information.
|
|
</p>
|
|
{!!schemaViewModel.currentSchema.presets.length && (
|
|
<>
|
|
<Heading3 title="Examples" />
|
|
<p className="my-4">
|
|
These buttons show the config object for specific common
|
|
tasks.
|
|
</p>
|
|
<div className="mb-4 flex flex-wrap gap-4">
|
|
{schemaViewModel.currentSchema.presets.map((p) => (
|
|
<button
|
|
key={'preset-' + p.name.toLowerCase()}
|
|
onClick={() => {
|
|
setPresets(p.keys);
|
|
}}
|
|
type="button"
|
|
className="focus:border-blue-nx-base focus:ring-blue-nx-base relative inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-1"
|
|
>
|
|
{p.name}
|
|
</button>
|
|
))}
|
|
{!!presets.length && (
|
|
<button
|
|
onClick={() => setPresets([])}
|
|
type="button"
|
|
className="focus:border-blue-nx-base focus:ring-blue-nx-base relative inline-flex items-center rounded-md border border-gray-200 bg-gray-50 px-2 py-1 text-xs font-medium text-gray-500 hover:bg-gray-100 focus:z-10 focus:outline-none focus:ring-1"
|
|
>
|
|
Reset <XCircleIcon className="ml-1.5 h-4 w-4" />
|
|
</button>
|
|
)}
|
|
</div>
|
|
</>
|
|
)}
|
|
<div className="rounded-md border border-gray-300 p-1">
|
|
<SchemaEditor
|
|
packageName={schemaViewModel.packageName}
|
|
schemaName={schemaViewModel.schemaMetadata.name}
|
|
type={schemaViewModel.type.replace('s', '') as any}
|
|
content={filterWithPresets(vm.fullExample, presets)}
|
|
schema={schemaViewModel.currentSchema}
|
|
/>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<div className="mt-8">
|
|
<Heading2 title="Options" />
|
|
{!schemaViewModel.subReference && (
|
|
<SchemaViewer
|
|
schema={schemaViewModel.currentSchema}
|
|
lookup={schemaViewModel.lookup}
|
|
reference="#"
|
|
stage={'both'}
|
|
/>
|
|
)}
|
|
{schemaViewModel.subReference && (
|
|
<SchemaViewer
|
|
schema={
|
|
getSchemaFromReference(
|
|
schemaViewModel.subReference,
|
|
schemaViewModel.lookup
|
|
) as JsonSchema1
|
|
}
|
|
lookup={schemaViewModel.lookup}
|
|
reference={schemaViewModel.subReference}
|
|
stage={'both'}
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|
|
|
|
const getMarkdown = (data: {
|
|
packageName: string;
|
|
schemaAlias: string;
|
|
schemaName: string;
|
|
schema: NxSchema;
|
|
type: 'executors' | 'generators';
|
|
}): string => {
|
|
const hasExamplesFile = !!data.schema['examplesFile'];
|
|
const executorNotice: string = `Options can be configured in \`project.json\` when defining the executor, or when invoking it. Read more about how to configure targets and executors here: [https://nx.dev/configuration/projectjson#targets](https://nx.dev/configuration/projectjson#targets).`;
|
|
|
|
return [
|
|
`# ${data.packageName}:${data.schemaName}`,
|
|
`\n\n`,
|
|
data.schema.description,
|
|
'\n\n',
|
|
data.type === 'executors' ? executorNotice : '',
|
|
`\n\n`,
|
|
hasExamplesFile ? data.schema['examplesFile'] : '',
|
|
data.type === 'generators'
|
|
? hasExamplesFile
|
|
? data.schema['examplesFile']
|
|
: getUsage(data.packageName, data.schemaName, data.schemaAlias)
|
|
: '',
|
|
!!data.schema['examples']
|
|
? `### Examples \n ${data.schema['examples']
|
|
.map(
|
|
(e: any) => `${e.description}: \n \`\`\`bash\n${e.command}\n\`\`\``
|
|
)
|
|
.join('\n')}`
|
|
: '',
|
|
`\n\n`,
|
|
].join('');
|
|
};
|
|
|
|
const getUsage = (
|
|
packageName: string,
|
|
schemaName: string,
|
|
schemaAlias: string
|
|
): string => `
|
|
## Usage
|
|
\`\`\`bash
|
|
nx generate ${schemaName} ...
|
|
\`\`\`
|
|
${!!schemaAlias ? `\`\`\`bash\nnx g ${schemaAlias} ... #same\n\`\`\`\n` : ''}
|
|
|
|
By default, Nx will search for \`${schemaName}\` in the default collection provisioned in workspace.json.
|
|
|
|
You can specify the collection explicitly as follows:
|
|
|
|
\`\`\`bash
|
|
nx g ${packageName}:${schemaName} ...
|
|
\`\`\`
|
|
|
|
Show what will be generated without writing to disk:
|
|
|
|
\`\`\`bash
|
|
nx g ${schemaName} ... --dry-run
|
|
\`\`\`
|
|
`;
|
|
|
|
export default Content;
|