diff --git a/.changeset/friendly-coins-approve.md b/.changeset/friendly-coins-approve.md new file mode 100644 index 0000000000..71a8240089 --- /dev/null +++ b/.changeset/friendly-coins-approve.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-app-backend': patch +--- + +Fixed unexpected behaviour where configuration supplied with `APP_CONFIG_*` environment variables where not filtered by the configuration schema. diff --git a/.changeset/green-cooks-sort.md b/.changeset/green-cooks-sort.md new file mode 100644 index 0000000000..51dd86ac2e --- /dev/null +++ b/.changeset/green-cooks-sort.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': minor +--- + +Adding negation keyword for entity filtering diff --git a/.changeset/healthy-shoes-judge.md b/.changeset/healthy-shoes-judge.md new file mode 100644 index 0000000000..eebd89a23d --- /dev/null +++ b/.changeset/healthy-shoes-judge.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-bitbucket-server': patch +--- + +Add `reviewers` input parameter to `publish:bitbucketServer:pull-request` diff --git a/.changeset/heavy-ties-tell.md b/.changeset/heavy-ties-tell.md new file mode 100644 index 0000000000..072b0c7860 --- /dev/null +++ b/.changeset/heavy-ties-tell.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend-module-microsoft-provider': patch +--- + +Add `skipUserProfile` config flag to Microsoft authenticator diff --git a/.changeset/poor-dodos-wait.md b/.changeset/poor-dodos-wait.md new file mode 100644 index 0000000000..f1d0b4e941 --- /dev/null +++ b/.changeset/poor-dodos-wait.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Add translation to the editor toolbar component. diff --git a/.changeset/pretty-buses-repair.md b/.changeset/pretty-buses-repair.md new file mode 100644 index 0000000000..e5575c36c1 --- /dev/null +++ b/.changeset/pretty-buses-repair.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Standardize template editor pages desktop and mobile layouts. diff --git a/.changeset/rare-rabbits-flow.md b/.changeset/rare-rabbits-flow.md new file mode 100644 index 0000000000..6b64957d59 --- /dev/null +++ b/.changeset/rare-rabbits-flow.md @@ -0,0 +1,29 @@ +--- +'@backstage/plugin-catalog-backend-module-bitbucket-cloud': minor +--- + +Fixes the event-based updates at `BitbucketCloudEntityProvider`. + +Previously, this entity provider had optional event support for legacy backends +that could be enabled by passing `catalogApi`, `events`, and `tokenManager`. + +For the new/current backend system, the `catalogModuleBitbucketCloudEntityProvider` +(`catalog.bitbucket-cloud-entity-provider`), event support was enabled by default. + +A recent change removed `tokenManager` as a dependency from the module as well as removed it as input. +While this didn't break the instantiation of the module, it broke the event-based updates, +and led to a runtime misbehavior, accompanied by an info log message. + +This change will replace the use of `tokenManager` with the use of `auth` (`AuthService`). + +Additionally, to simplify, it will make `catalogApi` and `events` required dependencies. +For the current backend system, this change is transparent and doesn't require any action. +For the legacy backend system, this change will require you to pass those dependencies +if you didn't do it already. + +BREAKING CHANGES: + +_(For legacy backend users only.)_ + +Previously optional `catalogApi`, and `events` are required now. +A new required dependency `auth` was added. diff --git a/.changeset/renovate-7874fad.md b/.changeset/renovate-7874fad.md new file mode 100644 index 0000000000..b7ccd5fe95 --- /dev/null +++ b/.changeset/renovate-7874fad.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-node': patch +--- + +Updated dependency `@smithy/node-http-handler` to `^3.0.0`. diff --git a/.changeset/rotten-camels-deny.md b/.changeset/rotten-camels-deny.md new file mode 100644 index 0000000000..f5660d953a --- /dev/null +++ b/.changeset/rotten-camels-deny.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Support `--max-warnings` flag for package linting diff --git a/.changeset/shy-plants-retire.md b/.changeset/shy-plants-retire.md new file mode 100644 index 0000000000..77427452f5 --- /dev/null +++ b/.changeset/shy-plants-retire.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search': patch +--- + +Updated the default SearchType.Accordion behavior to remain open after result type selection. This is a UX improvement to reduce the number of clicks needed when toggling result type filters. diff --git a/.changeset/silly-readers-build.md b/.changeset/silly-readers-build.md new file mode 100644 index 0000000000..4797c2b036 --- /dev/null +++ b/.changeset/silly-readers-build.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Add an actions filter on the list actions page and drawer. diff --git a/.changeset/thirty-pianos-mix.md b/.changeset/thirty-pianos-mix.md new file mode 100644 index 0000000000..147307ac9e --- /dev/null +++ b/.changeset/thirty-pianos-mix.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-techdocs-module-addons-contrib': patch +'@backstage/plugin-techdocs': patch +--- + +Use more of the available space for the navigation sidebar. diff --git a/.changeset/tricky-shoes-lie.md b/.changeset/tricky-shoes-lie.md new file mode 100644 index 0000000000..d7a17f0345 --- /dev/null +++ b/.changeset/tricky-shoes-lie.md @@ -0,0 +1,10 @@ +--- +'@backstage/plugin-catalog-graph': patch +--- + +Added InfoCard `action` attribute for CatalogGraphCard + +```tsx +const action = + , + ); + + expect( + screen.getByRole('button', { name: 'Custom action' }), + ).toBeInTheDocument(); + }); +}); diff --git a/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateEditorToolbar.tsx b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateEditorToolbar.tsx index a33915ae01..b09b4d861c 100644 --- a/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateEditorToolbar.tsx +++ b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateEditorToolbar.tsx @@ -31,18 +31,25 @@ import DialogActions from '@material-ui/core/DialogActions'; import ExtensionIcon from '@material-ui/icons/Extension'; import DescriptionIcon from '@material-ui/icons/Description'; -import { Link } from '@backstage/core-components'; +import { useTranslationRef } from '@backstage/frontend-plugin-api'; import { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react'; import { ActionPageContent } from '../../../components/ActionsPage/ActionsPage'; +import { scaffolderTranslationRef } from '../../../translation'; import { CustomFieldPlaygroud } from './CustomFieldPlaygroud'; const useStyles = makeStyles( theme => ({ paper: { - width: '40%', + width: '90%', padding: theme.spacing(2), backgroundColor: theme.palette.background.default, + [theme.breakpoints.up('sm')]: { + width: '70%', + }, + [theme.breakpoints.up('md')]: { + width: '50%', + }, }, appbar: { zIndex: 1, @@ -73,6 +80,7 @@ export function TemplateEditorToolbar(props: { }) { const { children, fieldExtensions } = props; const classes = useStyles(); + const { t } = useTranslationRef(scaffolderTranslationRef); const [showFieldsDrawer, setShowFieldsDrawer] = useState(false); const [showActionsDrawer, setShowActionsDrawer] = useState(false); const [showPublishModal, setShowPublishModal] = useState(false); @@ -81,22 +89,26 @@ export function TemplateEditorToolbar(props: {
{children}
- - + + - + - + - Publish changes + + {t('templateEditorToolbar.addToCatalogDialogTitle')} + - Follow the instructions below to create or update a template: -
    -
  1. Save the template files in a local directory
  2. -
  3. - Create a pull request to a new or existing git repository -
  4. -
  5. - If the template already exists, the changes will be reflected - in the software catalog once the pull request gets merged -
  6. -
  7. - But if you are creating a new template, follow this{' '} - - documentation - {' '} - to register the new template repository in software catalog -
  8. -
+ {t( + 'templateEditorToolbar.addToCatalogDialogContent.stepsIntroduction', + )} +
    + {t( + 'templateEditorToolbar.addToCatalogDialogContent.stepsListItems', + ) + .split('\n') + .map((step, index) => ( +
  • {step}
  • + ))} +
- diff --git a/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateEditorToolbarFileMenu.tsx b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateEditorToolbarFileMenu.tsx new file mode 100644 index 0000000000..9b8eee6162 --- /dev/null +++ b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateEditorToolbarFileMenu.tsx @@ -0,0 +1,109 @@ +/* + * Copyright 2024 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 React, { MouseEvent, useCallback, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; + +import Button from '@material-ui/core/Button'; +import Menu from '@material-ui/core/Menu'; +import MenuItem from '@material-ui/core/MenuItem'; + +import { useRouteRef } from '@backstage/core-plugin-api'; +import { useTranslationRef } from '@backstage/frontend-plugin-api'; + +import { editRouteRef } from '../../../routes'; +import { scaffolderTranslationRef } from '../../../translation'; + +export function TemplateEditorToolbarFileMenu(props: { + onOpenDirectory?: () => void; + onCreateDirectory?: () => void; + onCloseDirectory?: () => void; +}) { + const { onOpenDirectory, onCreateDirectory, onCloseDirectory } = props; + const navigate = useNavigate(); + const editLink = useRouteRef(editRouteRef); + const { t } = useTranslationRef(scaffolderTranslationRef); + const [anchorEl, setAnchorEl] = useState(null); + + const handleOpenMenu = useCallback( + (event: MouseEvent) => { + setAnchorEl(event.currentTarget); + }, + [setAnchorEl], + ); + + const handleCloseMenu = useCallback(() => { + setAnchorEl(null); + }, [setAnchorEl]); + + const handleOpenDirectory = useCallback(() => { + handleCloseMenu(); + onOpenDirectory?.(); + }, [handleCloseMenu, onOpenDirectory]); + + const handleCreateDirectory = useCallback(() => { + handleCloseMenu(); + onCreateDirectory?.(); + }, [handleCloseMenu, onCreateDirectory]); + + const handleCloseEditor = useCallback(() => { + handleCloseMenu(); + onCloseDirectory?.(); + navigate(editLink()); + }, [handleCloseMenu, onCloseDirectory, navigate, editLink]); + + return ( + <> + + + + {t('templateEditorToolbarFileMenu.options.openDirectory')} + + + {t('templateEditorToolbarFileMenu.options.createDirectory')} + + + {t('templateEditorToolbarFileMenu.options.closeEditor')} + + + + ); +} diff --git a/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateEditorToolbarTemplatesMenu.tsx b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateEditorToolbarTemplatesMenu.tsx new file mode 100644 index 0000000000..81ffac2c04 --- /dev/null +++ b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateEditorToolbarTemplatesMenu.tsx @@ -0,0 +1,110 @@ +/* + * Copyright 2024 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 React, { MouseEvent, useCallback, useState } from 'react'; + +import { makeStyles } from '@material-ui/core/styles'; +import Button from '@material-ui/core/Button'; +import Menu from '@material-ui/core/Menu'; +import MenuItem from '@material-ui/core/MenuItem'; + +import { Entity } from '@backstage/catalog-model'; +import { useTranslationRef } from '@backstage/frontend-plugin-api'; +import { scaffolderTranslationRef } from '../../../translation'; + +const ITEM_HEIGHT = 48; + +const useStyles = makeStyles({ + menu: { + maxHeight: ITEM_HEIGHT * 5, + }, +}); + +export type TemplateOption = { + label: string; + value: Entity; +}; + +export function TemplateEditorToolbarTemplatesMenu(props: { + options: TemplateOption[]; + selectedOption?: TemplateOption; + onSelectOption: (option: TemplateOption) => void; +}) { + const { options, selectedOption, onSelectOption } = props; + const classes = useStyles(); + const [anchorEl, setAnchorEl] = useState(null); + const { t } = useTranslationRef(scaffolderTranslationRef); + + const handleOpenMenu = useCallback( + (event: MouseEvent) => { + setAnchorEl(event.currentTarget); + }, + [setAnchorEl], + ); + + const handleCloseMenu = useCallback(() => { + setAnchorEl(null); + }, [setAnchorEl]); + + const handleSelectOption = useCallback( + (option: TemplateOption) => { + handleCloseMenu(); + onSelectOption(option); + }, + [handleCloseMenu, onSelectOption], + ); + + return ( + <> + + + {options.map((option, index) => ( + handleSelectOption(option)} + > + {option.label} + + ))} + + + ); +} diff --git a/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateFormPage.tsx b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateFormPage.tsx index b1f98878ad..7558276721 100644 --- a/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateFormPage.tsx +++ b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateFormPage.tsx @@ -61,6 +61,8 @@ export function TemplateFormPage(props: TemplateFormPageProps) {
{ const classes = useStyles(); - const { t } = useTranslationRef(scaffolderTranslationRef); const alertApi = useApi(alertApiRef); const catalogApi = useApi(catalogApiRef); const [errorText, setErrorText] = useState(); - const [selectedTemplate, setSelectedTemplate] = - useState(null); + const [selectedTemplate, setSelectedTemplate] = useState(); const [templateOptions, setTemplateOptions] = useState([]); const [templateYaml, setTemplateYaml] = useState(defaultPreviewTemplate); - const { loading } = useAsync( + useAsync( () => catalogApi .getEntities({ @@ -196,76 +173,42 @@ export const TemplateFormPreviewer = ({ const handleSelectChange = useCallback( // TODO(Rugvip): Afaik this should be Entity, but didn't want to make runtime changes while fixing types - (selected: any) => { + (selected: TemplateOption) => { setSelectedTemplate(selected); - setTemplateYaml(yaml.stringify(selected.spec)); + setTemplateYaml(yaml.stringify(selected.value.spec)); }, - [setTemplateYaml], + [setSelectedTemplate, setTemplateYaml], ); return ( - <> - {loading && } - -
- - - - - - - - } - renderValue={selected => { - if (!selected) { - return t('templateEditorPage.templateFormPreviewer.title'); - } - return (selected as Entity).metadata.title; - }} - inputProps={{ - 'aria-label': t( - 'templateEditorPage.templateFormPreviewer.title', - ), - }} - > - {templateOptions.map((option, index) => ( - - {option.label} - - ))} - - - -
-
- + + + + -
-
-
- -
-
-
- + + + + + + + + + ); }; diff --git a/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateIntroPage.tsx b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateIntroPage.tsx new file mode 100644 index 0000000000..b9825bc056 --- /dev/null +++ b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplateIntroPage.tsx @@ -0,0 +1,78 @@ +/* + * Copyright 2022 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 React from 'react'; +import { Content, Header, Page } from '@backstage/core-components'; + +import { WebFileSystemAccess } from '../../../lib/filesystem'; + +import { TemplateEditorIntro } from './TemplateEditorIntro'; +import { useNavigate } from 'react-router-dom'; +import { useRouteRef } from '@backstage/core-plugin-api'; +import { + rootRouteRef, + editorRouteRef, + templateFormRouteRef, + customFieldsRouteRef, +} from '../../../routes'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; +import { scaffolderTranslationRef } from '../../../translation'; +import { WebFileSystemStore } from '../../../lib/filesystem/WebFileSystemAccess'; +import { createExampleTemplate } from '../../../lib/filesystem/createExampleTemplate'; + +export function TemplateIntroPage() { + const navigate = useNavigate(); + const createLink = useRouteRef(rootRouteRef); + const editorLink = useRouteRef(editorRouteRef); + const templateFormLink = useRouteRef(templateFormRouteRef); + const customFieldsLink = useRouteRef(customFieldsRouteRef); + const { t } = useTranslationRef(scaffolderTranslationRef); + + return ( + +
+ + { + if (option === 'local') { + WebFileSystemAccess.requestDirectoryAccess() + .then(directory => WebFileSystemStore.setDirectory(directory)) + .then(() => navigate(editorLink())) + .catch(() => {}); + } else if (option === 'create-template') { + WebFileSystemAccess.requestDirectoryAccess() + .then(directory => { + createExampleTemplate(directory).then(() => { + WebFileSystemStore.setDirectory(directory); + navigate(editorLink()); + }); + }) + .catch(() => {}); + } else if (option === 'form') { + navigate(templateFormLink()); + } else if (option === 'field-explorer') { + navigate(customFieldsLink()); + } + }} + /> + + + ); +} diff --git a/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplatePage.tsx b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplatePage.tsx deleted file mode 100644 index b70ceba163..0000000000 --- a/plugins/scaffolder/src/alpha/components/TemplateEditorPage/TemplatePage.tsx +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2024 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 React, { useCallback } from 'react'; -import useAsyncRetry from 'react-use/esm/useAsyncRetry'; - -import { Page, Header, Content, Progress } from '@backstage/core-components'; -import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; -import { - FormProps, - FieldExtensionOptions, - type LayoutOptions, -} from '@backstage/plugin-scaffolder-react'; - -import { scaffolderTranslationRef } from '../../../translation'; -import { - WebFileSystemAccess, - WebFileSystemStore, -} from '../../../lib/filesystem'; -import { TemplateEditor } from './TemplateEditor'; - -import { makeStyles } from '@material-ui/core/styles'; - -const useStyles = makeStyles( - { - content: { - padding: 0, - }, - }, - { name: 'ScaffolderTemplateEditorToolbar' }, -); - -interface TemplatePageProps { - defaultPreviewTemplate?: string; - fieldExtensions?: FieldExtensionOptions[]; - layouts?: LayoutOptions[]; - formProps?: FormProps; -} - -export function TemplatePage(props: TemplatePageProps) { - const classes = useStyles(); - const { t } = useTranslationRef(scaffolderTranslationRef); - - const { value, loading, retry } = useAsyncRetry(async () => { - const directory = await WebFileSystemStore.getDirectory(); - if (!directory) return undefined; - return WebFileSystemAccess.fromHandle(directory); - }, []); - - const handleLoadDirectory = useCallback(() => { - WebFileSystemAccess.requestDirectoryAccess() - .then(WebFileSystemStore.setDirectory) - .then(retry); - }, [retry]); - - const handleCloseDirectory = useCallback(() => { - WebFileSystemStore.setDirectory(undefined).then(retry); - }, [retry]); - - return ( - -
- - {loading ? ( - - ) : ( - - )} - - - ); -} diff --git a/plugins/scaffolder/src/alpha/components/TemplateEditorPage/index.ts b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/index.ts index 84ab74da98..f16f2426d7 100644 --- a/plugins/scaffolder/src/alpha/components/TemplateEditorPage/index.ts +++ b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/index.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -export { TemplatePage } from './TemplatePage'; -export { TemplateFormPage } from './TemplateFormPage'; export { TemplateEditorPage } from './TemplateEditorPage'; +export { TemplateFormPage } from './TemplateFormPage'; +export { TemplateIntroPage } from './TemplateIntroPage'; export { CustomFieldsPage } from './CustomFieldsPage'; export type { ScaffolderCustomFieldExplorerClassKey } from './CustomFieldExplorer'; export type { ScaffolderTemplateEditorClassKey } from './TemplateEditor'; diff --git a/plugins/scaffolder/src/alpha/components/TemplateEditorPage/useTemplateDirectory.ts b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/useTemplateDirectory.ts new file mode 100644 index 0000000000..812a21e437 --- /dev/null +++ b/plugins/scaffolder/src/alpha/components/TemplateEditorPage/useTemplateDirectory.ts @@ -0,0 +1,66 @@ +/* + * Copyright 2024 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 { useCallback } from 'react'; +import useAsyncRetry from 'react-use/esm/useAsyncRetry'; + +import { + WebFileSystemAccess, + WebFileSystemStore, + WebDirectoryAccess, +} from '../../../lib/filesystem'; +import { createExampleTemplate } from '../../../lib/filesystem/createExampleTemplate'; + +export function useTemplateDirectory(): { + directory?: WebDirectoryAccess; + loading: boolean; + error?: Error; + handleOpenDirectory: () => void; + handleCreateDirectory: () => void; + handleCloseDirectory: () => void; +} { + const { value, loading, error, retry } = useAsyncRetry(async () => { + const directory = await WebFileSystemStore.getDirectory(); + if (!directory) return undefined; + return WebFileSystemAccess.fromHandle(directory); + }, []); + + const handleOpenDirectory = useCallback(() => { + WebFileSystemAccess.requestDirectoryAccess() + .then(WebFileSystemStore.setDirectory) + .then(retry); + }, [retry]); + + const handleCreateDirectory = useCallback(() => { + WebFileSystemAccess.requestDirectoryAccess() + .then(createExampleTemplate) + .then(WebFileSystemStore.setDirectory) + .then(retry); + }, [retry]); + + const handleCloseDirectory = useCallback(() => { + WebFileSystemStore.setDirectory(undefined).then(retry); + }, [retry]); + + return { + directory: value, + loading, + error, + handleOpenDirectory, + handleCreateDirectory, + handleCloseDirectory, + }; +} diff --git a/plugins/scaffolder/src/components/ActionsPage/ActionsPage.test.tsx b/plugins/scaffolder/src/components/ActionsPage/ActionsPage.test.tsx index b548bcbad4..bf056dd3b3 100644 --- a/plugins/scaffolder/src/components/ActionsPage/ActionsPage.test.tsx +++ b/plugins/scaffolder/src/components/ActionsPage/ActionsPage.test.tsx @@ -509,4 +509,81 @@ describe('TemplatePage', () => { expect(rendered.getByText('array(unknown)')).toBeInTheDocument(); }); + + it('should filter an action', async () => { + scaffolderApiMock.listActions.mockResolvedValue([ + { + id: 'githut:repo:create', + description: 'Create a new Github repository', + schema: { + input: { + type: 'object', + required: ['name'], + properties: { + name: { + title: 'Repository name', + type: 'string', + }, + }, + }, + }, + }, + { + id: 'githut:repo:push', + description: 'Push to a Github repository', + schema: { + input: { + type: 'object', + required: ['url'], + properties: { + url: { + title: 'Repository url', + type: 'string', + }, + }, + }, + }, + }, + ]); + + const rendered = await renderInTestApp( + + + , + { + mountedRoutes: { + '/create/actions': rootRouteRef, + }, + }, + ); + + expect( + rendered.getByRole('heading', { name: 'githut:repo:create' }), + ).toBeInTheDocument(); + expect( + rendered.getByRole('heading', { name: 'githut:repo:push' }), + ).toBeInTheDocument(); + + // should filter actions when searching + await userEvent.type( + rendered.getByPlaceholderText('Search for an action'), + 'create', + ); + await userEvent.keyboard('[ArrowDown][Enter]'); + expect( + rendered.getByRole('heading', { name: 'githut:repo:create' }), + ).toBeInTheDocument(); + expect( + rendered.queryByRole('heading', { name: 'githut:repo:push' }), + ).not.toBeInTheDocument(); + + // should show all actions when clearing the search + await userEvent.click(rendered.getByTitle('Clear')); + expect( + rendered.getByRole('heading', { name: 'githut:repo:create' }), + ).toBeInTheDocument(); + expect( + rendered.getByRole('heading', { name: 'githut:repo:push' }), + ).toBeInTheDocument(); + }); }); diff --git a/plugins/scaffolder/src/components/ActionsPage/ActionsPage.tsx b/plugins/scaffolder/src/components/ActionsPage/ActionsPage.tsx index 0949d948fc..539a5697d3 100644 --- a/plugins/scaffolder/src/components/ActionsPage/ActionsPage.tsx +++ b/plugins/scaffolder/src/components/ActionsPage/ActionsPage.tsx @@ -16,6 +16,7 @@ import React, { Fragment, useEffect, useState } from 'react'; import useAsync from 'react-use/esm/useAsync'; import { + Action, ActionExample, scaffolderApiRef, } from '@backstage/plugin-scaffolder-react'; @@ -39,6 +40,10 @@ import classNames from 'classnames'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import ExpandLessIcon from '@material-ui/icons/ExpandLess'; import LinkIcon from '@material-ui/icons/Link'; +import Autocomplete from '@material-ui/lab/Autocomplete'; +import TextField from '@material-ui/core/TextField'; +import InputAdornment from '@material-ui/core/InputAdornment'; +import SearchIcon from '@material-ui/icons/Search'; import { useApi, useRouteRef } from '@backstage/core-plugin-api'; import { @@ -125,14 +130,19 @@ export const ActionPageContent = () => { const { t } = useTranslationRef(scaffolderTranslationRef); const classes = useStyles(); - const { loading, value, error } = useAsync(async () => { + const { + loading, + value = [], + error, + } = useAsync(async () => { return api.listActions(); }, [api]); + const [selectedAction, setSelectedAction] = useState(null); const [isExpanded, setIsExpanded] = useState<{ [key: string]: boolean }>({}); useEffect(() => { - if (value && window.location.hash) { + if (value.length && window.location.hash) { document.querySelector(window.location.hash)?.scrollIntoView(); } }, [value]); @@ -295,71 +305,107 @@ export const ActionPageContent = () => { ); }; - return value?.map(action => { - if (action.id.startsWith('legacy:')) { - return undefined; - } - - const oneOf = renderTables( - 'oneOf', - `${action.id}.input`, - action.schema?.input?.oneOf, - ); - return ( - - - {action.id} - - - - - {action.description && } - {action.schema?.input && ( - - - {t('actionsPage.action.input')} - - {renderTable( - formatRows(`${action.id}.input`, action?.schema?.input), - )} - {oneOf} - - )} - {action.schema?.output && ( - - - {t('actionsPage.action.output')} - - {renderTable( - formatRows(`${action.id}.output`, action?.schema?.output), - )} - - )} - {action.examples && ( - - }> - - {t('actionsPage.action.examples')} - - - - - - - - - )} + return ( + <> + + option.id} + renderInput={params => ( + + + + ), + }} + /> + )} + onChange={(_event, option) => { + setSelectedAction(option); + }} + fullWidth + /> - ); - }); + {(selectedAction ? [selectedAction] : value).map(action => { + if (action.id.startsWith('legacy:')) { + return undefined; + } + + const oneOf = renderTables( + 'oneOf', + `${action.id}.input`, + action.schema?.input?.oneOf, + ); + return ( + + + + {action.id} + + + + + + {action.description && ( + + )} + {action.schema?.input && ( + + + {t('actionsPage.action.input')} + + {renderTable( + formatRows(`${action.id}.input`, action?.schema?.input), + )} + {oneOf} + + )} + {action.schema?.output && ( + + + {t('actionsPage.action.output')} + + {renderTable( + formatRows(`${action.id}.output`, action?.schema?.output), + )} + + )} + {action.examples && ( + + }> + + {t('actionsPage.action.examples')} + + + + + + + + + )} + + ); + })} + + ); }; export const ActionsPage = () => { const navigate = useNavigate(); diff --git a/plugins/scaffolder/src/components/Router/Router.tsx b/plugins/scaffolder/src/components/Router/Router.tsx index e79d930795..5766e3d043 100644 --- a/plugins/scaffolder/src/components/Router/Router.tsx +++ b/plugins/scaffolder/src/components/Router/Router.tsx @@ -54,8 +54,8 @@ import { import { TemplateListPage, TemplateWizardPage } from '../../alpha/components'; import { OngoingTask } from '../OngoingTask'; import { - TemplatePage, TemplateFormPage, + TemplateIntroPage, TemplateEditorPage, CustomFieldsPage, } from '../../alpha/components/TemplateEditorPage'; @@ -171,7 +171,7 @@ export const Router = (props: PropsWithChildren) => { path={editRouteRef.path} element={ - + } /> @@ -205,7 +205,7 @@ export const Router = (props: PropsWithChildren) => { path={editorRouteRef.path} element={ - { diff --git a/plugins/scaffolder/src/lib/filesystem/createExampleTemplate.ts b/plugins/scaffolder/src/lib/filesystem/createExampleTemplate.ts index b93d678d5e..e3d0053d69 100644 --- a/plugins/scaffolder/src/lib/filesystem/createExampleTemplate.ts +++ b/plugins/scaffolder/src/lib/filesystem/createExampleTemplate.ts @@ -91,4 +91,5 @@ export async function createExampleTemplate( for (const [name, data] of Object.entries(files)) { await directory.createFile({ name, data }); } + return directory; } diff --git a/plugins/scaffolder/src/lib/filesystem/index.ts b/plugins/scaffolder/src/lib/filesystem/index.ts index 29f72294ea..4f5c9ff08c 100644 --- a/plugins/scaffolder/src/lib/filesystem/index.ts +++ b/plugins/scaffolder/src/lib/filesystem/index.ts @@ -16,4 +16,8 @@ export type { TemplateFileAccess, TemplateDirectoryAccess } from './types'; export { blobToBase64 } from './helpers'; -export { WebFileSystemAccess, WebFileSystemStore } from './WebFileSystemAccess'; +export { + WebDirectoryAccess, + WebFileSystemAccess, + WebFileSystemStore, +} from './WebFileSystemAccess'; diff --git a/plugins/scaffolder/src/translation.ts b/plugins/scaffolder/src/translation.ts index 11c13194ce..7299d3245a 100644 --- a/plugins/scaffolder/src/translation.ts +++ b/plugins/scaffolder/src/translation.ts @@ -29,6 +29,7 @@ export const scaffolderTranslationRef = createTranslationRef({ description: 'There are no actions installed or there was an issue communicating with backend.', }, + searchFieldPlaceholder: 'Search for an action', tableCell: { name: 'Name', title: 'Title', @@ -194,12 +195,21 @@ export const scaffolderTranslationRef = createTranslationRef({ templateTypePicker: { title: 'Categories', }, + templateIntroPage: { + title: 'Manage Templates', + subtitle: + 'Edit, preview, and try out templates, forms, and custom fields', + }, templateFormPage: { - title: 'Template Form Playground', - subtitle: 'Edit, preview, and try out templates and template forms', + title: 'Template Editor', + subtitle: 'Edit, preview, and try out templates forms', + }, + templateCustomFieldPage: { + title: 'Custom Field Explorer', + subtitle: 'Edit, preview, and try out custom fields', }, templateEditorPage: { - title: 'Manage Templates', + title: 'Template Editor', subtitle: 'Edit, preview, and try out templates and template forms', dryRunResults: { title: 'Dry-run results', @@ -253,7 +263,7 @@ export const scaffolderTranslationRef = createTranslationRef({ unsupportedTooltip: 'Only supported in some Chromium-based browsers', }, formEditor: { - title: 'Template playground', + title: 'Template Form Playground', description: 'Preview and edit a template form, either using a sample template or by loading a template from the catalog.', }, @@ -266,6 +276,7 @@ export const scaffolderTranslationRef = createTranslationRef({ templateEditorTextArea: { saveIconTooltip: 'Save file', refreshIconTooltip: 'Reload file', + emptyStateParagraph: 'Please select an action on the file menu.', }, templateFormPreviewer: { title: 'Load Existing Template', @@ -298,5 +309,33 @@ export const scaffolderTranslationRef = createTranslationRef({ editConfigurationTitle: 'Edit Configuration', }, }, + templateEditorToolbar: { + customFieldExplorerTooltip: 'Custom Fields Explorer', + installedActionsDocumentationTooltip: 'Installed Actions Documentation', + addToCatalogButton: 'Publish', + addToCatalogDialogTitle: 'Publish changes', + addToCatalogDialogContent: { + stepsIntroduction: + 'Follow the instructions below to create or update a template:', + stepsListItems: + 'Save the template files in a local directory\nCreate a pull request to a new or existing git repository\nIf the template already exists, the changes will be reflected in the software catalog once the pull request gets merged\nBut if you are creating a new template, follow the documentation linked below to register the new template repository in software catalog', + }, + addToCatalogDialogActions: { + documentationButton: 'Go to the documentation', + documentationUrl: + 'https://backstage.io/docs/features/software-templates/adding-templates/', + }, + }, + templateEditorToolbarFileMenu: { + button: 'File', + options: { + openDirectory: 'Open template directory', + createDirectory: 'Create template directory', + closeEditor: 'Close template editor', + }, + }, + templateEditorToolbarTemplatesMenu: { + button: 'Templates', + }, }, }); diff --git a/plugins/search/src/components/SearchType/SearchType.Accordion.test.tsx b/plugins/search/src/components/SearchType/SearchType.Accordion.test.tsx index 556a9550a0..453b766791 100644 --- a/plugins/search/src/components/SearchType/SearchType.Accordion.test.tsx +++ b/plugins/search/src/components/SearchType/SearchType.Accordion.test.tsx @@ -140,18 +140,6 @@ describe('SearchType.Accordion', () => { expect(setPageCursorMock).toHaveBeenCalledWith(undefined); }); - it('should collapse when a new type is selected', async () => { - const { getByText, queryByText } = render( - - - , - ); - - await user.click(getByText(expectedType.name)); - - expect(queryByText('Collapse')).not.toBeInTheDocument(); - }); - it('should show result counts if enabled', async () => { const { getAllByText } = render( diff --git a/plugins/search/src/components/SearchType/SearchType.Accordion.tsx b/plugins/search/src/components/SearchType/SearchType.Accordion.tsx index f9a07b6dcd..bdd13f2fb2 100644 --- a/plugins/search/src/components/SearchType/SearchType.Accordion.tsx +++ b/plugins/search/src/components/SearchType/SearchType.Accordion.tsx @@ -96,7 +96,6 @@ export const SearchTypeAccordion = (props: SearchTypeAccordionProps) => { return () => { setTypes(type !== '' ? [type] : []); setPageCursor(undefined); - setExpanded(false); }; }; diff --git a/plugins/techdocs-module-addons-contrib/src/ExpandableNavigation/ExpandableNavigation.tsx b/plugins/techdocs-module-addons-contrib/src/ExpandableNavigation/ExpandableNavigation.tsx index 802e377f42..6cdf87a49f 100644 --- a/plugins/techdocs-module-addons-contrib/src/ExpandableNavigation/ExpandableNavigation.tsx +++ b/plugins/techdocs-module-addons-contrib/src/ExpandableNavigation/ExpandableNavigation.tsx @@ -30,8 +30,9 @@ const EXPANDABLE_NAVIGATION_LOCAL_STORAGE = const StyledButton = withStyles({ root: { position: 'absolute', - left: '220px', + left: '13.7rem', // Sidebar inner width (15.1em) minus the different margins/paddings top: '19px', + zIndex: 2, padding: 0, minWidth: 0, }, diff --git a/plugins/techdocs-node/package.json b/plugins/techdocs-node/package.json index a66c34935e..b72894a6d3 100644 --- a/plugins/techdocs-node/package.json +++ b/plugins/techdocs-node/package.json @@ -62,7 +62,7 @@ "@backstage/plugin-search-common": "workspace:^", "@backstage/plugin-techdocs-common": "workspace:^", "@google-cloud/storage": "^7.0.0", - "@smithy/node-http-handler": "^2.1.7", + "@smithy/node-http-handler": "^3.0.0", "@trendyol-js/openstack-swift-sdk": "^0.0.7", "@types/express": "^4.17.6", "dockerode": "^4.0.0", diff --git a/plugins/techdocs/src/reader/transformers/styles/rules/layout.ts b/plugins/techdocs/src/reader/transformers/styles/rules/layout.ts index 590f2a114b..1a326c62b8 100644 --- a/plugins/techdocs/src/reader/transformers/styles/rules/layout.ts +++ b/plugins/techdocs/src/reader/transformers/styles/rules/layout.ts @@ -86,9 +86,14 @@ export default ({ theme, sidebar }: RuleOptions) => ` scrollbar-width: thin; } .md-sidebar .md-sidebar__scrollwrap { - width: calc(12.1rem); + width: calc(16rem); overflow-y: hidden; } +@supports selector(::-webkit-scrollbar) { + [dir=ltr] .md-sidebar__inner { + padding-right: calc(100% - 15.1rem); + } +} .md-sidebar--secondary { right: ${theme.spacing(3)}px; } @@ -202,18 +207,22 @@ export default ({ theme, sidebar }: RuleOptions) => ` height: 100%; } .md-sidebar--primary { - width: 12.1rem !important; + width: 16rem !important; z-index: 200; left: ${ sidebar.isPinned - ? `calc(-12.1rem + ${SIDEBAR_WIDTH})` - : 'calc(-12.1rem + 72px)' + ? `calc(-16rem + ${SIDEBAR_WIDTH})` + : 'calc(-16rem + 72px)' } !important; } .md-sidebar--secondary:not([hidden]) { display: none; } + [data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary { + transform: translateX(16rem); + } + .md-content { max-width: 100%; margin-left: 0; @@ -241,8 +250,8 @@ export default ({ theme, sidebar }: RuleOptions) => ` @media screen and (max-width: 600px) { .md-sidebar--primary { - left: -12.1rem !important; - width: 12.1rem; + left: -16rem !important; + width: 16rem; } } diff --git a/yarn.lock b/yarn.lock index 93d7efa51d..2d1cc17f58 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5581,7 +5581,6 @@ __metadata: version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-backend-module-bitbucket-cloud@workspace:plugins/catalog-backend-module-bitbucket-cloud" dependencies: - "@backstage/backend-common": ^0.25.0 "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-test-utils": "workspace:^" "@backstage/catalog-client": "workspace:^" @@ -8276,7 +8275,7 @@ __metadata: "@backstage/plugin-search-common": "workspace:^" "@backstage/plugin-techdocs-common": "workspace:^" "@google-cloud/storage": ^7.0.0 - "@smithy/node-http-handler": ^2.1.7 + "@smithy/node-http-handler": ^3.0.0 "@trendyol-js/openstack-swift-sdk": ^0.0.7 "@types/express": ^4.17.6 "@types/fs-extra": ^11.0.0 @@ -8756,8 +8755,8 @@ __metadata: linkType: hard "@changesets/cli@npm:^2.14.0": - version: 2.27.8 - resolution: "@changesets/cli@npm:2.27.8" + version: 2.27.9 + resolution: "@changesets/cli@npm:2.27.9" dependencies: "@changesets/apply-release-plan": ^7.0.5 "@changesets/assemble-release-plan": ^6.0.4 @@ -8774,14 +8773,12 @@ __metadata: "@changesets/types": ^6.0.0 "@changesets/write": ^0.3.2 "@manypkg/get-packages": ^1.1.3 - "@types/semver": ^7.5.0 ansi-colors: ^4.1.3 ci-info: ^3.7.0 enquirer: ^2.3.0 external-editor: ^3.1.0 fs-extra: ^7.0.1 mri: ^1.2.0 - outdent: ^0.5.0 p-limit: ^2.2.0 package-manager-detector: ^0.2.0 picocolors: ^1.1.0 @@ -8791,7 +8788,7 @@ __metadata: term-size: ^2.1.0 bin: changeset: bin.js - checksum: b58386716b337976d5797debd4a418fb257bec1e6c9932b99eac7725dd5a76fceff32691c625f897fd4baa78aa2bfba9747fbacf7d8193197f9246b36d31c013 + checksum: 4bd36c152f9f93716b001f3ed849717588d2a9eb97f058e86f95ba6a43d8e4311073174251150aabb96f0a1ab5f8ab5ee6a32f85fc9248363f92b3826227cb9d languageName: node linkType: hard @@ -8977,8 +8974,8 @@ __metadata: linkType: hard "@codemirror/language@npm:^6.0.0": - version: 6.10.2 - resolution: "@codemirror/language@npm:6.10.2" + version: 6.10.3 + resolution: "@codemirror/language@npm:6.10.3" dependencies: "@codemirror/state": ^6.0.0 "@codemirror/view": ^6.23.0 @@ -8986,7 +8983,7 @@ __metadata: "@lezer/highlight": ^1.0.0 "@lezer/lr": ^1.0.0 style-mod: ^4.0.0 - checksum: 4e60afb75fb56519f59d9d85e0aa03f0c8d017e0da0f3f8f321baf35a776801fcec9787f3d0c029eba12aa766fba98b0fe86fc3111b43e0812b554184c0e8d67 + checksum: 53fb72299500f63706f78c888d6b5fd81043ea11ea2fa4c72c13c6d4794bb6f4ec29450208c56b4f40e839984b3dc73505262803fa61416baf588da389a7c577 languageName: node linkType: hard @@ -9041,13 +9038,13 @@ __metadata: linkType: hard "@codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.23.0": - version: 6.33.0 - resolution: "@codemirror/view@npm:6.33.0" + version: 6.34.1 + resolution: "@codemirror/view@npm:6.34.1" dependencies: "@codemirror/state": ^6.4.0 style-mod: ^4.1.0 w3c-keyname: ^2.2.4 - checksum: e28896a7fb40df8e7221fbebfc2cd92c10c6963948e20f3a4300e99c897fbddd091f4fc90cc30eeaf90d07c61dcf6170cd3c164810606fa07337ffb970ffdac2 + checksum: 5c7bf199f0b45a3cc192f08c2ac89e5ab972f313cb4f2c979edf6e05b27bccd60c6cb42d5dacb6813ef3a928d75476eb0a00ffdeffd7431c8e9f44bab4f6e12e languageName: node linkType: hard @@ -15291,16 +15288,6 @@ __metadata: languageName: node linkType: hard -"@smithy/abort-controller@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/abort-controller@npm:2.2.0" - dependencies: - "@smithy/types": ^2.12.0 - tslib: ^2.6.2 - checksum: d0d7fcaa7b67b04c9ad825017110cc294ff06af07f8054ac3b75d8de88ff5fbef1d08f5c1ae672db1839d14ce25f277c459d2b7b7263cbe9e6c3d4518a19230e - languageName: node - linkType: hard - "@smithy/abort-controller@npm:^3.1.2": version: 3.1.2 resolution: "@smithy/abort-controller@npm:3.1.2" @@ -15591,20 +15578,7 @@ __metadata: languageName: node linkType: hard -"@smithy/node-http-handler@npm:^2.1.7": - version: 2.5.0 - resolution: "@smithy/node-http-handler@npm:2.5.0" - dependencies: - "@smithy/abort-controller": ^2.2.0 - "@smithy/protocol-http": ^3.3.0 - "@smithy/querystring-builder": ^2.2.0 - "@smithy/types": ^2.12.0 - tslib: ^2.6.2 - checksum: 2e63fafdac5bef62181994af2ec065b0f7f04eaed88fb2990a21a9925226fead5013cf4f232b527f3f4d9ffb68ccbe8cd263ad22a7351d36b0dc23e975929a0c - languageName: node - linkType: hard - -"@smithy/node-http-handler@npm:^3.2.0": +"@smithy/node-http-handler@npm:^3.0.0, @smithy/node-http-handler@npm:^3.2.0": version: 3.2.0 resolution: "@smithy/node-http-handler@npm:3.2.0" dependencies: @@ -15627,16 +15601,6 @@ __metadata: languageName: node linkType: hard -"@smithy/protocol-http@npm:^3.3.0": - version: 3.3.0 - resolution: "@smithy/protocol-http@npm:3.3.0" - dependencies: - "@smithy/types": ^2.12.0 - tslib: ^2.6.2 - checksum: 6c1aaaee9f6ecfb841766938312268f30cbda253f172de7467463aae7d7bfea19a801ab570f3737334e992d2d0ee7446e6af6a6fd82b08533790c489289dff76 - languageName: node - linkType: hard - "@smithy/protocol-http@npm:^4.1.1": version: 4.1.1 resolution: "@smithy/protocol-http@npm:4.1.1" @@ -15647,17 +15611,6 @@ __metadata: languageName: node linkType: hard -"@smithy/querystring-builder@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/querystring-builder@npm:2.2.0" - dependencies: - "@smithy/types": ^2.12.0 - "@smithy/util-uri-escape": ^2.2.0 - tslib: ^2.6.2 - checksum: db492903302a694a0e982c37b9a74314160c5ee485742f24f8b6d0da66f121e7ff8588742a3a1964f6b983c15cacd52b883c5efa714882a754f575da7a7e014d - languageName: node - linkType: hard - "@smithy/querystring-builder@npm:^3.0.4": version: 3.0.4 resolution: "@smithy/querystring-builder@npm:3.0.4" @@ -15737,15 +15690,6 @@ __metadata: languageName: node linkType: hard -"@smithy/types@npm:^2.12.0": - version: 2.12.0 - resolution: "@smithy/types@npm:2.12.0" - dependencies: - tslib: ^2.6.2 - checksum: 2dd93746624d87afbf51c22116fc69f82e95004b78cf681c4a283d908155c22a2b7a3afbd64a3aff7deefb6619276f186e212422ad200df3b42c32ef5330374e - languageName: node - linkType: hard - "@smithy/types@npm:^3.4.0": version: 3.4.0 resolution: "@smithy/types@npm:3.4.0" @@ -15909,15 +15853,6 @@ __metadata: languageName: node linkType: hard -"@smithy/util-uri-escape@npm:^2.2.0": - version: 2.2.0 - resolution: "@smithy/util-uri-escape@npm:2.2.0" - dependencies: - tslib: ^2.6.2 - checksum: bade35312d75d1c84226f2a81b70dfef91766c02ecb6c6854b6f920cddb423e01963f7d0c183d523b5991f8e7ca93bcf73f8b3c6923979152b8350c9f3c24fd6 - languageName: node - linkType: hard - "@smithy/util-uri-escape@npm:^3.0.0": version: 3.0.0 resolution: "@smithy/util-uri-escape@npm:3.0.0" @@ -18136,9 +18071,9 @@ __metadata: linkType: hard "@types/lodash@npm:^4.14.151": - version: 4.17.9 - resolution: "@types/lodash@npm:4.17.9" - checksum: 6d1bf3e77f0a54d97532755a74260d402d8972259c5451b74612c16cb983b73e0760e5bfe4f9e68ab15051511c867812b40715a01f9805afe6bc36c7dd676378 + version: 4.17.10 + resolution: "@types/lodash@npm:4.17.10" + checksum: 4600f2f25270c8fee6953e363d318149a5f0f1b1bb820aa2f42d7ada6e4f7de31848bb5ffc2c687b40bd73aa982167bdd6e6d8d456e72abe0c660ec77d1fa7e9 languageName: node linkType: hard @@ -35229,11 +35164,9 @@ __metadata: linkType: hard "node-mocks-http@npm:^1.0.0": - version: 1.16.0 - resolution: "node-mocks-http@npm:1.16.0" + version: 1.16.1 + resolution: "node-mocks-http@npm:1.16.1" dependencies: - "@types/express": ^4.17.21 - "@types/node": "*" accepts: ^1.3.7 content-disposition: ^0.5.3 depd: ^1.1.0 @@ -35244,7 +35177,15 @@ __metadata: parseurl: ^1.3.3 range-parser: ^1.2.0 type-is: ^1.6.18 - checksum: 21ccf1ecaaa6ee0f7c061a7063f59d59c9793a485a907c09c83ff73b12f205ef87537022a4ba8ad937d07454ee0450290093d4a66a4df21e7e8b3696d23e1a7d + peerDependencies: + "@types/express": ^4.17.21 || ^5.0.0 + "@types/node": "*" + peerDependenciesMeta: + "@types/express": + optional: true + "@types/node": + optional: true + checksum: 198030725eac236062eb3547a7d5cec2d6f2d44bf05efab0ea621e90f671d6966dca2873faaea9bcbb5dde92a222aff0610a01d453c2f76b0bc5dbdf4bd8057a languageName: node linkType: hard