Derive the owned entities in the catalog from group memberships
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog': patch
|
||||
---
|
||||
|
||||
Use the OWNED_BY relation and compare it to the users MEMBER_OF relation. The user entity is searched by name, based on the userId of the identity.
|
||||
@@ -15,7 +15,11 @@
|
||||
*/
|
||||
|
||||
import { CatalogApi } from '@backstage/catalog-client';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import {
|
||||
Entity,
|
||||
RELATION_MEMBER_OF,
|
||||
RELATION_OWNED_BY,
|
||||
} from '@backstage/catalog-model';
|
||||
import {
|
||||
ApiProvider,
|
||||
ApiRegistry,
|
||||
@@ -46,6 +50,12 @@ describe('CatalogPage', () => {
|
||||
owner: 'tools@example.com',
|
||||
type: 'service',
|
||||
},
|
||||
relations: [
|
||||
{
|
||||
type: RELATION_OWNED_BY,
|
||||
target: { kind: 'Group', name: 'tools', namespace: 'default' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
@@ -57,11 +67,34 @@ describe('CatalogPage', () => {
|
||||
owner: 'not-tools@example.com',
|
||||
type: 'service',
|
||||
},
|
||||
relations: [
|
||||
{
|
||||
type: RELATION_OWNED_BY,
|
||||
target: {
|
||||
kind: 'Group',
|
||||
name: 'not-tools',
|
||||
namespace: 'default',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
] as Entity[],
|
||||
}),
|
||||
getLocationByEntity: () =>
|
||||
Promise.resolve({ id: 'id', type: 'github', target: 'url' }),
|
||||
getEntityByName: async entityName => {
|
||||
return {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'User',
|
||||
metadata: { name: entityName.name },
|
||||
relations: [
|
||||
{
|
||||
type: RELATION_MEMBER_OF,
|
||||
target: { namespace: 'default', kind: 'Group', name: 'tools' },
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
};
|
||||
const testProfile: Partial<ProfileInfo> = {
|
||||
displayName: 'Display Name',
|
||||
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
Content,
|
||||
ContentHeader,
|
||||
errorApiRef,
|
||||
identityApiRef,
|
||||
SupportButton,
|
||||
useApi,
|
||||
} from '@backstage/core';
|
||||
@@ -38,6 +37,8 @@ import { ResultsFilter } from '../ResultsFilter/ResultsFilter';
|
||||
import CatalogLayout from './CatalogLayout';
|
||||
import { CatalogTabs, LabeledComponentType } from './CatalogTabs';
|
||||
import { WelcomeBanner } from './WelcomeBanner';
|
||||
import { useUserGroups } from '../useUserGroups';
|
||||
import { RELATION_OWNED_BY } from '@backstage/catalog-model';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
contentWrapper: {
|
||||
@@ -65,7 +66,6 @@ const CatalogPageContents = () => {
|
||||
const catalogApi = useApi(catalogApiRef);
|
||||
const errorApi = useApi(errorApiRef);
|
||||
const { isStarredEntity } = useStarredEntities();
|
||||
const userId = useApi(identityApiRef).getUserId();
|
||||
const [selectedTab, setSelectedTab] = useState<string>();
|
||||
const [selectedSidebarItem, setSelectedSidebarItem] = useState<string>();
|
||||
const orgName = configApi.getOptionalString('organization.name') ?? 'Company';
|
||||
@@ -112,6 +112,8 @@ const CatalogPageContents = () => {
|
||||
[],
|
||||
);
|
||||
|
||||
const { groups } = useUserGroups();
|
||||
|
||||
const filterGroups = useMemo<ButtonGroup[]>(
|
||||
() => [
|
||||
{
|
||||
@@ -121,7 +123,16 @@ const CatalogPageContents = () => {
|
||||
id: 'owned',
|
||||
label: 'Owned',
|
||||
icon: SettingsIcon,
|
||||
filterFn: entity => entity.spec?.owner === userId,
|
||||
filterFn: entity => {
|
||||
const ownerRelation = entity.relations?.find(
|
||||
r =>
|
||||
r.type === RELATION_OWNED_BY &&
|
||||
r.target.kind.toLowerCase() === 'group',
|
||||
);
|
||||
return (
|
||||
!!ownerRelation && groups.includes(ownerRelation.target.name)
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'starred',
|
||||
@@ -142,7 +153,7 @@ const CatalogPageContents = () => {
|
||||
],
|
||||
},
|
||||
],
|
||||
[isStarredEntity, userId, orgName],
|
||||
[isStarredEntity, orgName, groups],
|
||||
);
|
||||
|
||||
const showAddExampleEntities =
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* 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 { useAsync } from 'react-use';
|
||||
import { useMemo } from 'react';
|
||||
import { RELATION_MEMBER_OF } from '@backstage/catalog-model';
|
||||
import { identityApiRef, useApi } from '@backstage/core';
|
||||
import { catalogApiRef } from '../plugin';
|
||||
|
||||
/**
|
||||
* Get the group memberships of the logged-in user.
|
||||
*/
|
||||
export const useUserGroups: () => {
|
||||
groups: string[];
|
||||
loading: boolean;
|
||||
error?: Error;
|
||||
} = () => {
|
||||
const catalogApi = useApi(catalogApiRef);
|
||||
const userId = useApi(identityApiRef).getUserId();
|
||||
|
||||
// TODO: should the identityApiRef already include the entity? or at least a full EntityName?
|
||||
const { value: user, loading, error } = useAsync(async () => {
|
||||
return await catalogApi.getEntityByName({
|
||||
kind: 'User',
|
||||
namespace: 'default',
|
||||
name: userId,
|
||||
});
|
||||
}, [catalogApi, userId]);
|
||||
|
||||
// calculate the group memberships
|
||||
const groups = useMemo<string[]>(() => {
|
||||
if (user && user.relations) {
|
||||
return user.relations
|
||||
.filter(
|
||||
r =>
|
||||
r.type === RELATION_MEMBER_OF &&
|
||||
r.target.kind.toLowerCase() === 'group',
|
||||
)
|
||||
.map(r => r.target.name);
|
||||
}
|
||||
|
||||
return [];
|
||||
}, [user]);
|
||||
|
||||
return { groups, loading, error };
|
||||
};
|
||||
Reference in New Issue
Block a user