Merge branch 'master' into storybook8
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-api-docs': patch
|
||||
---
|
||||
|
||||
Uses theme values to style the API definition schema so that theme overrides apply.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Align with type declaration of template filter/global function by supporting undefined as return value.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/catalog-client': patch
|
||||
---
|
||||
|
||||
Fix for certain filter fields in the `catalogApiMock` being case sensitive.
|
||||
+2
-2
@@ -354,7 +354,7 @@ Passport-supported authentication method.
|
||||
|
||||
## Custom ScmAuthApi Implementation
|
||||
|
||||
The default `ScmAuthAPi` provides integrations for `github`, `gitlab`, `azure` and `bitbucket` and is created by the following code in `packages/app/src/apis.ts`:
|
||||
The default `ScmAuthApi` provides integrations for `github`, `gitlab`, `azure` and `bitbucket` and is created by the following code in `packages/app/src/apis.ts`:
|
||||
|
||||
```ts
|
||||
ScmAuth.createDefaultApiFactory();
|
||||
@@ -379,7 +379,7 @@ export const apis: AnyApiFactory[] = [
|
||||
];
|
||||
```
|
||||
|
||||
Then replace it with something like this, which will create an `ApiFactory` with only a github provider.
|
||||
Then replace it with something like this, which will create an `ApiFactory` with only a GitHub provider.
|
||||
|
||||
```ts title="packages/app/src/apis.ts"
|
||||
export const apis: AnyApiFactory[] = [
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { CATALOG_FILTER_EXISTS } from '../types';
|
||||
import { InMemoryCatalogClient } from './InMemoryCatalogClient';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
|
||||
@@ -25,6 +26,7 @@ const entity1: Entity = {
|
||||
name: 'e1',
|
||||
uid: 'u1',
|
||||
},
|
||||
relations: [{ type: 'relatedTo', targetRef: 'customkind:default/e2' }],
|
||||
};
|
||||
|
||||
const entity2: Entity = {
|
||||
@@ -42,10 +44,32 @@ const entities = [entity1, entity2];
|
||||
describe('InMemoryCatalogClient', () => {
|
||||
it('getEntities', async () => {
|
||||
const client = new InMemoryCatalogClient({ entities });
|
||||
|
||||
await expect(client.getEntities()).resolves.toEqual({ items: entities });
|
||||
|
||||
await expect(
|
||||
client.getEntities({ filter: { 'metadata.name': 'E1' } }),
|
||||
).resolves.toEqual({ items: [entity1] });
|
||||
|
||||
await expect(
|
||||
client.getEntities({ filter: { 'metadata.uid': 'u2' } }),
|
||||
).resolves.toEqual({ items: [entity2] });
|
||||
|
||||
await expect(
|
||||
client.getEntities({ filter: { 'metadata.uid': 'U2' } }),
|
||||
).resolves.toEqual({ items: [entity2] });
|
||||
|
||||
await expect(
|
||||
client.getEntities({
|
||||
filter: { 'relations.relatedto': CATALOG_FILTER_EXISTS },
|
||||
}),
|
||||
).resolves.toEqual({ items: [entity1] });
|
||||
|
||||
await expect(
|
||||
client.getEntities({
|
||||
filter: { 'relations.relatedTo': 'customkind:default/e2' },
|
||||
}),
|
||||
).resolves.toEqual({ items: [entity1] });
|
||||
});
|
||||
|
||||
it('getEntitiesByRefs', async () => {
|
||||
|
||||
@@ -48,13 +48,22 @@ function buildEntitySearch(entity: Entity) {
|
||||
const rows = traverse(entity);
|
||||
|
||||
if (entity.metadata?.name) {
|
||||
rows.push({ key: 'metadata.name', value: entity.metadata.name });
|
||||
rows.push({
|
||||
key: 'metadata.name',
|
||||
value: entity.metadata.name.toLocaleLowerCase('en-US'),
|
||||
});
|
||||
}
|
||||
if (entity.metadata?.namespace) {
|
||||
rows.push({ key: 'metadata.namespace', value: entity.metadata.namespace });
|
||||
rows.push({
|
||||
key: 'metadata.namespace',
|
||||
value: entity.metadata.namespace.toLocaleLowerCase('en-US'),
|
||||
});
|
||||
}
|
||||
if (entity.metadata?.uid) {
|
||||
rows.push({ key: 'metadata.uid', value: entity.metadata.uid });
|
||||
rows.push({
|
||||
key: 'metadata.uid',
|
||||
value: entity.metadata.uid.toLocaleLowerCase('en-US'),
|
||||
});
|
||||
}
|
||||
|
||||
if (!entity.metadata.namespace) {
|
||||
@@ -64,8 +73,8 @@ function buildEntitySearch(entity: Entity) {
|
||||
// Visit relations
|
||||
for (const relation of entity.relations ?? []) {
|
||||
rows.push({
|
||||
key: `relations.${relation.type}`,
|
||||
value: relation.targetRef,
|
||||
key: `relations.${relation.type.toLocaleLowerCase('en-US')}`,
|
||||
value: relation.targetRef.toLocaleLowerCase('en-US'),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,8 @@ const useStyles = makeStyles(theme => ({
|
||||
.errors small`]: {
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
[`& .parameter__name.required:after`]: {
|
||||
[`& .parameter__name.required:after,
|
||||
.parameter__name.required span`]: {
|
||||
color: theme.palette.warning.dark,
|
||||
},
|
||||
[`& table.model,
|
||||
@@ -132,6 +133,46 @@ const useStyles = makeStyles(theme => ({
|
||||
[`& span.prop-type`]: {
|
||||
color: theme.palette.success.light,
|
||||
},
|
||||
[`& .opblock-control-arrow svg, .authorization__btn .unlocked`]: {
|
||||
fill: theme.palette.text.primary,
|
||||
},
|
||||
[`& .json-schema-2020-12__title,
|
||||
.json-schema-2020-12-keyword__name,
|
||||
.json-schema-2020-12-property .json-schema-2020-12__title,
|
||||
.json-schema-2020-12-keyword--description`]: {
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
[`.json-schema-2020-12-accordion__icon svg`]: {
|
||||
fill: theme.palette.text.primary,
|
||||
},
|
||||
[`& .json-schema-2020-12-accordion,
|
||||
.json-schema-2020-12-expand-deep-button`]: {
|
||||
background: 'none',
|
||||
appearance: 'none',
|
||||
},
|
||||
[`& .json-schema-2020-12-expand-deep-button,
|
||||
.json-schema-2020-12-keyword__name--secondary,
|
||||
.json-schema-2020-12-keyword__value--secondary,
|
||||
.json-schema-2020-12__attribute--muted,
|
||||
.json-schema-2020-12-keyword__value--const,
|
||||
.json-schema-2020-12-keyword__value--warning`]: {
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
[`& .json-schema-2020-12-body,
|
||||
.json-schema-2020-12-keyword__value--const,
|
||||
.json-schema-2020-12-keyword__value--warning`]: {
|
||||
borderColor: theme.palette.text.secondary,
|
||||
},
|
||||
[`.json-schema-2020-12__constraint--string`]: {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
},
|
||||
[`& .json-schema-2020-12__attribute--primary`]: {
|
||||
color: theme.palette.primary.main,
|
||||
},
|
||||
[`& .json-schema-2020-12-property--required>.json-schema-2020-12:first-of-type>.json-schema-2020-12-head .json-schema-2020-12__title:after`]:
|
||||
{
|
||||
color: theme.palette.warning.dark,
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -107,8 +107,9 @@ describe('SecureTemplater', () => {
|
||||
const mockFilter1 = jest.fn(() => 'filtered text');
|
||||
const mockFilter2 = jest.fn((var1, var2) => `${var1} ${var2}`);
|
||||
const mockFilter3 = jest.fn((var1, var2) => ({ var1, var2 }));
|
||||
const mockFilter4 = jest.fn(() => undefined);
|
||||
const renderWith = await SecureTemplater.loadRenderer({
|
||||
templateFilters: { mockFilter1, mockFilter2, mockFilter3 },
|
||||
templateFilters: { mockFilter1, mockFilter2, mockFilter3, mockFilter4 },
|
||||
});
|
||||
const renderWithout = await SecureTemplater.loadRenderer();
|
||||
|
||||
@@ -131,6 +132,7 @@ describe('SecureTemplater', () => {
|
||||
var2: 'another extra arg',
|
||||
}),
|
||||
);
|
||||
expect(renderWith('${{ inputValue | mockFilter4 }}', ctx)).toBe('');
|
||||
|
||||
expect(() => renderWithout('${{ inputValue | mockFilter1 }}', ctx)).toThrow(
|
||||
/Error: filter not found: mockFilter1/,
|
||||
@@ -152,8 +154,9 @@ describe('SecureTemplater', () => {
|
||||
const mockGlobal1 = jest.fn(() => 'awesome global function');
|
||||
const mockGlobal2 = 'foo';
|
||||
const mockGlobal3 = 123456;
|
||||
const mockGlobal4 = jest.fn(() => undefined);
|
||||
const renderWith = await SecureTemplater.loadRenderer({
|
||||
templateGlobals: { mockGlobal1, mockGlobal2, mockGlobal3 },
|
||||
templateGlobals: { mockGlobal1, mockGlobal2, mockGlobal3, mockGlobal4 },
|
||||
});
|
||||
const renderWithout = await SecureTemplater.loadRenderer();
|
||||
|
||||
@@ -164,6 +167,7 @@ describe('SecureTemplater', () => {
|
||||
);
|
||||
expect(renderWith('${{ mockGlobal2 }}', ctx)).toBe('foo');
|
||||
expect(renderWith('${{ mockGlobal3 }}', ctx)).toBe('123456');
|
||||
expect(renderWith('${{ mockGlobal4() }}', ctx)).toBe('');
|
||||
|
||||
expect(() => renderWithout('${{ mockGlobal1() }}', ctx)).toThrow(
|
||||
/Error: Unable to call `mockGlobal1`/,
|
||||
|
||||
@@ -52,14 +52,17 @@ const { render, renderCompat } = (() => {
|
||||
});
|
||||
compatEnv.addFilter('jsonify', compatEnv.getFilter('dump'));
|
||||
|
||||
const handleFunctionResult = (value) => {
|
||||
return value === '' ? undefined : JSON.parse(value);
|
||||
};
|
||||
for (const name of JSON.parse(availableTemplateFilters)) {
|
||||
env.addFilter(name, (...args) => JSON.parse(callFilter(name, args)));
|
||||
env.addFilter(name, (...args) => handleFunctionResult(callFilter(name, args)));
|
||||
}
|
||||
for (const [name, value] of Object.entries(JSON.parse(availableTemplateGlobals))) {
|
||||
env.addGlobal(name, value);
|
||||
}
|
||||
for (const name of JSON.parse(availableTemplateCallbacks)) {
|
||||
env.addGlobal(name, (...args) => JSON.parse(callGlobal(name, args)));
|
||||
env.addGlobal(name, (...args) => handleFunctionResult(callGlobal(name, args)));
|
||||
}
|
||||
|
||||
let uninstallCompat = undefined;
|
||||
@@ -187,7 +190,8 @@ export class SecureTemplater {
|
||||
if (!Object.hasOwn(templateFilters, filterName)) {
|
||||
return '';
|
||||
}
|
||||
return JSON.stringify(templateFilters[filterName](...args));
|
||||
const rz = templateFilters[filterName](...args);
|
||||
return rz === undefined ? '' : JSON.stringify(rz);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -201,7 +205,8 @@ export class SecureTemplater {
|
||||
if (typeof global !== 'function') {
|
||||
return '';
|
||||
}
|
||||
return JSON.stringify(global(...args));
|
||||
const rz = global(...args);
|
||||
return rz === undefined ? '' : JSON.stringify(rz);
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user