Merge pull request #8438 from mufaddal7/feature/OwnedEntityPicker

add OwnedEntityPicker field in plugin/scaffolder
This commit is contained in:
Ben Lambert
2021-12-16 11:26:42 +01:00
committed by GitHub
12 changed files with 214 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-react': patch
---
added useOwnedEntities hook to get the list of entities of the logged-in user
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder': patch
---
Added OwnedEntityPicker field which displays Owned Entities in options
+7
View File
@@ -9,6 +9,7 @@ import { ApiRef } from '@backstage/core-plugin-api';
import { AsyncState } from 'react-use/lib/useAsync';
import { CATALOG_FILTER_EXISTS } from '@backstage/catalog-client';
import { CatalogApi } from '@backstage/catalog-client';
import { CatalogListResponse } from '@backstage/catalog-client';
import { ComponentEntity } from '@backstage/catalog-model';
import { ComponentProps } from 'react';
import { Context } from 'react';
@@ -847,6 +848,12 @@ export function useEntityOwnership(): {
// @public
export function useEntityTypeFilter(): EntityTypeReturn;
// @public
export function useOwnedEntities(allowedKinds?: string[]): {
loading: boolean;
ownedEntities: CatalogListResponse<Entity> | undefined;
};
// Warning: (ae-missing-release-tag) "useOwnUser" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public
+1
View File
@@ -42,3 +42,4 @@ export {
useEntityOwnership,
loadIdentityOwnerRefs,
} from './useEntityOwnership';
export { useOwnedEntities } from './useOwnedEntities';
@@ -0,0 +1,71 @@
/*
* Copyright 2021 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 { catalogApiRef } from './../api';
import {
loadCatalogOwnerRefs,
loadIdentityOwnerRefs,
} from './useEntityOwnership';
import { identityApiRef, useApi } from '@backstage/core-plugin-api';
import { Entity, RELATION_OWNED_BY } from '@backstage/catalog-model';
import { CatalogListResponse } from '@backstage/catalog-client';
import { useAsync } from 'react-use';
import { useMemo } from 'react';
/**
* Takes the relevant parts of the Backstage identity, and translates them into
* a list of entities which are owned by the user. Takes an optional parameter
* to filter the entities based on allowedKinds
*
* @public
*
* @param allowedKinds - Array of allowed kinds to filter the entities
* @returns CatalogListResponse<Entity>
*/
export function useOwnedEntities(allowedKinds?: string[]): {
loading: boolean;
ownedEntities: CatalogListResponse<Entity> | undefined;
} {
const identityApi = useApi(identityApiRef);
const catalogApi = useApi(catalogApiRef);
const { loading, value: refs } = useAsync(async () => {
const identityRefs = await loadIdentityOwnerRefs(identityApi);
const catalogRefs = await loadCatalogOwnerRefs(catalogApi, identityRefs);
const catalogs = await catalogApi.getEntities(
allowedKinds
? {
filter: {
kind: allowedKinds,
[`relations.${RELATION_OWNED_BY}`]:
[...identityRefs, ...catalogRefs] || [],
},
}
: {
filter: {
[`relations.${RELATION_OWNED_BY}`]:
[...identityRefs, ...catalogRefs] || [],
},
},
);
return catalogs;
}, []);
const ownedEntities = useMemo(() => {
return refs;
}, [refs]);
return useMemo(() => ({ loading, ownedEntities }), [loading, ownedEntities]);
}
+18
View File
@@ -96,6 +96,24 @@ export type FieldExtensionOptions<T = any> = {
validation?: CustomFieldValidator<T>;
};
// Warning: (ae-missing-release-tag) "OwnedEntityPicker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const OwnedEntityPicker: ({
onChange,
schema: { title, description },
required,
uiSchema,
rawErrors,
formData,
idSchema,
}: FieldProps<string>) => JSX.Element;
// Warning: (ae-missing-release-tag) "OwnedEntityPickerFieldExtension" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const OwnedEntityPickerFieldExtension: () => null;
// Warning: (ae-missing-release-tag) "OwnerPicker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
@@ -0,0 +1,75 @@
/*
* Copyright 2021 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 {
formatEntityRefTitle,
useOwnedEntities,
} from '@backstage/plugin-catalog-react';
import { TextField } from '@material-ui/core';
import FormControl from '@material-ui/core/FormControl';
import Autocomplete from '@material-ui/lab/Autocomplete';
import { FieldProps } from '@rjsf/core';
import React from 'react';
export const OwnedEntityPicker = ({
onChange,
schema: { title = 'Entity', description = 'An entity from the catalog' },
required,
uiSchema,
rawErrors,
formData,
idSchema,
}: FieldProps<string>) => {
const allowedKinds = uiSchema['ui:options']?.allowedKinds as string[];
const defaultKind = uiSchema['ui:options']?.defaultKind as string | undefined;
const { ownedEntities, loading } = useOwnedEntities(allowedKinds);
const entityRefs = ownedEntities?.items
.map(e => formatEntityRefTitle(e, { defaultKind }))
.filter(n => n);
const onSelect = (_: any, value: string | null) => {
onChange(value || '');
};
return (
<FormControl
margin="normal"
required={required}
error={rawErrors?.length > 0 && !formData}
>
<Autocomplete
id={idSchema?.$id}
value={(formData as string) || ''}
loading={loading}
onChange={onSelect}
options={entityRefs || []}
autoSelect
freeSolo
renderInput={params => (
<TextField
{...params}
label={title}
margin="normal"
helperText={description}
variant="outlined"
required={required}
InputProps={params.InputProps}
/>
)}
/>
</FormControl>
);
};
@@ -0,0 +1,16 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { OwnedEntityPicker } from './OwnedEntityPicker';
@@ -18,3 +18,4 @@ export * from './EntityPicker';
export * from './OwnerPicker';
export * from './RepoUrlPicker';
export * from './TextValuePicker';
export * from './OwnedEntityPicker';
@@ -24,6 +24,7 @@ import {
RepoUrlPicker,
} from '../components/fields/RepoUrlPicker';
import { FieldExtensionOptions } from './types';
import { OwnedEntityPicker } from '../components/fields/OwnedEntityPicker';
export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS: FieldExtensionOptions[] = [
{
@@ -44,4 +45,8 @@ export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS: FieldExtensionOptions[] = [
component: OwnerPicker,
name: 'OwnerPicker',
},
{
component: OwnedEntityPicker,
name: 'OwnedEntityPicker',
},
];
+2
View File
@@ -31,6 +31,7 @@ export {
EntityPickerFieldExtension,
EntityNamePickerFieldExtension,
OwnerPickerFieldExtension,
OwnedEntityPickerFieldExtension,
RepoUrlPickerFieldExtension,
ScaffolderPage,
scaffolderPlugin as plugin,
@@ -42,6 +43,7 @@ export {
OwnerPicker,
RepoUrlPicker,
TextValuePicker,
OwnedEntityPicker,
} from './components/fields';
export { FavouriteTemplate } from './components/FavouriteTemplate';
export { TemplateList } from './components/TemplateList';
+8
View File
@@ -35,6 +35,7 @@ import {
discoveryApiRef,
identityApiRef,
} from '@backstage/core-plugin-api';
import { OwnedEntityPicker } from './components/fields/OwnedEntityPicker';
export const scaffolderPlugin = createPlugin({
id: 'scaffolder',
@@ -95,3 +96,10 @@ export const ScaffolderPage = scaffolderPlugin.provide(
mountPoint: rootRouteRef,
}),
);
export const OwnedEntityPickerFieldExtension = scaffolderPlugin.provide(
createScaffolderFieldExtension({
component: OwnedEntityPicker,
name: 'OwnedEntityPicker',
}),
);