feat(v2): docs options.onlyIncludeVersions (#3373)

* docs options.onlyIncludeVersions

* adapt docsVersionDropdown if we render a single version

* fix bad error message

* fix netlify deploy when versioning is disabled
This commit is contained in:
Sébastien Lorber 2020-08-31 17:08:24 +02:00 committed by GitHub
parent 149d82c730
commit d8cfabb66a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 144 additions and 22 deletions

View file

@ -146,7 +146,7 @@ describe('simple site', () => {
context: defaultContext, context: defaultContext,
}), }),
).toThrowErrorMatchingInlineSnapshot( ).toThrowErrorMatchingInlineSnapshot(
`"Docs versions option provided configuration for unknown versions: unknownVersionName1,unknownVersionName2. Available version names are: current"`, `"Bad docs options.versions: unknown versions found: unknownVersionName1,unknownVersionName2. Available version names are: current"`,
); );
}); });
@ -297,6 +297,19 @@ describe('versioned site, pluginId=default', () => {
]); ]);
}); });
test('readVersionsMetadata versioned site with onlyIncludeVersions option', () => {
const versionsMetadata = readVersionsMetadata({
options: {
...defaultOptions,
// Order reversed on purpose: should not have any impact
onlyIncludeVersions: [vwithSlugs.versionName, v101.versionName],
},
context: defaultContext,
});
expect(versionsMetadata).toEqual([v101, vwithSlugs]);
});
test('readVersionsMetadata versioned site with disableVersioning', () => { test('readVersionsMetadata versioned site with disableVersioning', () => {
const versionsMetadata = readVersionsMetadata({ const versionsMetadata = readVersionsMetadata({
options: {...defaultOptions, disableVersioning: true}, options: {...defaultOptions, disableVersioning: true},
@ -323,6 +336,49 @@ describe('versioned site, pluginId=default', () => {
); );
}); });
test('readVersionsMetadata versioned site with empty onlyIncludeVersions', () => {
expect(() =>
readVersionsMetadata({
options: {
...defaultOptions,
onlyIncludeVersions: [],
},
context: defaultContext,
}),
).toThrowErrorMatchingInlineSnapshot(
`"Bad docs options.onlyIncludeVersions: an empty array is not allowed, at least one version is needed"`,
);
});
test('readVersionsMetadata versioned site with unknown versions in onlyIncludeVersions', () => {
expect(() =>
readVersionsMetadata({
options: {
...defaultOptions,
onlyIncludeVersions: ['unknownVersion1', 'unknownVersion2'],
},
context: defaultContext,
}),
).toThrowErrorMatchingInlineSnapshot(
`"Bad docs options.onlyIncludeVersions: unknown versions found: unknownVersion1,unknownVersion2. Available version names are: current, 1.0.1, 1.0.0, withSlugs"`,
);
});
test('readVersionsMetadata versioned site with lastVersion not in onlyIncludeVersions', () => {
expect(() =>
readVersionsMetadata({
options: {
...defaultOptions,
lastVersion: '1.0.1',
onlyIncludeVersions: ['current', '1.0.0'],
},
context: defaultContext,
}),
).toThrowErrorMatchingInlineSnapshot(
`"Bad docs options.lastVersion: if you use both the onlyIncludeVersions and lastVersion options, then lastVersion must be present in the provided onlyIncludeVersions array"`,
);
});
test('readVersionsMetadata versioned site with invalid versions.json file', () => { test('readVersionsMetadata versioned site with invalid versions.json file', () => {
const mock = jest.spyOn(JSON, 'parse').mockImplementationOnce(() => { const mock = jest.spyOn(JSON, 'parse').mockImplementationOnce(() => {
return { return {

View file

@ -68,6 +68,7 @@ export const OptionsSchema = Joi.object({
includeCurrentVersion: Joi.bool().default( includeCurrentVersion: Joi.bool().default(
DEFAULT_OPTIONS.includeCurrentVersion, DEFAULT_OPTIONS.includeCurrentVersion,
), ),
onlyIncludeVersions: Joi.array().items(Joi.string().required()).optional(),
disableVersioning: Joi.bool().default(DEFAULT_OPTIONS.disableVersioning), disableVersioning: Joi.bool().default(DEFAULT_OPTIONS.disableVersioning),
lastVersion: Joi.string().optional(), lastVersion: Joi.string().optional(),
versions: VersionsOptionsSchema, versions: VersionsOptionsSchema,

View file

@ -47,6 +47,7 @@ export type VersionOptions = {
export type VersionsOptions = { export type VersionsOptions = {
lastVersion?: string; lastVersion?: string;
versions: Record<string, VersionOptions>; versions: Record<string, VersionOptions>;
onlyIncludeVersions?: string[];
}; };
export type PluginOptions = MetadataOptions & export type PluginOptions = MetadataOptions &

View file

@ -257,17 +257,60 @@ function checkVersionsOptions(
`Docs option lastVersion=${options.lastVersion} is invalid. ${availableVersionNamesMsg}`, `Docs option lastVersion=${options.lastVersion} is invalid. ${availableVersionNamesMsg}`,
); );
} }
const unknownVersionNames = difference( const unknownVersionConfigNames = difference(
Object.keys(options.versions), Object.keys(options.versions),
availableVersionNames, availableVersionNames,
); );
if (unknownVersionNames.length > 0) { if (unknownVersionConfigNames.length > 0) {
throw new Error( throw new Error(
`Docs versions option provided configuration for unknown versions: ${unknownVersionNames.join( `Bad docs options.versions: unknown versions found: ${unknownVersionConfigNames.join(
',', ',',
)}. ${availableVersionNamesMsg}`, )}. ${availableVersionNamesMsg}`,
); );
} }
if (options.onlyIncludeVersions) {
if (options.onlyIncludeVersions.length === 0) {
throw new Error(
`Bad docs options.onlyIncludeVersions: an empty array is not allowed, at least one version is needed`,
);
}
const unknownOnlyIncludeVersionNames = difference(
options.onlyIncludeVersions,
availableVersionNames,
);
if (unknownOnlyIncludeVersionNames.length > 0) {
throw new Error(
`Bad docs options.onlyIncludeVersions: unknown versions found: ${unknownOnlyIncludeVersionNames.join(
',',
)}. ${availableVersionNamesMsg}`,
);
}
if (
options.lastVersion &&
!options.onlyIncludeVersions.includes(options.lastVersion)
) {
throw new Error(
`Bad docs options.lastVersion: if you use both the onlyIncludeVersions and lastVersion options, then lastVersion must be present in the provided onlyIncludeVersions array`,
);
}
}
}
// Filter versions according to provided options
// Note: we preserve the order in which versions are provided
// the order of the onlyIncludeVersions array does not matter
function filterVersions(
versionNamesUnfiltered: string[],
options: Pick<PluginOptions, 'onlyIncludeVersions'>,
) {
if (options.onlyIncludeVersions) {
return versionNamesUnfiltered.filter((name) =>
options.onlyIncludeVersions!.includes(name),
);
} else {
return versionNamesUnfiltered;
}
} }
export function readVersionsMetadata({ export function readVersionsMetadata({
@ -285,11 +328,14 @@ export function readVersionsMetadata({
| 'disableVersioning' | 'disableVersioning'
| 'lastVersion' | 'lastVersion'
| 'versions' | 'versions'
| 'onlyIncludeVersions'
>; >;
}): VersionMetadata[] { }): VersionMetadata[] {
const versionNames = readVersionNames(context.siteDir, options); const versionNamesUnfiltered = readVersionNames(context.siteDir, options);
checkVersionsOptions(versionNames, options); checkVersionsOptions(versionNamesUnfiltered, options);
const versionNames = filterVersions(versionNamesUnfiltered, options);
const lastVersionName = const lastVersionName =
options.lastVersion ?? getDefaultLastVersionName(versionNames); options.lastVersion ?? getDefaultLastVersionName(versionNames);

View file

@ -26,19 +26,28 @@ export default function DocsVersionDropdownNavbarItem({
const versions = useVersions(docsPluginId); const versions = useVersions(docsPluginId);
const latestVersion = useLatestVersion(docsPluginId); const latestVersion = useLatestVersion(docsPluginId);
const items = versions.map((version) => { function getItems() {
// We try to link to the same doc, in another version // We don't want to render a version dropdown with 0 or 1 item
// When not possible, fallback to the "main doc" of the version // If we build the site with a single docs version (onlyIncludeVersions: ['1.0.0'])
const versionDoc = // We'd rather render a buttonb instead of a dropdown
activeDocContext?.alternateDocVersions[version.name] || if (versions.length <= 2) {
getVersionMainDoc(version); return undefined;
return { }
isNavLink: true,
label: version.label, return versions.map((version) => {
to: versionDoc.path, // We try to link to the same doc, in another version
isActive: () => version === activeDocContext?.activeVersion, // When not possible, fallback to the "main doc" of the version
}; const versionDoc =
}); activeDocContext?.alternateDocVersions[version.name] ||
getVersionMainDoc(version);
return {
isNavLink: true,
label: version.label,
to: versionDoc.path,
isActive: () => version === activeDocContext?.activeVersion,
};
});
}
const dropdownVersion = activeDocContext.activeVersion ?? latestVersion; const dropdownVersion = activeDocContext.activeVersion ?? latestVersion;
@ -54,7 +63,7 @@ export default function DocsVersionDropdownNavbarItem({
mobile={mobile} mobile={mobile}
label={dropdownLabel} label={dropdownLabel}
to={dropdownTo} to={dropdownTo}
items={items} items={getItems()}
/> />
); );
} }

View file

@ -362,6 +362,11 @@ module.exports = {
}, },
*/ */
}, },
/**
* Sometimes you only want to include a subset of all available versions.
* Tip: limit to 2 or 3 versions to improve startup and build time in dev and deploy previews
*/
onlyIncludeVersions: undefined, // ex: ["current", "1.0.0", "2.0.0"]
}, },
], ],
], ],

View file

@ -178,6 +178,10 @@ module.exports = {
remarkPlugins: [require('./src/plugins/remark-npm2yarn')], remarkPlugins: [require('./src/plugins/remark-npm2yarn')],
disableVersioning: isVersioningDisabled, disableVersioning: isVersioningDisabled,
lastVersion: isDev || isDeployPreview ? 'current' : undefined, lastVersion: isDev || isDeployPreview ? 'current' : undefined,
onlyIncludeVersions:
!isVersioningDisabled && (isDev || isDeployPreview)
? ['current', ...versions.slice(0, 2)]
: undefined,
versions: { versions: {
current: { current: {
// path: isDev || isDeployPreview ? '' : 'next', // path: isDev || isDeployPreview ? '' : 'next',

View file

@ -17722,7 +17722,7 @@ react-dev-utils@^9.1.0:
strip-ansi "5.2.0" strip-ansi "5.2.0"
text-table "0.2.0" text-table "0.2.0"
react-dom@^16.10.2, react-dom@^16.8.4: react-dom@^16.8.4:
version "16.13.1" version "16.13.1"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f"
integrity sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag== integrity sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==
@ -17902,7 +17902,7 @@ react-waypoint@^9.0.2:
prop-types "^15.0.0" prop-types "^15.0.0"
react-is "^16.6.3" react-is "^16.6.3"
react@^16.10.2, react@^16.8.4: react@^16.8.4:
version "16.13.1" version "16.13.1"
resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e" resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e"
integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w== integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==