diff --git a/.changeset/gentle-deers-return.md b/.changeset/gentle-deers-return.md
new file mode 100644
index 0000000000..5784226b1d
--- /dev/null
+++ b/.changeset/gentle-deers-return.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-techdocs': patch
+---
+
+Allow passing down `withSearch` prop to `EntityTechdocsContent` component since it was `true` by default, now user can use the `EntityTechdocsContent` component _without_ showing the search field on top of the content.
diff --git a/.changeset/little-scissors-fold.md b/.changeset/little-scissors-fold.md
new file mode 100644
index 0000000000..1b70e3977d
--- /dev/null
+++ b/.changeset/little-scissors-fold.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-scaffolder-react': patch
+---
+
+Fix field extension validation not working when field is in dependencies in an array field
diff --git a/.changeset/red-hotels-sneeze.md b/.changeset/red-hotels-sneeze.md
new file mode 100644
index 0000000000..a1ce4d7bd6
--- /dev/null
+++ b/.changeset/red-hotels-sneeze.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-catalog': patch
+---
+
+Fixing spelling mistake in translation
diff --git a/.github/workflows/deploy_docker-image.yml b/.github/workflows/deploy_docker-image.yml
index a1764b976a..2285f61f48 100644
--- a/.github/workflows/deploy_docker-image.yml
+++ b/.github/workflows/deploy_docker-image.yml
@@ -59,7 +59,7 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1
+ uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
- name: Build and push
uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0
diff --git a/ADOPTERS.md b/ADOPTERS.md
index 4ab88c398a..1eacd4c104 100644
--- a/ADOPTERS.md
+++ b/ADOPTERS.md
@@ -281,4 +281,5 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/
| [Tele2 Kazakhstan](https://tele2.kz/) / [Altel Digital](https://digital.altel.kz/) | [Kuanysh Bekkulov](https://www.linkedin.com/in/kuanysh-bekkulov/), [Alexandr Puzeyev](https://www.linkedin.com/in/alexandr-puzeyev/) | Developer portal: services, components, APIs, and resources; includes documentation (Docs-as-Code), service templates, and plugins for integration with internal systems and tools.
| [Axelerant](https://www.axelerant.com/) | [Zeshan Ziya](https://github.com/zeshanziya) | Developer portal, main gateway to infrastructure, documentation, internal tooling, and service catalog with a focus on project visibility.
| [KnowBe4](https://www.knowbe4.com) | [Brandon Vicinus](https://www.linkedin.com/in/bvicinus/) | Internal Developer Portal managed by the Developer Experience Team. IDP hosts many different internal tools as plugins created by multiple teams, many of which are directly integrated with the Service Catalog. |
+| [Scalepoint](https://scalepoint.com) | [Yuriy Ostapenko](https://github.com/yuriyostapenko), [Dmytro Pasko](https://github.com/dimapasko), [Yuri Sedykh ](https://github.com/yuiri-sedykh), [Bartosz Wisniewski](https://github.com/Epgor) | Internal Developer Portal: Software Catalog with infrastructure resources and dependencies, Software Templates, TechDocs, Tech Radar, Kubernetes and Observability, as well as custom CI/CD components |
diff --git a/docs/conf/writing.md b/docs/conf/writing.md
index 6e827c075e..85a719e1d0 100644
--- a/docs/conf/writing.md
+++ b/docs/conf/writing.md
@@ -239,4 +239,7 @@ privateKey: |
-----END RSA PRIVATE KEY-----
```
-**Warning: Sensitive information, such as private keys, should not be hard coded**. We recommend that this entire file should be a secret and stored as such in a secure storage solution like Vault, to ensure they are neither exposed nor misused. This example key part only shows the format on how to use the yaml | syntax to make sure that the key is valid.
+> [!WARNING]
+> Sensitive information, such as private keys, should not be hard coded.
+
+We recommend that this entire file should be a secret and stored as such in a secure storage solution like Vault, to ensure they are neither exposed nor misused. This example key part only shows the format on how to use the yaml | syntax to make sure that the key is valid.
diff --git a/docs/features/software-templates/writing-custom-actions.md b/docs/features/software-templates/writing-custom-actions.md
index 11e67af07f..8cfc5464f2 100644
--- a/docs/features/software-templates/writing-custom-actions.md
+++ b/docs/features/software-templates/writing-custom-actions.md
@@ -220,7 +220,7 @@ const scaffolderModuleCustomExtensions = createBackendModule({
async init({ scaffolder /* ..., other dependencies */ }) {
// Here you have the opportunity to interact with the extension
// point before the plugin itself gets instantiated
- scaffolder.addActions(new createNewFileAction()); // just an example
+ scaffolder.addActions(createNewFileAction()); // just an example
},
});
},
diff --git a/microsite/data/plugins/cyclops-modules.yaml b/microsite/data/plugins/cyclops-modules.yaml
new file mode 100644
index 0000000000..f2c083295e
--- /dev/null
+++ b/microsite/data/plugins/cyclops-modules.yaml
@@ -0,0 +1,14 @@
+---
+title: Cyclops Modules
+author: Cyclops UI
+authorUrl: https://cyclops-ui.com/
+category: App Delivery
+description: Manage Cyclops Modules through Backstage catalog
+documentation: https://github.com/cyclops-ui/backstage-plugins#readme
+iconUrl: /img/cyclops.svg
+npmPackageName: '@cyclopsui/backstage-plugin-cyclops-modules'
+tags:
+ - Kubernetes
+ - Productivity
+ - Delivery
+addedDate: '2024-01-02'
diff --git a/microsite/data/plugins/knative-event-mesh.yaml b/microsite/data/plugins/knative-event-mesh.yaml
index 107114cc78..6ecb219b32 100644
--- a/microsite/data/plugins/knative-event-mesh.yaml
+++ b/microsite/data/plugins/knative-event-mesh.yaml
@@ -6,4 +6,5 @@ category: Monitoring
description: A plugin that provides a way to view and manage Knative Event Mesh resources.
documentation: https://knative.dev/docs/install/installing-backstage-plugins/
npmPackageName: '@knative-extensions/plugin-knative-event-mesh-backend'
+iconUrl: https://raw.githubusercontent.com/knative/community/refs/heads/main/icons/logo.svg
addedDate: '2024-12-16'
diff --git a/microsite/src/pages/community/index.tsx b/microsite/src/pages/community/index.tsx
index c9367f4662..171a5efcdf 100644
--- a/microsite/src/pages/community/index.tsx
+++ b/microsite/src/pages/community/index.tsx
@@ -106,6 +106,11 @@ const Community = () => {
url: 'https://www.alauda.io/community/169249',
logo: 'img/partner-logo-alauda.png',
},
+ {
+ name: 'Liatrio',
+ url: 'https://www.liatrio.com/service-offerings/backstage',
+ logo: 'img/partner-logo-liatrio.png',
+ },
];
//#endregion
diff --git a/microsite/static/img/cyclops.svg b/microsite/static/img/cyclops.svg
new file mode 100644
index 0000000000..fbc297443c
--- /dev/null
+++ b/microsite/static/img/cyclops.svg
@@ -0,0 +1,51 @@
+
+
diff --git a/microsite/static/img/partner-logo-alauda.png b/microsite/static/img/partner-logo-alauda.png
index 09392a2582..b43719deb9 100644
Binary files a/microsite/static/img/partner-logo-alauda.png and b/microsite/static/img/partner-logo-alauda.png differ
diff --git a/microsite/static/img/partner-logo-liatrio.png b/microsite/static/img/partner-logo-liatrio.png
new file mode 100644
index 0000000000..bd6238cf8c
Binary files /dev/null and b/microsite/static/img/partner-logo-liatrio.png differ
diff --git a/packages/yarn-plugin/README.md b/packages/yarn-plugin/README.md
index 67ea19b1bd..c1d5647b8e 100644
--- a/packages/yarn-plugin/README.md
+++ b/packages/yarn-plugin/README.md
@@ -24,3 +24,17 @@ The resulting changes in the file system should be committed to your repo.
The yarn plugin recognizes the version string `"backstage:^"`, and replaces it
with the appropriate version based on the overall Backstage version in
backstage.json.
+
+## Local Development
+
+- Run unit tests: `yarn test`
+- Build the plugin locally: `yarn build`
+- Rebuild whenever plugin files change: `yarn start`
+- Install local build (in a package directory outside the Backstage monorepo):
+ `yarn plugin import
+/path/to/backstage-repo/packages/yarn-plugin/bundles/@yarnpkg/plugin-backstage.js`
+
+The plugin can be manually tested in any repository running at least yarn 4.1.1.
+Sadly it can't be manually tested directly in the Backstage monorepo - since
+packages in this repository use `workspace:^` dependencies, there's no use case
+for the yarn plugin.
diff --git a/plugins/catalog/report-alpha.api.md b/plugins/catalog/report-alpha.api.md
index 3a9f0c6c33..bdd9240d53 100644
--- a/plugins/catalog/report-alpha.api.md
+++ b/plugins/catalog/report-alpha.api.md
@@ -115,7 +115,7 @@ export const catalogTranslationRef: TranslationRef<
readonly 'hasSystemsCard.emptyMessage': 'No system is part of this domain';
readonly 'relatedEntitiesCard.emptyHelpLinkTitle': 'Learn how to change this';
readonly 'systemDiagramCard.title': 'System Diagram';
- readonly 'systemDiagramCard.description': 'Use pinch & zoo to move around the diagram.';
+ readonly 'systemDiagramCard.description': 'Use pinch & zoom to move around the diagram.';
readonly 'systemDiagramCard.edgeLabels.dependsOn': 'depends on';
readonly 'systemDiagramCard.edgeLabels.partOf': 'part of';
readonly 'systemDiagramCard.edgeLabels.provides': 'provides';
diff --git a/plugins/catalog/src/alpha/translation.ts b/plugins/catalog/src/alpha/translation.ts
index e5e6fa18e2..2dc2f2d34e 100644
--- a/plugins/catalog/src/alpha/translation.ts
+++ b/plugins/catalog/src/alpha/translation.ts
@@ -156,7 +156,7 @@ export const catalogTranslationRef = createTranslationRef({
},
systemDiagramCard: {
title: 'System Diagram',
- description: 'Use pinch & zoo to move around the diagram.',
+ description: 'Use pinch & zoom to move around the diagram.',
edgeLabels: {
partOf: 'part of',
provides: 'provides',
diff --git a/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.test.ts b/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.test.ts
index f4dab376bc..02e15ec53b 100644
--- a/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.test.ts
+++ b/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.test.ts
@@ -435,4 +435,62 @@ describe('createAsyncValidators', () => {
expect(validators.CustomLinkField).toHaveBeenCalled();
});
+
+ it('should validate field in the dependencies in an array field', async () => {
+ const schema: JsonObject = {
+ title: 'Make a choice',
+ properties: {
+ myArray: {
+ type: 'array',
+ title: 'Array',
+ items: {
+ type: 'object',
+ required: ['selector'],
+ properties: {
+ selector: {
+ title: 'Selector',
+ type: 'string',
+ enum: ['Choice 1', 'Choice 2'],
+ },
+ },
+ dependencies: {
+ selector: {
+ oneOf: [
+ { properties: { selector: { enum: ['Choice 1'] } } },
+ {
+ properties: {
+ selector: { enum: ['Choice 2'] },
+ customValidatedField: {
+ title: 'Custom validated field',
+ type: 'string',
+ 'ui:field': 'ValidateKebabCase',
+ },
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ },
+ };
+
+ const validators = { ValidateKebabCase: jest.fn() };
+
+ const validate = createAsyncValidators(schema, validators, {
+ apiHolder: { get: jest.fn() },
+ });
+
+ await validate({
+ myArray: [
+ {
+ selector: 'Choice 2',
+ customValidatedField: 'apple',
+ },
+ { selector: 'Choice 1' },
+ ],
+ });
+
+ expect(validators.ValidateKebabCase).toHaveBeenCalled();
+ });
});
diff --git a/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.ts b/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.ts
index d11d0b9b3b..b8ae3a6dfd 100644
--- a/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.ts
+++ b/plugins/scaffolder-react/src/next/components/Stepper/createAsyncValidators.ts
@@ -135,6 +135,26 @@ export const createAsyncValidators = (
for (const [, propValue] of Object.entries(properties)) {
await doValidate(propValue);
}
+ if (Array.isArray(value)) {
+ for (const [_, v] of Object.entries(value)) {
+ const { schema: itemSchema, uiSchema: itemUiSchema } =
+ extractSchemaFromStep(definitionInSchema.items);
+
+ if (isObject(v)) {
+ for (const [pK, pV] of Object.entries(v)) {
+ if ('ui:field' in itemUiSchema[pK]) {
+ await validateForm(
+ itemUiSchema[pK]['ui:field'],
+ pK,
+ pV,
+ itemSchema,
+ itemUiSchema,
+ );
+ }
+ }
+ }
+ }
+ }
} else if (isObject(value)) {
formValidation[key] = await validate(formData, pointer, value);
}
diff --git a/plugins/techdocs/report.api.md b/plugins/techdocs/report.api.md
index c577de5eac..196fef5f35 100644
--- a/plugins/techdocs/report.api.md
+++ b/plugins/techdocs/report.api.md
@@ -133,9 +133,12 @@ export type DocsTableRow = {
};
// @public
-export const EmbeddedDocsRouter: (
- props: PropsWithChildren<{}>,
-) => React_2.JSX.Element;
+export const EmbeddedDocsRouter: ({
+ children,
+ withSearch,
+}: React_2.PropsWithChildren<{
+ withSearch?: boolean | undefined;
+}>) => React_2.JSX.Element;
// @public
export const EntityListDocsGrid: (
@@ -191,9 +194,12 @@ export type EntityListDocsTableProps = {
};
// @public
-export const EntityTechdocsContent: (props: {
- children?: ReactNode;
-}) => JSX_2.Element;
+export const EntityTechdocsContent: ({
+ children,
+ withSearch,
+}: PropsWithChildren<{
+ withSearch?: boolean | undefined;
+}>) => JSX_2.Element;
// @public
export const isTechDocsAvailable: (entity: Entity) => boolean;
diff --git a/plugins/techdocs/src/Router.tsx b/plugins/techdocs/src/Router.tsx
index 352c9f5b73..6a0bc0e08e 100644
--- a/plugins/techdocs/src/Router.tsx
+++ b/plugins/techdocs/src/Router.tsx
@@ -57,16 +57,19 @@ export const Router = () => {
};
export const EmbeddedDocsRouter = (
- props: PropsWithChildren<{ emptyState?: React.ReactElement }>,
+ props: PropsWithChildren<{
+ emptyState?: React.ReactElement;
+ withSearch?: boolean;
+ }>,
) => {
- const { children, emptyState } = props;
+ const { children, emptyState, withSearch = true } = props;
const { entity } = useEntity();
// Using objects instead of elements, otherwise "outlet" will be null on sub-pages and add-ons won't render
const element = useRoutes([
{
path: '/*',
- element: ,
+ element: ,
children: [
{
path: '*',
@@ -96,8 +99,11 @@ export const EmbeddedDocsRouter = (
*
* @public
*/
-export const LegacyEmbeddedDocsRouter = (props: PropsWithChildren<{}>) => {
+export const LegacyEmbeddedDocsRouter = ({
+ children,
+ withSearch = true,
+}: PropsWithChildren<{ withSearch?: boolean }>) => {
// Wrap the Router to avoid exposing the emptyState prop in the non-alpha
// public API and make it easier for us to change later.
- return ;
+ return ;
};
diff --git a/yarn.lock b/yarn.lock
index 583357a7bc..f76e8bb686 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -19434,13 +19434,13 @@ __metadata:
linkType: hard
"@types/dockerode@npm:^3.3.0, @types/dockerode@npm:^3.3.29":
- version: 3.3.32
- resolution: "@types/dockerode@npm:3.3.32"
+ version: 3.3.33
+ resolution: "@types/dockerode@npm:3.3.33"
dependencies:
"@types/docker-modem": "*"
"@types/node": "*"
"@types/ssh2": "*"
- checksum: 17bfa92511cdc6ab51a67cb4678931b43670feffd737ba593c3ff90a6f71673aa04f8a81524690dddc08b483628d657a338a176171ff131de9e0efba4c3ecc11
+ checksum: 4e3ed41f3b89a213c9ba923862b653f54ee7232b2c95553410d0c3846396efb592d0291fa2f50d4b47d42a2ae0b49f422e72efcdd845d0ebb60da2e8990e9293
languageName: node
linkType: hard