From cc9c99329bf9e74c8aff52ca866160b10e330ca4 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 26 Sep 2023 14:30:18 +0200 Subject: [PATCH 01/19] feat(frontend-app-api): set base path using app router logic Signed-off-by: Camila Belo --- .../frontend-app-api/src/extensions/CoreNav.tsx | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/frontend-app-api/src/extensions/CoreNav.tsx b/packages/frontend-app-api/src/extensions/CoreNav.tsx index e66bee8212..50aa8fd408 100644 --- a/packages/frontend-app-api/src/extensions/CoreNav.tsx +++ b/packages/frontend-app-api/src/extensions/CoreNav.tsx @@ -19,6 +19,8 @@ import { createExtension, coreExtensionData, createExtensionInput, + useRouteRef, + NavTarget, } from '@backstage/frontend-plugin-api'; import { makeStyles } from '@material-ui/core'; import { @@ -29,7 +31,6 @@ import { SidebarDivider, SidebarItem, } from '@backstage/core-components'; -import { GraphiQLIcon } from '@backstage/plugin-graphiql'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import LogoIcon from '../../../app/src/components/Root/LogoIcon'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports @@ -68,20 +69,26 @@ export const CoreNav = createExtension({ at: 'core.layout/nav', inputs: { items: createExtensionInput({ - path: coreExtensionData.navTarget, + target: coreExtensionData.navTarget, }), }, output: { element: coreExtensionData.reactElement, }, - factory({ bind }) { + factory({ bind, inputs }) { + const SidebarNavItem = (props: NavTarget) => { + const { icon, title, routeRef } = props; + const to = useRouteRef(routeRef)(); + return ; + }; bind({ - // TODO: set base path using the logic from AppRouter element: ( - + {inputs.items.map((item, index) => ( + + ))} ), }); From 6e9fbc540df4935392e06ee7281499be02db3dd1 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 26 Sep 2023 14:44:47 +0200 Subject: [PATCH 02/19] feat(frontend-app-api): register app default api implementations Signed-off-by: Camila Belo --- .../frontend-app-api/src/wiring/createApp.tsx | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index bb50dea075..dc7db79022 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -49,6 +49,7 @@ import { featureFlagsApiRef, attachComponentData, useRouteRef, + identityApiRef, } from '@backstage/core-plugin-api'; import { getAvailablePlugins } from './discovery'; import { @@ -62,6 +63,8 @@ import { // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { AppThemeProvider } from '../../../core-app-api/src/app/AppThemeProvider'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { AppIdentityProxy } from '../../../core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports import { AppContextProvider } from '../../../core-app-api/src/app/AppContext'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { LocalStorageFeatureFlags } from '../../../core-app-api/src/apis/implementations/FeatureFlagsApi/LocalStorageFeatureFlags'; @@ -366,13 +369,13 @@ function createApiHolder( ): ApiHolder { const factoryRegistry = new ApiFactoryRegistry(); - const apiFactories = + const pluginApis = coreExtension.attachments .get('apis') ?.map(e => e.getData(coreExtensionData.apiFactory)) .filter((x): x is AnyApiFactory => !!x) ?? []; - for (const factory of apiFactories) { + for (const factory of [...defaultApis, ...pluginApis]) { factoryRegistry.register('default', factory); } @@ -383,6 +386,38 @@ function createApiHolder( factory: () => new LocalStorageFeatureFlags(), }); + factoryRegistry.register('static', { + api: identityApiRef, + deps: {}, + factory: () => { + const appIdentityProxy = new AppIdentityProxy(); + // TODO: Remove this when sign-in page is migrated + appIdentityProxy.setTarget( + { + getUserId: () => 'guest', + getIdToken: async () => undefined, + getProfile: () => ({ + email: 'guest@example.com', + displayName: 'Guest', + }), + getProfileInfo: async () => ({ + email: 'guest@example.com', + displayName: 'Guest', + }), + getBackstageIdentity: async () => ({ + type: 'user', + userEntityRef: 'user:default/guest', + ownershipEntityRefs: ['user:default/guest'], + }), + getCredentials: async () => ({}), + signOut: async () => {}, + }, + { signOutTargetUrl: '/' }, + ); + return appIdentityProxy; + }, + }); + factoryRegistry.register('static', { api: appThemeApiRef, deps: {}, From 5d92f07ff6b053ba2fdecdd72fb490928fb0e6b4 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Wed, 27 Sep 2023 09:38:24 +0200 Subject: [PATCH 03/19] feat(frontend-app-api): add support for sidebar group Signed-off-by: Camila Belo --- .../src/extensions/CoreNav.tsx | 18 +++++++--- .../src/extensions/createNavItemExtension.tsx | 35 ++++++++++++++++--- .../src/wiring/coreExtensionData.ts | 1 + 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/packages/frontend-app-api/src/extensions/CoreNav.tsx b/packages/frontend-app-api/src/extensions/CoreNav.tsx index 50aa8fd408..9c829a348f 100644 --- a/packages/frontend-app-api/src/extensions/CoreNav.tsx +++ b/packages/frontend-app-api/src/extensions/CoreNav.tsx @@ -30,6 +30,7 @@ import { sidebarConfig, SidebarDivider, SidebarItem, + SidebarGroup, } from '@backstage/core-components'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import LogoIcon from '../../../app/src/components/Root/LogoIcon'; @@ -64,6 +65,18 @@ const SidebarLogo = () => { ); }; +const SidebarNavItem = (props: NavTarget) => { + const { icon: Icon, title, group, routeRef } = props; + const to = useRouteRef(routeRef)(); + return group ? ( + } label={title}> + {group} + + ) : ( + + ); +}; + export const CoreNav = createExtension({ id: 'core.nav', at: 'core.layout/nav', @@ -76,11 +89,6 @@ export const CoreNav = createExtension({ element: coreExtensionData.reactElement, }, factory({ bind, inputs }) { - const SidebarNavItem = (props: NavTarget) => { - const { icon, title, routeRef } = props; - const to = useRouteRef(routeRef)(); - return ; - }; bind({ element: ( diff --git a/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx b/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx index 8c55531866..723c9e9956 100644 --- a/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx @@ -16,19 +16,33 @@ import { IconComponent, RouteRef } from '@backstage/core-plugin-api'; import { createSchemaFromZod } from '../schema/createSchemaFromZod'; -import { coreExtensionData, createExtension } from '../wiring'; +import { + AnyExtensionInputMap, + ExtensionInputValues, + coreExtensionData, + createExtension, +} from '../wiring'; +import { Expand } from '../wiring/createExtension'; +import { Suspense, lazy } from 'react'; +import React from 'react'; /** * Helper for creating extensions for a nav item. * @public */ -export function createNavItemExtension(options: { +export function createNavItemExtension< + TInputs extends AnyExtensionInputMap, +>(options: { id: string; routeRef: RouteRef; title: string; icon: IconComponent; + inputs?: TInputs; + group?: (options: { + inputs: Expand>; + }) => Promise; }) { - const { id, routeRef, title, icon } = options; + const { id, routeRef, title, icon, group } = options; return createExtension({ id, at: 'core.nav/items', @@ -37,15 +51,28 @@ export function createNavItemExtension(options: { title: z.string().default(title), }), ), + inputs: options.inputs, output: { navTarget: coreExtensionData.navTarget, }, - factory: ({ bind, config }) => { + factory: ({ bind, config, inputs }) => { + const Group = group + ? (lazy(() => + group({ inputs }).then(element => ({ + default: () => element, + })), + ) as unknown as () => JSX.Element) + : undefined; bind({ navTarget: { title: config.title, icon, routeRef, + group: Group ? ( + + + + ) : undefined, }, }); }, diff --git a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts index 079d5bcb18..d03513677d 100644 --- a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts +++ b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts @@ -27,6 +27,7 @@ export type NavTarget = { title: string; icon: IconComponent; routeRef: RouteRef<{}>; + group?: JSX.Element; }; /** @public */ From f22ab808eb5c05adf4446b55a98a31d9e2c6b27c Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 26 Sep 2023 14:46:21 +0200 Subject: [PATCH 04/19] feat(catalog): create plugin and api extensions Signed-off-by: Camila Belo --- plugins/catalog/package.json | 1 + plugins/catalog/src/alpha.ts | 37 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 412c7d0716..4ef0db4910 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -51,6 +51,7 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", "@backstage/integration-react": "workspace:^", "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", diff --git a/plugins/catalog/src/alpha.ts b/plugins/catalog/src/alpha.ts index 3509c1fb7f..ffa50ea1f7 100644 --- a/plugins/catalog/src/alpha.ts +++ b/plugins/catalog/src/alpha.ts @@ -15,3 +15,40 @@ */ export * from './translation'; + +import { + DiscoveryApi, + FetchApi, + discoveryApiRef, + fetchApiRef, +} from '@backstage/core-plugin-api'; +import { CatalogClient } from '@backstage/catalog-client'; +import { + createApiExtension, + createPlugin, +} from '@backstage/frontend-plugin-api'; +import { catalogApiRef } from '@backstage/plugin-catalog-react'; + +/** @alpha */ +export const CatalogApi = createApiExtension({ + factory: { + api: catalogApiRef, + deps: { + discoveryApi: discoveryApiRef, + fetchApi: fetchApiRef, + }, + factory: ({ + discoveryApi, + fetchApi, + }: { + discoveryApi: DiscoveryApi; + fetchApi: FetchApi; + }) => new CatalogClient({ discoveryApi, fetchApi }), + }, +}); + +/** @alpha */ +export default createPlugin({ + id: 'plugin.catalog', + extensions: [CatalogApi], +}); From 3de3a1b872b59fa701ffc43a1346ccd08fa53f32 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 26 Sep 2023 14:48:19 +0200 Subject: [PATCH 05/19] feat(search): configure alpha subpath Signed-off-by: Camila Belo --- plugins/search/package.json | 19 ++++++++++++++++--- plugins/search/src/alpha.tsx | 15 +++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 plugins/search/src/alpha.tsx diff --git a/plugins/search/package.json b/plugins/search/package.json index 77c3bd4727..f5d4042964 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -6,9 +6,22 @@ "types": "src/index.ts", "license": "Apache-2.0", "publishConfig": { - "access": "public", - "main": "dist/index.esm.js", - "types": "dist/index.d.ts" + "access": "public" + }, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.tsx", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.tsx" + ], + "package.json": [ + "package.json" + ] + } }, "backstage": { "role": "frontend-plugin" diff --git a/plugins/search/src/alpha.tsx b/plugins/search/src/alpha.tsx new file mode 100644 index 0000000000..eb2f165350 --- /dev/null +++ b/plugins/search/src/alpha.tsx @@ -0,0 +1,15 @@ +/* + * Copyright 2023 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. + */ From baf56d5abf4cbc44bd43e1a874851e50d804c1d0 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 26 Sep 2023 14:50:35 +0200 Subject: [PATCH 06/19] feat(search): create search api extension Signed-off-by: Camila Belo --- plugins/search/package.json | 1 + plugins/search/src/alpha.tsx | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/plugins/search/package.json b/plugins/search/package.json index f5d4042964..8b90867a5a 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -51,6 +51,7 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-search-common": "workspace:^", "@backstage/plugin-search-react": "workspace:^", diff --git a/plugins/search/src/alpha.tsx b/plugins/search/src/alpha.tsx index eb2f165350..89ff6b7664 100644 --- a/plugins/search/src/alpha.tsx +++ b/plugins/search/src/alpha.tsx @@ -13,3 +13,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +import { + DiscoveryApi, + IdentityApi, + discoveryApiRef, + identityApiRef, +} from '@backstage/core-plugin-api'; + +import { createApiExtension } from '@backstage/frontend-plugin-api'; + +import { searchApiRef } from '@backstage/plugin-search-react'; + +import { SearchClient } from './apis'; + +/** @alpha */ +export const SearchApi = createApiExtension({ + factory: { + api: searchApiRef, + deps: { discoveryApi: discoveryApiRef, identityApi: identityApiRef }, + factory: ({ + identityApi, + discoveryApi, + }: { + identityApi: IdentityApi; + discoveryApi: DiscoveryApi; + }) => new SearchClient({ discoveryApi, identityApi }), + }, +}); From 51b63d4939e2479b9e2f26bdb5923a2eee13887e Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 26 Sep 2023 14:52:52 +0200 Subject: [PATCH 07/19] feat(search): create search page extension Signed-off-by: Camila Belo --- plugins/search/src/alpha.tsx | 188 +++++++++++++++++- .../src/components/SearchPage/UrlUpdater.tsx | 85 ++++++++ 2 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 plugins/search/src/components/SearchPage/UrlUpdater.tsx diff --git a/plugins/search/src/alpha.tsx b/plugins/search/src/alpha.tsx index 89ff6b7664..669656338d 100644 --- a/plugins/search/src/alpha.tsx +++ b/plugins/search/src/alpha.tsx @@ -14,16 +14,55 @@ * limitations under the License. */ +import React from 'react'; + +import { Grid, makeStyles, Paper, Theme } from '@material-ui/core'; + import { + CatalogIcon, + Content, + DocsIcon, + Header, + Page, + useSidebarPinState, +} from '@backstage/core-components'; +import { + createRouteRef, + useApi, DiscoveryApi, IdentityApi, discoveryApiRef, identityApiRef, } from '@backstage/core-plugin-api'; -import { createApiExtension } from '@backstage/frontend-plugin-api'; +import { + createApiExtension, + createPageExtension, + createExtensionInput, + createSchemaFromZod, +} from '@backstage/frontend-plugin-api'; +import { + catalogApiRef, + CATALOG_FILTER_EXISTS, +} from '@backstage/plugin-catalog-react'; + +import { SearchType } from '@backstage/plugin-search'; +import { + DefaultResultListItem, + SearchBar, + SearchFilter, + SearchPagination, + SearchResult as SearchResults, + SearchResultPager, + useSearch, + SearchContextProvider, +} from '@backstage/plugin-search-react'; +import { SearchResult } from '@backstage/plugin-search-common'; import { searchApiRef } from '@backstage/plugin-search-react'; +import { searchResultItemExtensionData } from '@backstage/plugin-search-react/alpha'; + +import { UrlUpdater } from './components/SearchPage/SearchPage'; import { SearchClient } from './apis'; @@ -41,3 +80,150 @@ export const SearchApi = createApiExtension({ }) => new SearchClient({ discoveryApi, identityApi }), }, }); + +const useStyles = makeStyles((theme: Theme) => ({ + filter: { + '& + &': { + marginTop: theme.spacing(2.5), + }, + }, + filters: { + padding: theme.spacing(2), + marginTop: theme.spacing(2), + }, +})); + +const searchRouteRef = createRouteRef({ id: 'plugin.search.page' }); + +/** @alpha */ +export const SearchPage = createPageExtension({ + id: 'plugin.search.page', + routeRef: searchRouteRef, + configSchema: createSchemaFromZod(z => + z.object({ + path: z.string().default('/search'), + noTrack: z.boolean().default(false), + }), + ), + inputs: { + items: createExtensionInput({ + item: searchResultItemExtensionData, + }), + }, + loader: async ({ config, inputs }) => { + const getResultItemComponent = (result: SearchResult) => { + const value = inputs.items.find(({ item }) => item?.predicate?.(result)); + return value?.item.component ?? DefaultResultListItem; + }; + + const Component = () => { + const classes = useStyles(); + const { isMobile } = useSidebarPinState(); + const { types } = useSearch(); + const catalogApi = useApi(catalogApiRef); + + return ( + + {!isMobile &&
} + + + + + + {!isMobile && ( + + , + }, + { + value: 'techdocs', + name: 'Documentation', + icon: , + }, + { + value: 'adr', + name: 'Architecture Decision Records', + icon: , + }, + ]} + /> + + {types.includes('techdocs') && ( + { + // Return a list of entities which are documented. + const { items } = await catalogApi.getEntities({ + fields: ['metadata.name'], + filter: { + 'metadata.annotations.backstage.io/techdocs-ref': + CATALOG_FILTER_EXISTS, + }, + }); + + const names = items.map( + entity => entity.metadata.name, + ); + names.sort(); + return names; + }} + /> + )} + + + + + )} + + + + {({ results }) => + results.map((result, index) => { + const SearchResultListItem = + getResultItemComponent(result); + return ( + + ); + }) + } + + + + + + + ); + }; + + return ( + + + + + ); + }, +}); diff --git a/plugins/search/src/components/SearchPage/UrlUpdater.tsx b/plugins/search/src/components/SearchPage/UrlUpdater.tsx new file mode 100644 index 0000000000..d44195b6e2 --- /dev/null +++ b/plugins/search/src/components/SearchPage/UrlUpdater.tsx @@ -0,0 +1,85 @@ +/* + * Copyright 2023 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 { useEffect } from 'react'; +import usePrevious from 'react-use/lib/usePrevious'; +import qs from 'qs'; +import { useLocation } from 'react-router-dom'; +import { useSearch } from '@backstage/plugin-search-react'; +import { JsonObject } from '@backstage/types'; + +export const UrlUpdater = () => { + const location = useLocation(); + const { + term, + setTerm, + types, + setTypes, + pageCursor, + setPageCursor, + filters, + setFilters, + } = useSearch(); + + const prevQueryParams = usePrevious(location.search); + + useEffect(() => { + // Only respond to changes to url query params + if (location.search === prevQueryParams) { + return; + } + + const query = + qs.parse(location.search.substring(1), { arrayLimit: 0 }) || {}; + + if (query.filters) { + setFilters(query.filters as JsonObject); + } + + if (query.query) { + setTerm(query.query as string); + } + + if (query.pageCursor) { + setPageCursor(query.pageCursor as string); + } + + if (query.types) { + setTypes(query.types as string[]); + } + }, [prevQueryParams, location, setTerm, setTypes, setPageCursor, setFilters]); + + useEffect(() => { + const newParams = qs.stringify( + { + query: term, + types, + pageCursor, + filters, + }, + { arrayFormat: 'brackets' }, + ); + const newUrl = `${window.location.pathname}?${newParams}`; + + // We directly manipulate window history here in order to not re-render + // infinitely (state => location => state => etc). The intention of this + // code is just to ensure the right query/filters are loaded when a user + // clicks the "back" button after clicking a result. + window.history.replaceState(null, document.title, newUrl); + }, [term, types, pageCursor, filters]); + + return null; +}; From d0fb8e148148c26a837cd00dea3e14f7fa3e10c1 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 26 Sep 2023 14:53:49 +0200 Subject: [PATCH 08/19] feat(search): create search nav item extension Signed-off-by: Camila Belo --- plugins/search/src/alpha.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/search/src/alpha.tsx b/plugins/search/src/alpha.tsx index 669656338d..599997495e 100644 --- a/plugins/search/src/alpha.tsx +++ b/plugins/search/src/alpha.tsx @@ -17,6 +17,7 @@ import React from 'react'; import { Grid, makeStyles, Paper, Theme } from '@material-ui/core'; +import SearchIcon from '@material-ui/icons/Search'; import { CatalogIcon, @@ -39,6 +40,7 @@ import { createApiExtension, createPageExtension, createExtensionInput, + createNavItemExtension, createSchemaFromZod, } from '@backstage/frontend-plugin-api'; @@ -227,3 +229,11 @@ export const SearchPage = createPageExtension({ ); }, }); + +/** @alpha */ +export const SearchNavItem = createNavItemExtension({ + id: 'plugin.search.nav.index', + routeRef: searchRouteRef, + title: 'Search', + icon: SearchIcon, +}); From 99f557f2563a9a6fc5019b3971dd904a1ff6bfbb Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Wed, 27 Sep 2023 09:43:12 +0200 Subject: [PATCH 09/19] feat(search): create search modal extension Signed-off-by: Camila Belo --- plugins/search/src/alpha.tsx | 264 ++++++++++++++++++++++++++++++++++- 1 file changed, 257 insertions(+), 7 deletions(-) diff --git a/plugins/search/src/alpha.tsx b/plugins/search/src/alpha.tsx index 599997495e..c8a96a4a5a 100644 --- a/plugins/search/src/alpha.tsx +++ b/plugins/search/src/alpha.tsx @@ -14,10 +14,24 @@ * limitations under the License. */ -import React from 'react'; +import React, { useCallback, useEffect, useRef } from 'react'; +import { useNavigate } from 'react-router-dom'; -import { Grid, makeStyles, Paper, Theme } from '@material-ui/core'; +import { + makeStyles, + Theme, + Grid, + Box, + Paper, + DialogActions, + DialogContent, + DialogTitle, + Button, + IconButton, +} from '@material-ui/core'; +import CloseIcon from '@material-ui/icons/Close'; import SearchIcon from '@material-ui/icons/Search'; +import ArrowForwardIcon from '@material-ui/icons/ArrowForward'; import { CatalogIcon, @@ -41,6 +55,8 @@ import { createPageExtension, createExtensionInput, createNavItemExtension, + createExtensionDataRef, + createExtension, createSchemaFromZod, } from '@backstage/frontend-plugin-api'; @@ -49,7 +65,6 @@ import { CATALOG_FILTER_EXISTS, } from '@backstage/plugin-catalog-react'; -import { SearchType } from '@backstage/plugin-search'; import { DefaultResultListItem, SearchBar, @@ -64,9 +79,11 @@ import { SearchResult } from '@backstage/plugin-search-common'; import { searchApiRef } from '@backstage/plugin-search-react'; import { searchResultItemExtensionData } from '@backstage/plugin-search-react/alpha'; -import { UrlUpdater } from './components/SearchPage/SearchPage'; - import { SearchClient } from './apis'; +import { SearchType } from './components/SearchType'; +import { UrlUpdater } from './components/SearchPage/SearchPage'; +import { SidebarSearchModal } from './components/SidebarSearchModal/SidebarSearchModal'; +import { useSearchModal } from './components/SearchModal'; /** @alpha */ export const SearchApi = createApiExtension({ @@ -83,7 +100,7 @@ export const SearchApi = createApiExtension({ }, }); -const useStyles = makeStyles((theme: Theme) => ({ +const useSearchPageStyles = makeStyles((theme: Theme) => ({ filter: { '& + &': { marginTop: theme.spacing(2.5), @@ -119,7 +136,7 @@ export const SearchPage = createPageExtension({ }; const Component = () => { - const classes = useStyles(); + const classes = useSearchPageStyles(); const { isMobile } = useSidebarPinState(); const { types } = useSearch(); const catalogApi = useApi(catalogApiRef); @@ -230,10 +247,243 @@ export const SearchPage = createPageExtension({ }, }); +const searchModalExtensionData = createExtensionDataRef( + 'plugin.search.modal.element', +); + +const useSearchModalStyles = makeStyles(theme => ({ + dialogTitle: { + gap: theme.spacing(1), + display: 'grid', + alignItems: 'center', + gridTemplateColumns: '1fr auto', + '&> button': { + marginTop: theme.spacing(1), + }, + }, + container: { + borderRadius: 30, + display: 'flex', + height: '2.4em', + padding: theme.spacing(1), + }, + filter: { + '& + &': { + marginTop: theme.spacing(2.5), + }, + }, + filters: { + padding: theme.spacing(2), + marginTop: theme.spacing(2), + }, + input: { + flex: 1, + }, + button: { + '&:hover': { + background: 'none', + }, + }, + dialogActionsContainer: { padding: theme.spacing(1, 3) }, + viewResultsLink: { verticalAlign: '0.5em' }, +})); + +/** @alpha */ +export const SearchModal = createExtension({ + id: 'plugin.search.modal', + at: 'plugin.search.nav.index/modal', + configSchema: createSchemaFromZod(z => + z.object({ + noTrack: z.boolean().default(false), + }), + ), + inputs: { + items: createExtensionInput({ + item: searchResultItemExtensionData, + }), + }, + output: { + element: searchModalExtensionData, + }, + factory({ bind, config, inputs }) { + const getResultItemComponent = (result: SearchResult) => { + const value = inputs.items.find(({ item }) => item?.predicate?.(result)); + return value?.item.component ?? DefaultResultListItem; + }; + + const Component = () => { + const classes = useSearchModalStyles(); + const navigate = useNavigate(); + const catalogApi = useApi(catalogApiRef); + + const { types } = useSearch(); + const { toggleModal } = useSearchModal(); + const searchRootRoute = '/search'; + const searchBarRef = useRef(null); + + useEffect(() => { + searchBarRef?.current?.focus(); + }); + + // This handler is called when "enter" is pressed + const handleSearchBarSubmit = useCallback(() => { + toggleModal(); + // Using ref to get the current field value without waiting for a query debounce + const query = searchBarRef.current?.value ?? ''; + navigate(`${searchRootRoute}?query=${query}`); + }, [navigate, toggleModal, searchRootRoute]); + + return ( + <> + + + + + + + + + + + + + + + + {types.includes('techdocs') && ( + + { + // Return a list of entities which are documented. + const { items } = await catalogApi.getEntities({ + fields: ['metadata.name'], + filter: { + 'metadata.annotations.backstage.io/techdocs-ref': + CATALOG_FILTER_EXISTS, + }, + }); + + const names = items.map(entity => entity.metadata.name); + names.sort(); + return names; + }} + /> + + )} + + + + + + + + + + + + + + + {({ results }) => + results.map((result, index) => { + const SearchResultListItem = + getResultItemComponent(result); + return ( + + ); + }) + } + + + + + + + + + + + + + ); + }; + + bind({ + element: , + }); + }, +}); + /** @alpha */ export const SearchNavItem = createNavItemExtension({ id: 'plugin.search.nav.index', routeRef: searchRouteRef, title: 'Search', icon: SearchIcon, + group: async ({ inputs }) => ( + {() => inputs.modal.element} + ), + inputs: { + modal: createExtensionInput( + { + element: searchModalExtensionData, + }, + { + singleton: true, + }, + ), + }, }); From 9143802c1c62ee8221d01dd429a5fd0ae0304097 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 26 Sep 2023 14:55:02 +0200 Subject: [PATCH 10/19] feat(search): create search plugin extension Signed-off-by: Camila Belo --- plugins/search/src/alpha.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/search/src/alpha.tsx b/plugins/search/src/alpha.tsx index c8a96a4a5a..9eb9d489f4 100644 --- a/plugins/search/src/alpha.tsx +++ b/plugins/search/src/alpha.tsx @@ -51,6 +51,7 @@ import { } from '@backstage/core-plugin-api'; import { + createPlugin, createApiExtension, createPageExtension, createExtensionInput, @@ -487,3 +488,9 @@ export const SearchNavItem = createNavItemExtension({ ), }, }); + +/** @alpha */ +export default createPlugin({ + id: 'plugin.search', + extensions: [SearchApi, SearchPage, SearchModal, SearchNavItem], +}); From a094b8301439046137b35c8dd3bfe03c5e3c87ac Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 26 Sep 2023 14:56:00 +0200 Subject: [PATCH 11/19] feat(app-next): install search plugin Signed-off-by: Camila Belo --- packages/app-next/src/examples/pagesPlugin.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/app-next/src/examples/pagesPlugin.tsx b/packages/app-next/src/examples/pagesPlugin.tsx index c805442305..290c6b118e 100644 --- a/packages/app-next/src/examples/pagesPlugin.tsx +++ b/packages/app-next/src/examples/pagesPlugin.tsx @@ -48,6 +48,9 @@ const IndexPage = createPageExtension({
GraphiQL
+
+ Search +
); }; From 08e7675364d8440a6653b5f0a7f61c3a12eedbb7 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 26 Sep 2023 14:56:48 +0200 Subject: [PATCH 12/19] chore: update yarn.lock Signed-off-by: Camila Belo --- yarn.lock | 2 ++ 1 file changed, 2 insertions(+) diff --git a/yarn.lock b/yarn.lock index e429806816..2fe1ebc6f3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6023,6 +6023,7 @@ __metadata: "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" "@backstage/errors": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" "@backstage/integration-react": "workspace:^" "@backstage/plugin-catalog-common": "workspace:^" "@backstage/plugin-catalog-react": "workspace:^" @@ -9117,6 +9118,7 @@ __metadata: "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" "@backstage/errors": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" "@backstage/plugin-catalog-react": "workspace:^" "@backstage/plugin-search-common": "workspace:^" "@backstage/plugin-search-react": "workspace:^" From d13c57733e2dccb17f1ba27387787e6577eafe3b Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 26 Sep 2023 14:59:17 +0200 Subject: [PATCH 13/19] chore: update api reports Signed-off-by: Camila Belo --- .../api-report.md | 2 -- plugins/catalog/alpha-api-report.md | 9 ++++++ plugins/search/alpha-api-report.md | 30 +++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 plugins/search/alpha-api-report.md diff --git a/plugins/catalog-backend-module-incremental-ingestion/api-report.md b/plugins/catalog-backend-module-incremental-ingestion/api-report.md index 4088b05bb5..c2bfcedfce 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/api-report.md +++ b/plugins/catalog-backend-module-incremental-ingestion/api-report.md @@ -3,8 +3,6 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -/// - import { CatalogBuilder } from '@backstage/plugin-catalog-backend'; import type { Config } from '@backstage/config'; import type { DeferredEntity } from '@backstage/plugin-catalog-node'; diff --git a/plugins/catalog/alpha-api-report.md b/plugins/catalog/alpha-api-report.md index 27de408f86..631c43e73c 100644 --- a/plugins/catalog/alpha-api-report.md +++ b/plugins/catalog/alpha-api-report.md @@ -3,8 +3,13 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { BackstagePlugin } from '@backstage/frontend-plugin-api'; +import { Extension } from '@backstage/frontend-plugin-api'; import { TranslationRef } from '@backstage/core-plugin-api/alpha'; +// @alpha (undocumented) +export const CatalogApi: Extension<{}>; + // @alpha (undocumented) export const catalogTranslationRef: TranslationRef< 'catalog', @@ -14,5 +19,9 @@ export const catalogTranslationRef: TranslationRef< } >; +// @alpha (undocumented) +const _default: BackstagePlugin; +export default _default; + // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/search/alpha-api-report.md b/plugins/search/alpha-api-report.md new file mode 100644 index 0000000000..dd1bce1f9f --- /dev/null +++ b/plugins/search/alpha-api-report.md @@ -0,0 +1,30 @@ +## API Report File for "@backstage/plugin-search" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackstagePlugin } from '@backstage/frontend-plugin-api'; +import { Extension } from '@backstage/frontend-plugin-api'; + +// @alpha (undocumented) +const _default: BackstagePlugin; +export default _default; + +// @alpha (undocumented) +export const SearchApi: Extension<{}>; + +// @alpha (undocumented) +export const SearchModal: Extension; + +// @alpha (undocumented) +export const SearchNavItem: Extension<{ + title: string; +}>; + +// @alpha (undocumented) +export const SearchPage: Extension<{ + path: string; +}>; + +// (No @packageDocumentation comment for this package) +``` From e5a2956dd265059d7dad25ea6ebb2142a33d17dc Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 26 Sep 2023 15:04:18 +0200 Subject: [PATCH 14/19] chore: add changeset files Signed-off-by: Camila Belo --- .changeset/olive-cars-rescue.md | 5 +++++ .changeset/purple-forks-fetch.md | 5 +++++ .changeset/tasty-avocados-hope.md | 5 +++++ .changeset/tough-camels-enjoy.md | 5 +++++ 4 files changed, 20 insertions(+) create mode 100644 .changeset/olive-cars-rescue.md create mode 100644 .changeset/purple-forks-fetch.md create mode 100644 .changeset/tasty-avocados-hope.md create mode 100644 .changeset/tough-camels-enjoy.md diff --git a/.changeset/olive-cars-rescue.md b/.changeset/olive-cars-rescue.md new file mode 100644 index 0000000000..95728eb45e --- /dev/null +++ b/.changeset/olive-cars-rescue.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search': patch +--- + +Create an experimental search plugin that is compatible with declarative integration system. diff --git a/.changeset/purple-forks-fetch.md b/.changeset/purple-forks-fetch.md new file mode 100644 index 0000000000..022fc32e71 --- /dev/null +++ b/.changeset/purple-forks-fetch.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': patch +--- + +Register default api implementations when creating declarative integrated apps. diff --git a/.changeset/tasty-avocados-hope.md b/.changeset/tasty-avocados-hope.md new file mode 100644 index 0000000000..c5bea6a79c --- /dev/null +++ b/.changeset/tasty-avocados-hope.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': patch +--- + +Migrate catalog api to declarative integration system. diff --git a/.changeset/tough-camels-enjoy.md b/.changeset/tough-camels-enjoy.md new file mode 100644 index 0000000000..07422e1b1b --- /dev/null +++ b/.changeset/tough-camels-enjoy.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-plugin-api': patch +--- + +Add support for `SidebarGroup` on the sidebar item extension. From d3a37f55c0862443355bb3b55bb8ef6f922c4f4e Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Thu, 28 Sep 2023 13:18:35 +0200 Subject: [PATCH 15/19] chore: update changeset files Signed-off-by: Camila Belo --- .changeset/{tough-camels-enjoy.md => late-papayas-push.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .changeset/{tough-camels-enjoy.md => late-papayas-push.md} (100%) diff --git a/.changeset/tough-camels-enjoy.md b/.changeset/late-papayas-push.md similarity index 100% rename from .changeset/tough-camels-enjoy.md rename to .changeset/late-papayas-push.md From 18d667507612f1e64b64da500b334e2a391929d7 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Thu, 28 Sep 2023 13:45:22 +0200 Subject: [PATCH 16/19] refactor(search): remove search modal for now Signed-off-by: Camila Belo --- .../src/extensions/CoreNav.tsx | 12 +- .../src/extensions/createNavItemExtension.tsx | 35 +-- .../src/wiring/coreExtensionData.ts | 1 - plugins/search/alpha-api-report.md | 4 +- plugins/search/src/alpha.tsx | 257 +----------------- 5 files changed, 11 insertions(+), 298 deletions(-) diff --git a/packages/frontend-app-api/src/extensions/CoreNav.tsx b/packages/frontend-app-api/src/extensions/CoreNav.tsx index 9c829a348f..71ab71a6aa 100644 --- a/packages/frontend-app-api/src/extensions/CoreNav.tsx +++ b/packages/frontend-app-api/src/extensions/CoreNav.tsx @@ -30,7 +30,6 @@ import { sidebarConfig, SidebarDivider, SidebarItem, - SidebarGroup, } from '@backstage/core-components'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import LogoIcon from '../../../app/src/components/Root/LogoIcon'; @@ -66,15 +65,10 @@ const SidebarLogo = () => { }; const SidebarNavItem = (props: NavTarget) => { - const { icon: Icon, title, group, routeRef } = props; + const { icon: Icon, title, routeRef } = props; const to = useRouteRef(routeRef)(); - return group ? ( - } label={title}> - {group} - - ) : ( - - ); + // TODO: Support opening modal, for example, the search one + return ; }; export const CoreNav = createExtension({ diff --git a/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx b/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx index 723c9e9956..8c55531866 100644 --- a/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createNavItemExtension.tsx @@ -16,33 +16,19 @@ import { IconComponent, RouteRef } from '@backstage/core-plugin-api'; import { createSchemaFromZod } from '../schema/createSchemaFromZod'; -import { - AnyExtensionInputMap, - ExtensionInputValues, - coreExtensionData, - createExtension, -} from '../wiring'; -import { Expand } from '../wiring/createExtension'; -import { Suspense, lazy } from 'react'; -import React from 'react'; +import { coreExtensionData, createExtension } from '../wiring'; /** * Helper for creating extensions for a nav item. * @public */ -export function createNavItemExtension< - TInputs extends AnyExtensionInputMap, ->(options: { +export function createNavItemExtension(options: { id: string; routeRef: RouteRef; title: string; icon: IconComponent; - inputs?: TInputs; - group?: (options: { - inputs: Expand>; - }) => Promise; }) { - const { id, routeRef, title, icon, group } = options; + const { id, routeRef, title, icon } = options; return createExtension({ id, at: 'core.nav/items', @@ -51,28 +37,15 @@ export function createNavItemExtension< title: z.string().default(title), }), ), - inputs: options.inputs, output: { navTarget: coreExtensionData.navTarget, }, - factory: ({ bind, config, inputs }) => { - const Group = group - ? (lazy(() => - group({ inputs }).then(element => ({ - default: () => element, - })), - ) as unknown as () => JSX.Element) - : undefined; + factory: ({ bind, config }) => { bind({ navTarget: { title: config.title, icon, routeRef, - group: Group ? ( - - - - ) : undefined, }, }); }, diff --git a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts index d03513677d..079d5bcb18 100644 --- a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts +++ b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts @@ -27,7 +27,6 @@ export type NavTarget = { title: string; icon: IconComponent; routeRef: RouteRef<{}>; - group?: JSX.Element; }; /** @public */ diff --git a/plugins/search/alpha-api-report.md b/plugins/search/alpha-api-report.md index dd1bce1f9f..5799ff5cd6 100644 --- a/plugins/search/alpha-api-report.md +++ b/plugins/search/alpha-api-report.md @@ -13,9 +13,6 @@ export default _default; // @alpha (undocumented) export const SearchApi: Extension<{}>; -// @alpha (undocumented) -export const SearchModal: Extension; - // @alpha (undocumented) export const SearchNavItem: Extension<{ title: string; @@ -24,6 +21,7 @@ export const SearchNavItem: Extension<{ // @alpha (undocumented) export const SearchPage: Extension<{ path: string; + noTrack: boolean; }>; // (No @packageDocumentation comment for this package) diff --git a/plugins/search/src/alpha.tsx b/plugins/search/src/alpha.tsx index 9eb9d489f4..2a9a714abd 100644 --- a/plugins/search/src/alpha.tsx +++ b/plugins/search/src/alpha.tsx @@ -14,24 +14,10 @@ * limitations under the License. */ -import React, { useCallback, useEffect, useRef } from 'react'; -import { useNavigate } from 'react-router-dom'; +import React from 'react'; -import { - makeStyles, - Theme, - Grid, - Box, - Paper, - DialogActions, - DialogContent, - DialogTitle, - Button, - IconButton, -} from '@material-ui/core'; -import CloseIcon from '@material-ui/icons/Close'; +import { makeStyles, Theme, Grid, Paper } from '@material-ui/core'; import SearchIcon from '@material-ui/icons/Search'; -import ArrowForwardIcon from '@material-ui/icons/ArrowForward'; import { CatalogIcon, @@ -56,8 +42,6 @@ import { createPageExtension, createExtensionInput, createNavItemExtension, - createExtensionDataRef, - createExtension, createSchemaFromZod, } from '@backstage/frontend-plugin-api'; @@ -83,8 +67,6 @@ import { searchResultItemExtensionData } from '@backstage/plugin-search-react/al import { SearchClient } from './apis'; import { SearchType } from './components/SearchType'; import { UrlUpdater } from './components/SearchPage/SearchPage'; -import { SidebarSearchModal } from './components/SidebarSearchModal/SidebarSearchModal'; -import { useSearchModal } from './components/SearchModal'; /** @alpha */ export const SearchApi = createApiExtension({ @@ -248,249 +230,16 @@ export const SearchPage = createPageExtension({ }, }); -const searchModalExtensionData = createExtensionDataRef( - 'plugin.search.modal.element', -); - -const useSearchModalStyles = makeStyles(theme => ({ - dialogTitle: { - gap: theme.spacing(1), - display: 'grid', - alignItems: 'center', - gridTemplateColumns: '1fr auto', - '&> button': { - marginTop: theme.spacing(1), - }, - }, - container: { - borderRadius: 30, - display: 'flex', - height: '2.4em', - padding: theme.spacing(1), - }, - filter: { - '& + &': { - marginTop: theme.spacing(2.5), - }, - }, - filters: { - padding: theme.spacing(2), - marginTop: theme.spacing(2), - }, - input: { - flex: 1, - }, - button: { - '&:hover': { - background: 'none', - }, - }, - dialogActionsContainer: { padding: theme.spacing(1, 3) }, - viewResultsLink: { verticalAlign: '0.5em' }, -})); - -/** @alpha */ -export const SearchModal = createExtension({ - id: 'plugin.search.modal', - at: 'plugin.search.nav.index/modal', - configSchema: createSchemaFromZod(z => - z.object({ - noTrack: z.boolean().default(false), - }), - ), - inputs: { - items: createExtensionInput({ - item: searchResultItemExtensionData, - }), - }, - output: { - element: searchModalExtensionData, - }, - factory({ bind, config, inputs }) { - const getResultItemComponent = (result: SearchResult) => { - const value = inputs.items.find(({ item }) => item?.predicate?.(result)); - return value?.item.component ?? DefaultResultListItem; - }; - - const Component = () => { - const classes = useSearchModalStyles(); - const navigate = useNavigate(); - const catalogApi = useApi(catalogApiRef); - - const { types } = useSearch(); - const { toggleModal } = useSearchModal(); - const searchRootRoute = '/search'; - const searchBarRef = useRef(null); - - useEffect(() => { - searchBarRef?.current?.focus(); - }); - - // This handler is called when "enter" is pressed - const handleSearchBarSubmit = useCallback(() => { - toggleModal(); - // Using ref to get the current field value without waiting for a query debounce - const query = searchBarRef.current?.value ?? ''; - navigate(`${searchRootRoute}?query=${query}`); - }, [navigate, toggleModal, searchRootRoute]); - - return ( - <> - - - - - - - - - - - - - - - - {types.includes('techdocs') && ( - - { - // Return a list of entities which are documented. - const { items } = await catalogApi.getEntities({ - fields: ['metadata.name'], - filter: { - 'metadata.annotations.backstage.io/techdocs-ref': - CATALOG_FILTER_EXISTS, - }, - }); - - const names = items.map(entity => entity.metadata.name); - names.sort(); - return names; - }} - /> - - )} - - - - - - - - - - - - - - - {({ results }) => - results.map((result, index) => { - const SearchResultListItem = - getResultItemComponent(result); - return ( - - ); - }) - } - - - - - - - - - - - - - ); - }; - - bind({ - element: , - }); - }, -}); - /** @alpha */ export const SearchNavItem = createNavItemExtension({ id: 'plugin.search.nav.index', routeRef: searchRouteRef, title: 'Search', icon: SearchIcon, - group: async ({ inputs }) => ( - {() => inputs.modal.element} - ), - inputs: { - modal: createExtensionInput( - { - element: searchModalExtensionData, - }, - { - singleton: true, - }, - ), - }, }); /** @alpha */ export default createPlugin({ id: 'plugin.search', - extensions: [SearchApi, SearchPage, SearchModal, SearchNavItem], + extensions: [SearchApi, SearchPage, SearchNavItem], }); From e9950c327cf5a4463dd8c016212bc154ff5166c2 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Thu, 28 Sep 2023 14:50:43 +0200 Subject: [PATCH 17/19] fix(catalog): use correct plugin id Signed-off-by: Camila Belo --- plugins/catalog/src/alpha.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/catalog/src/alpha.ts b/plugins/catalog/src/alpha.ts index ffa50ea1f7..d9c2af338d 100644 --- a/plugins/catalog/src/alpha.ts +++ b/plugins/catalog/src/alpha.ts @@ -49,6 +49,6 @@ export const CatalogApi = createApiExtension({ /** @alpha */ export default createPlugin({ - id: 'plugin.catalog', + id: 'catalog', extensions: [CatalogApi], }); From 2dbc40c80cbecfd9378fd6ddddff564a7d98a931 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Thu, 28 Sep 2023 14:52:00 +0200 Subject: [PATCH 18/19] chore: mention alpha exports on changesets Signed-off-by: Camila Belo --- .changeset/olive-cars-rescue.md | 2 +- .changeset/tasty-avocados-hope.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/olive-cars-rescue.md b/.changeset/olive-cars-rescue.md index 95728eb45e..fd6c8fe331 100644 --- a/.changeset/olive-cars-rescue.md +++ b/.changeset/olive-cars-rescue.md @@ -2,4 +2,4 @@ '@backstage/plugin-search': patch --- -Create an experimental search plugin that is compatible with declarative integration system. +Create an experimental search plugin that is compatible with the declarative integration system, it is exported from `/alpha` subpath. diff --git a/.changeset/tasty-avocados-hope.md b/.changeset/tasty-avocados-hope.md index c5bea6a79c..0772b55683 100644 --- a/.changeset/tasty-avocados-hope.md +++ b/.changeset/tasty-avocados-hope.md @@ -2,4 +2,4 @@ '@backstage/plugin-catalog': patch --- -Migrate catalog api to declarative integration system. +Migrate catalog api to declarative integration system, it is exported from `/alpha` subpath. From 2b7fb9e1ca5ce9e50a5e9b3ecae05feb9cf8dc63 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Thu, 28 Sep 2023 16:10:39 +0200 Subject: [PATCH 19/19] chore: update catalog backend api report Signed-off-by: Camila Belo --- .../catalog-backend-module-incremental-ingestion/api-report.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/catalog-backend-module-incremental-ingestion/api-report.md b/plugins/catalog-backend-module-incremental-ingestion/api-report.md index c2bfcedfce..4088b05bb5 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/api-report.md +++ b/plugins/catalog-backend-module-incremental-ingestion/api-report.md @@ -3,6 +3,8 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +/// + import { CatalogBuilder } from '@backstage/plugin-catalog-backend'; import type { Config } from '@backstage/config'; import type { DeferredEntity } from '@backstage/plugin-catalog-node';