Migrate techdocs-cli-embedded-app to NFS
Signed-off-by: Gabriel Dugny <gabriel.dugny@believe.com>
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs': minor
|
||||
---
|
||||
|
||||
Add 2 config elements to extension "page:techdocs/reader" to configure default layout `withSearch` and `withHeader`. Default are unchanged to `true`.
|
||||
|
||||
E.g. to disable the search and header on the Techdocs Reader Page:
|
||||
|
||||
```yaml
|
||||
app:
|
||||
extensions:
|
||||
- page:techdocs/reader:
|
||||
config:
|
||||
withSearch: false
|
||||
withHeader: false
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@techdocs/cli': patch
|
||||
---
|
||||
|
||||
Migrate the Techdocs CLI embedded app to the New Frontend System (NFS)
|
||||
@@ -1,6 +1,11 @@
|
||||
app:
|
||||
title: Techdocs Preview App
|
||||
baseUrl: http://localhost:3000
|
||||
extensions:
|
||||
- sign-in-page:app: false
|
||||
- page:techdocs/reader:
|
||||
config:
|
||||
withSearch: false
|
||||
|
||||
backend:
|
||||
baseUrl: http://localhost:3000
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (2)
|
||||
## Unused devDependencies (2)
|
||||
|
||||
| Name | Location | Severity |
|
||||
| :-------- | :----------- | :------- |
|
||||
| react-use | packages/techdocs-cli-embedded-app/package.json | error |
|
||||
| history | packages/techdocs-cli-embedded-app/package.json | error |
|
||||
|
||||
## Unused devDependencies (3)
|
||||
|
||||
| Name | Location | Severity |
|
||||
| :-------------------------- | :----------- | :------- |
|
||||
| @testing-library/user-event | packages/techdocs-cli-embedded-app/package.json | error |
|
||||
| @testing-library/dom | packages/techdocs-cli-embedded-app/package.json | error |
|
||||
| cross-env | packages/techdocs-cli-embedded-app/package.json | error |
|
||||
| Name | Location | Severity |
|
||||
| :-------------------------- | :---------------- | :------- |
|
||||
| @testing-library/user-event | package.json:61:6 | error |
|
||||
| cross-env | package.json:64:6 | error |
|
||||
|
||||
|
||||
@@ -32,13 +32,13 @@
|
||||
},
|
||||
"prettier": "@backstage/cli/config/prettier",
|
||||
"dependencies": {
|
||||
"@backstage/app-defaults": "workspace:^",
|
||||
"@backstage/catalog-model": "workspace:^",
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@backstage/config": "workspace:^",
|
||||
"@backstage/core-app-api": "workspace:^",
|
||||
"@backstage/core-components": "workspace:^",
|
||||
"@backstage/core-plugin-api": "workspace:^",
|
||||
"@backstage/frontend-defaults": "workspace:^",
|
||||
"@backstage/frontend-plugin-api": "workspace:^",
|
||||
"@backstage/integration-react": "workspace:^",
|
||||
"@backstage/plugin-catalog": "workspace:^",
|
||||
"@backstage/plugin-techdocs": "workspace:^",
|
||||
@@ -48,11 +48,9 @@
|
||||
"@backstage/ui": "workspace:^",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"history": "^5.0.0",
|
||||
"react": "^18.0.2",
|
||||
"react-dom": "^18.0.2",
|
||||
"react-router-dom": "^6.3.0",
|
||||
"react-use": "^17.2.4"
|
||||
"react-router-dom": "^6.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^",
|
||||
|
||||
@@ -15,13 +15,27 @@
|
||||
*/
|
||||
|
||||
import { renderWithEffects } from '@backstage/test-utils';
|
||||
import App from './App';
|
||||
import app from './App';
|
||||
|
||||
jest.mock('./config', () => ({
|
||||
configLoader: async () => [
|
||||
{
|
||||
data: {
|
||||
app: { title: 'Test' },
|
||||
app: {
|
||||
title: 'Test',
|
||||
extensions: [
|
||||
{
|
||||
'sign-in-page:app': false,
|
||||
},
|
||||
{
|
||||
'page:techdocs/reader': {
|
||||
config: {
|
||||
withSearch: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
backend: { baseUrl: 'http://localhost:7007' },
|
||||
techdocs: {
|
||||
storageUrl: 'http://localhost:7007/api/techdocs/static/docs',
|
||||
@@ -34,7 +48,7 @@ jest.mock('./config', () => ({
|
||||
|
||||
describe('App', () => {
|
||||
it('should render', async () => {
|
||||
const rendered = await renderWithEffects(<App />);
|
||||
const rendered = await renderWithEffects(app);
|
||||
expect(rendered.getByText('Docs Preview')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,85 +14,41 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Navigate, Route } from 'react-router-dom';
|
||||
import techdocsPlugin from '@backstage/plugin-techdocs/alpha';
|
||||
|
||||
import {
|
||||
DefaultTechDocsHome,
|
||||
TechDocsIndexPage,
|
||||
TechDocsReaderPage,
|
||||
techdocsPlugin,
|
||||
} from '@backstage/plugin-techdocs';
|
||||
import {
|
||||
createTechDocsAddonExtension,
|
||||
TechDocsAddons,
|
||||
TechDocsAddonLocations,
|
||||
} from '@backstage/plugin-techdocs-react';
|
||||
import { createApp } from '@backstage/app-defaults';
|
||||
import { FlatRoutes } from '@backstage/core-app-api';
|
||||
import { CatalogEntityPage } from '@backstage/plugin-catalog';
|
||||
import { createApp } from '@backstage/frontend-defaults';
|
||||
import { ConfigReader } from '@backstage/core-app-api';
|
||||
import catalogPlugin from '@backstage/plugin-catalog/alpha';
|
||||
|
||||
import { apis } from './apis';
|
||||
import * as plugins from './plugins';
|
||||
import { configLoader } from './config';
|
||||
import { Root } from './components/Root';
|
||||
import { techDocsPage, TechDocsThemeToggle } from './components/TechDocsPage';
|
||||
import { TechDocsLiveReload } from './LiveReloadAddon';
|
||||
|
||||
const app = createApp({
|
||||
apis,
|
||||
configLoader,
|
||||
plugins: Object.values(plugins),
|
||||
import { createFrontendModule } from '@backstage/frontend-plugin-api';
|
||||
import { SidebarContent } from './components/Root/Root';
|
||||
import {
|
||||
techDocsThemeToggleAddonModule,
|
||||
techdocsLiveReloadAddonModule,
|
||||
} from './addons';
|
||||
|
||||
const appPlugin = createFrontendModule({
|
||||
pluginId: 'app',
|
||||
extensions: [...apis, SidebarContent],
|
||||
});
|
||||
|
||||
const AppProvider = app.getProvider();
|
||||
const AppRouter = app.getRouter();
|
||||
const app = createApp({
|
||||
features: [
|
||||
appPlugin,
|
||||
techdocsPlugin,
|
||||
catalogPlugin,
|
||||
techDocsThemeToggleAddonModule,
|
||||
techdocsLiveReloadAddonModule,
|
||||
],
|
||||
advanced: {
|
||||
async configLoader() {
|
||||
const appConfigs = await configLoader();
|
||||
return { config: ConfigReader.fromConfigs(appConfigs) };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const ThemeToggleAddon = techdocsPlugin.provide(
|
||||
createTechDocsAddonExtension({
|
||||
name: 'ThemeToggleAddon',
|
||||
component: TechDocsThemeToggle,
|
||||
location: TechDocsAddonLocations.Header,
|
||||
}),
|
||||
);
|
||||
|
||||
const LiveReloadAddon = techdocsPlugin.provide(
|
||||
createTechDocsAddonExtension({
|
||||
name: 'LiveReloadAddon',
|
||||
component: TechDocsLiveReload,
|
||||
location: TechDocsAddonLocations.Content,
|
||||
}),
|
||||
);
|
||||
|
||||
const routes = (
|
||||
<FlatRoutes>
|
||||
<Navigate key="/" to="/docs/default/component/local/" />
|
||||
{/* we need this route as TechDocs header links relies on it */}
|
||||
<Route
|
||||
path="/catalog/:namespace/:kind/:name"
|
||||
element={<CatalogEntityPage />}
|
||||
/>
|
||||
<Route path="/docs" element={<TechDocsIndexPage />}>
|
||||
<DefaultTechDocsHome />
|
||||
</Route>
|
||||
<Route
|
||||
path="/docs/:namespace/:kind/:name/*"
|
||||
element={<TechDocsReaderPage />}
|
||||
>
|
||||
{techDocsPage}
|
||||
<TechDocsAddons>
|
||||
<LiveReloadAddon />
|
||||
<ThemeToggleAddon />
|
||||
</TechDocsAddons>
|
||||
</Route>
|
||||
</FlatRoutes>
|
||||
);
|
||||
|
||||
const App = () => (
|
||||
<AppProvider>
|
||||
<AppRouter>
|
||||
<Root>{routes}</Root>
|
||||
</AppRouter>
|
||||
</AppProvider>
|
||||
);
|
||||
|
||||
export default App;
|
||||
export default app.createRoot();
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2026 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { AddonBlueprint } from '@backstage/plugin-techdocs-react/alpha';
|
||||
import { TechDocsAddonLocations } from '@backstage/plugin-techdocs-react';
|
||||
import { createFrontendModule } from '@backstage/frontend-plugin-api';
|
||||
import { TechDocsThemeToggle } from './components/TechDocsPage';
|
||||
import { TechDocsLiveReload } from './components/LiveReload/LiveReloadAddon';
|
||||
|
||||
const techDocsThemeToggleAddonExtension = AddonBlueprint.make({
|
||||
name: 'techdocs-theme-toggle-addon',
|
||||
params: {
|
||||
name: 'ThemeToggleAddon',
|
||||
component: TechDocsThemeToggle,
|
||||
location: TechDocsAddonLocations.Header,
|
||||
},
|
||||
});
|
||||
|
||||
export const techDocsThemeToggleAddonModule = createFrontendModule({
|
||||
pluginId: 'techdocs',
|
||||
extensions: [techDocsThemeToggleAddonExtension],
|
||||
});
|
||||
|
||||
const techdocsLiveReloadAddonExtension = AddonBlueprint.make({
|
||||
name: 'techdocs-live-reload-addon',
|
||||
params: {
|
||||
name: 'LiveReloadAddon',
|
||||
component: TechDocsLiveReload,
|
||||
location: TechDocsAddonLocations.Content,
|
||||
},
|
||||
});
|
||||
|
||||
export const techdocsLiveReloadAddonModule = createFrontendModule({
|
||||
pluginId: 'techdocs',
|
||||
extensions: [techdocsLiveReloadAddonExtension],
|
||||
});
|
||||
@@ -13,6 +13,14 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import {
|
||||
ApiBlueprint,
|
||||
configApiRef,
|
||||
DiscoveryApi,
|
||||
discoveryApiRef,
|
||||
IdentityApi,
|
||||
identityApiRef,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
|
||||
import { CompoundEntityRef } from '@backstage/catalog-model';
|
||||
import { Config } from '@backstage/config';
|
||||
@@ -20,15 +28,6 @@ import {
|
||||
scmIntegrationsApiRef,
|
||||
ScmIntegrationsApi,
|
||||
} from '@backstage/integration-react';
|
||||
import {
|
||||
AnyApiFactory,
|
||||
configApiRef,
|
||||
createApiFactory,
|
||||
DiscoveryApi,
|
||||
discoveryApiRef,
|
||||
IdentityApi,
|
||||
identityApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import {
|
||||
SyncResult,
|
||||
TechDocsApi,
|
||||
@@ -158,38 +157,50 @@ class TechDocsDevApi implements TechDocsApi {
|
||||
}
|
||||
}
|
||||
|
||||
export const apis: AnyApiFactory[] = [
|
||||
createApiFactory({
|
||||
api: techdocsStorageApiRef,
|
||||
deps: {
|
||||
configApi: configApiRef,
|
||||
discoveryApi: discoveryApiRef,
|
||||
identityApi: identityApiRef,
|
||||
},
|
||||
factory: ({ configApi, discoveryApi, identityApi }) =>
|
||||
new TechDocsDevStorageApi({
|
||||
configApi,
|
||||
discoveryApi,
|
||||
identityApi,
|
||||
export const apis = [
|
||||
ApiBlueprint.make({
|
||||
name: 'techdocs-dev-storage',
|
||||
params: defineParams =>
|
||||
defineParams({
|
||||
api: techdocsStorageApiRef,
|
||||
deps: {
|
||||
configApi: configApiRef,
|
||||
discoveryApi: discoveryApiRef,
|
||||
identityApi: identityApiRef,
|
||||
},
|
||||
factory: ({ configApi, discoveryApi, identityApi }) =>
|
||||
new TechDocsDevStorageApi({
|
||||
configApi,
|
||||
discoveryApi,
|
||||
identityApi,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
createApiFactory({
|
||||
api: techdocsApiRef,
|
||||
deps: {
|
||||
configApi: configApiRef,
|
||||
discoveryApi: discoveryApiRef,
|
||||
identityApi: identityApiRef,
|
||||
},
|
||||
factory: ({ configApi, discoveryApi, identityApi }) =>
|
||||
new TechDocsDevApi({
|
||||
configApi,
|
||||
discoveryApi,
|
||||
identityApi,
|
||||
ApiBlueprint.make({
|
||||
name: 'techdocs-dev',
|
||||
params: defineParams =>
|
||||
defineParams({
|
||||
api: techdocsApiRef,
|
||||
deps: {
|
||||
configApi: configApiRef,
|
||||
discoveryApi: discoveryApiRef,
|
||||
identityApi: identityApiRef,
|
||||
},
|
||||
factory: ({ configApi, discoveryApi, identityApi }) =>
|
||||
new TechDocsDevApi({
|
||||
configApi,
|
||||
discoveryApi,
|
||||
identityApi,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
createApiFactory({
|
||||
api: scmIntegrationsApiRef,
|
||||
deps: { configApi: configApiRef },
|
||||
factory: ({ configApi }) => ScmIntegrationsApi.fromConfig(configApi),
|
||||
ApiBlueprint.make({
|
||||
name: 'scm-integrations',
|
||||
params: defineParams =>
|
||||
defineParams({
|
||||
api: scmIntegrationsApiRef,
|
||||
deps: { configApi: configApiRef },
|
||||
factory: ({ configApi }) => ScmIntegrationsApi.fromConfig(configApi),
|
||||
}),
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
useSidebarOpenState,
|
||||
Link,
|
||||
} from '@backstage/core-components';
|
||||
import { NavContentBlueprint } from '@backstage/frontend-plugin-api';
|
||||
|
||||
const useSidebarLogoStyles = makeStyles({
|
||||
root: {
|
||||
@@ -79,3 +80,8 @@ export const Root = ({ children }: PropsWithChildren<{}>) => (
|
||||
{children}
|
||||
</SidebarPage>
|
||||
);
|
||||
export const SidebarContent = NavContentBlueprint.make({
|
||||
params: {
|
||||
component: ({}) => <Root />,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -25,7 +25,7 @@ import IconButton from '@material-ui/core/IconButton';
|
||||
import LightIcon from '@material-ui/icons/Brightness7';
|
||||
import DarkIcon from '@material-ui/icons/Brightness4';
|
||||
|
||||
import { appThemeApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
import { appThemeApiRef, useApi } from '@backstage/frontend-plugin-api';
|
||||
|
||||
import {
|
||||
TechDocsReaderPage,
|
||||
@@ -93,7 +93,7 @@ export const TechDocsThemeToggle = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const DefaultTechDocsPage = () => {
|
||||
export const DefaultTechDocsPage = () => {
|
||||
return (
|
||||
<TechDocsReaderPage>
|
||||
<TechDocsReaderPageHeader />
|
||||
|
||||
@@ -19,4 +19,4 @@ import ReactDOM from 'react-dom/client';
|
||||
import '@backstage/ui/css/styles.css';
|
||||
import App from './App';
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(<App />);
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(App);
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { plugin as TechDocsPlugin } from '@backstage/plugin-techdocs';
|
||||
@@ -265,9 +265,13 @@ const _default: OverridableFrontendPlugin<
|
||||
}>;
|
||||
'page:techdocs/reader': OverridableExtensionDefinition<{
|
||||
config: {
|
||||
withSearch: boolean;
|
||||
withHeader: boolean;
|
||||
path: string | undefined;
|
||||
};
|
||||
configInput: {
|
||||
withSearch?: boolean | undefined;
|
||||
withHeader?: boolean | undefined;
|
||||
path?: string | undefined;
|
||||
};
|
||||
output:
|
||||
|
||||
@@ -152,7 +152,13 @@ const techDocsReaderPage = PageBlueprint.makeWithOverrides({
|
||||
inputs: {
|
||||
addons: createExtensionInput([AddonBlueprint.dataRefs.addon]),
|
||||
},
|
||||
factory(originalFactory, { inputs }) {
|
||||
config: {
|
||||
schema: {
|
||||
withSearch: z => z.boolean().default(true),
|
||||
withHeader: z => z.boolean().default(true),
|
||||
},
|
||||
},
|
||||
factory(originalFactory, { inputs, config }) {
|
||||
const addons = inputs.addons.map(output => {
|
||||
const options = output.get(AddonBlueprint.dataRefs.addon);
|
||||
const Addon = options.component;
|
||||
@@ -166,7 +172,10 @@ const techDocsReaderPage = PageBlueprint.makeWithOverrides({
|
||||
loader: async () =>
|
||||
await import('../Router').then(({ TechDocsReaderRouter }) => (
|
||||
<TechDocsReaderRouter>
|
||||
<TechDocsReaderLayout />
|
||||
<TechDocsReaderLayout
|
||||
withSearch={config.withSearch}
|
||||
withHeader={config.withHeader}
|
||||
/>
|
||||
<TechDocsAddons>{addons}</TechDocsAddons>
|
||||
</TechDocsReaderRouter>
|
||||
)),
|
||||
|
||||
@@ -47899,13 +47899,13 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "techdocs-cli-embedded-app@workspace:packages/techdocs-cli-embedded-app"
|
||||
dependencies:
|
||||
"@backstage/app-defaults": "workspace:^"
|
||||
"@backstage/catalog-model": "workspace:^"
|
||||
"@backstage/cli": "workspace:^"
|
||||
"@backstage/config": "workspace:^"
|
||||
"@backstage/core-app-api": "workspace:^"
|
||||
"@backstage/core-components": "workspace:^"
|
||||
"@backstage/core-plugin-api": "workspace:^"
|
||||
"@backstage/frontend-defaults": "workspace:^"
|
||||
"@backstage/frontend-plugin-api": "workspace:^"
|
||||
"@backstage/integration-react": "workspace:^"
|
||||
"@backstage/plugin-catalog": "workspace:^"
|
||||
"@backstage/plugin-techdocs": "workspace:^"
|
||||
@@ -47922,11 +47922,9 @@ __metadata:
|
||||
"@types/react": "npm:*"
|
||||
"@types/react-dom": "npm:*"
|
||||
cross-env: "npm:^10.0.0"
|
||||
history: "npm:^5.0.0"
|
||||
react: "npm:^18.0.2"
|
||||
react-dom: "npm:^18.0.2"
|
||||
react-router-dom: "npm:^6.3.0"
|
||||
react-use: "npm:^17.2.4"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
|
||||
Reference in New Issue
Block a user