2021-09-02 19:05:13 -07:00
|
|
|
import React from 'react';
|
|
|
|
import { Form, Select, Switch, Tag, Typography } from 'antd';
|
|
|
|
import { Link } from 'react-router-dom';
|
|
|
|
import styled from 'styled-components';
|
|
|
|
import { useEntityRegistry } from '../useEntityRegistry';
|
|
|
|
import { ActorFilter, EntityType, PolicyType, SearchResult } from '../../types.generated';
|
|
|
|
import { useGetSearchResultsLazyQuery } from '../../graphql/search.generated';
|
|
|
|
|
|
|
|
type Props = {
|
|
|
|
policyType: PolicyType;
|
|
|
|
actors: ActorFilter;
|
|
|
|
setActors: (actors: ActorFilter) => void;
|
|
|
|
};
|
|
|
|
|
|
|
|
const SearchResultContainer = styled.div`
|
2022-03-04 12:19:37 -08:00
|
|
|
display: flex;f
|
2021-09-02 19:05:13 -07:00
|
|
|
justify-content: space-between;
|
|
|
|
align-items: center;
|
|
|
|
padding: 12px;
|
|
|
|
`;
|
|
|
|
|
|
|
|
const ActorForm = styled(Form)`
|
|
|
|
margin: 12px;
|
|
|
|
margin-top: 36px;
|
|
|
|
margin-bottom: 40px;
|
|
|
|
`;
|
|
|
|
|
|
|
|
const ActorFormHeader = styled.div`
|
|
|
|
margin-bottom: 28px;
|
|
|
|
`;
|
|
|
|
|
2022-03-04 12:19:37 -08:00
|
|
|
const ActorName = styled.div`
|
|
|
|
margin-right: 8px;
|
|
|
|
`;
|
|
|
|
|
2021-09-02 19:05:13 -07:00
|
|
|
/**
|
|
|
|
* Component used to construct the "actors" portion of a DataHub
|
|
|
|
* access Policy by populating an ActorFilter object.
|
|
|
|
*/
|
|
|
|
export default function PolicyActorForm({ policyType, actors, setActors }: Props) {
|
|
|
|
const entityRegistry = useEntityRegistry();
|
|
|
|
|
|
|
|
// Search for actors while building policy.
|
|
|
|
const [userSearch, { data: userSearchData }] = useGetSearchResultsLazyQuery();
|
|
|
|
const [groupSearch, { data: groupSearchData }] = useGetSearchResultsLazyQuery();
|
|
|
|
|
|
|
|
// Toggle the "Owners" switch
|
|
|
|
const onToggleAppliesToOwners = (value: boolean) => {
|
|
|
|
setActors({
|
|
|
|
...actors,
|
|
|
|
resourceOwners: value,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
// When a user search result is selected, add the urn to the ActorFilter
|
|
|
|
const onSelectUserActor = (newUser: string) => {
|
|
|
|
if (newUser === 'All') {
|
|
|
|
setActors({
|
|
|
|
...actors,
|
|
|
|
allUsers: true,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
const newUserActors = [...(actors.users || []), newUser];
|
|
|
|
setActors({
|
|
|
|
...actors,
|
|
|
|
users: newUserActors,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// When a user search result is deselected, remove the urn from the ActorFilter
|
|
|
|
const onDeselectUserActor = (user: string) => {
|
|
|
|
if (user === 'All') {
|
|
|
|
setActors({
|
|
|
|
...actors,
|
|
|
|
allUsers: false,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
const newUserActors = actors.users?.filter((u) => u !== user);
|
|
|
|
setActors({
|
|
|
|
...actors,
|
|
|
|
users: newUserActors,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// When a group search result is selected, add the urn to the ActorFilter
|
|
|
|
const onSelectGroupActor = (newGroup: string) => {
|
|
|
|
if (newGroup === 'All') {
|
|
|
|
setActors({
|
|
|
|
...actors,
|
|
|
|
allGroups: true,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
const newGroupActors = [...(actors.groups || []), newGroup];
|
|
|
|
setActors({
|
|
|
|
...actors,
|
|
|
|
groups: newGroupActors,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// When a group search result is deselected, remove the urn from the ActorFilter
|
|
|
|
const onDeselectGroupActor = (group: string) => {
|
|
|
|
if (group === 'All') {
|
|
|
|
setActors({
|
|
|
|
...actors,
|
|
|
|
allGroups: false,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
const newGroupActors = actors.groups?.filter((g) => g !== group);
|
|
|
|
setActors({
|
|
|
|
...actors,
|
|
|
|
groups: newGroupActors,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Invokes the search API as the user types
|
|
|
|
const handleSearch = (type: EntityType, text: string, searchQuery: any) => {
|
|
|
|
if (text.length > 2) {
|
|
|
|
searchQuery({
|
|
|
|
variables: {
|
|
|
|
input: {
|
|
|
|
type,
|
|
|
|
query: text,
|
|
|
|
start: 0,
|
|
|
|
count: 10,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Invokes the user search API as the user types
|
2021-09-29 12:54:38 -07:00
|
|
|
const handleUserSearch = (text: string) => {
|
2021-09-02 19:05:13 -07:00
|
|
|
return handleSearch(EntityType.CorpUser, text, userSearch);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Invokes the group search API as the user types
|
2021-09-29 12:54:38 -07:00
|
|
|
const handleGroupSearch = (text: string) => {
|
2021-09-02 19:05:13 -07:00
|
|
|
return handleSearch(EntityType.CorpGroup, text, groupSearch);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Renders a search result in the select dropdown.
|
|
|
|
const renderSearchResult = (result: SearchResult) => {
|
|
|
|
return (
|
|
|
|
<SearchResultContainer>
|
2022-03-04 12:19:37 -08:00
|
|
|
<ActorName>{entityRegistry.getDisplayName(result.entity.type, result.entity)}</ActorName>
|
2021-09-02 19:05:13 -07:00
|
|
|
<Link
|
|
|
|
target="_blank"
|
|
|
|
rel="noopener noreferrer"
|
|
|
|
to={() => `/${entityRegistry.getPathName(result.entity.type)}/${result.entity.urn}`}
|
|
|
|
>
|
|
|
|
View
|
2022-03-04 12:19:37 -08:00
|
|
|
</Link>
|
2021-09-02 19:05:13 -07:00
|
|
|
</SearchResultContainer>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Whether to show "owners" switch.
|
|
|
|
const showAppliesToOwners = policyType === PolicyType.Metadata;
|
|
|
|
|
|
|
|
// User and group dropdown search results!
|
|
|
|
const userSearchResults = userSearchData?.search?.searchResults;
|
|
|
|
const groupSearchResults = groupSearchData?.search?.searchResults;
|
|
|
|
|
|
|
|
// Select dropdown values.
|
|
|
|
const usersSelectValue = actors.allUsers ? ['All'] : actors.users || [];
|
|
|
|
const groupsSelectValue = actors.allGroups ? ['All'] : actors.groups || [];
|
|
|
|
|
|
|
|
return (
|
|
|
|
<ActorForm layout="vertical">
|
|
|
|
<ActorFormHeader>
|
|
|
|
<Typography.Title level={4}>Applies to</Typography.Title>
|
|
|
|
<Typography.Paragraph>Select the users & groups that this policy should apply to.</Typography.Paragraph>
|
|
|
|
</ActorFormHeader>
|
|
|
|
{showAppliesToOwners && (
|
|
|
|
<Form.Item label={<Typography.Text strong>Owners</Typography.Text>} labelAlign="right">
|
|
|
|
<Typography.Paragraph>
|
|
|
|
Whether this policy should be apply to owners of the Metadata asset. If true, those who are
|
|
|
|
marked as owners of a Metadata Asset, either directly or indirectly via a Group, will have the
|
|
|
|
selected privileges.
|
|
|
|
</Typography.Paragraph>
|
|
|
|
<Switch size="small" checked={actors.resourceOwners} onChange={onToggleAppliesToOwners} />
|
|
|
|
</Form.Item>
|
|
|
|
)}
|
|
|
|
<Form.Item label={<Typography.Text strong>Users</Typography.Text>}>
|
|
|
|
<Typography.Paragraph>
|
|
|
|
Search for specific users that this policy should apply to, or select `All Users` to apply it to all
|
|
|
|
users.
|
|
|
|
</Typography.Paragraph>
|
|
|
|
<Select
|
|
|
|
value={usersSelectValue}
|
|
|
|
mode="multiple"
|
2022-03-04 12:19:37 -08:00
|
|
|
filterOption={false}
|
2021-09-02 19:05:13 -07:00
|
|
|
placeholder="Search for users..."
|
|
|
|
onSelect={(asset: any) => onSelectUserActor(asset)}
|
|
|
|
onDeselect={(asset: any) => onDeselectUserActor(asset)}
|
2021-09-29 12:54:38 -07:00
|
|
|
onSearch={handleUserSearch}
|
2021-09-02 19:05:13 -07:00
|
|
|
tagRender={(tagProps) => (
|
|
|
|
<Tag closable={tagProps.closable} onClose={tagProps.onClose}>
|
|
|
|
{tagProps.value}
|
|
|
|
</Tag>
|
|
|
|
)}
|
|
|
|
>
|
|
|
|
{userSearchResults?.map((result) => (
|
|
|
|
<Select.Option value={result.entity.urn}>{renderSearchResult(result)}</Select.Option>
|
|
|
|
))}
|
|
|
|
<Select.Option value="All">All Users</Select.Option>
|
|
|
|
</Select>
|
|
|
|
</Form.Item>
|
|
|
|
<Form.Item label={<Typography.Text strong>Groups</Typography.Text>}>
|
|
|
|
<Typography.Paragraph>
|
|
|
|
Search for specific groups that this policy should apply to, or select `All Groups` to apply it to
|
|
|
|
all groups.
|
|
|
|
</Typography.Paragraph>
|
|
|
|
<Select
|
|
|
|
value={groupsSelectValue}
|
|
|
|
mode="multiple"
|
|
|
|
placeholder="Search for groups..."
|
|
|
|
onSelect={(asset: any) => onSelectGroupActor(asset)}
|
|
|
|
onDeselect={(asset: any) => onDeselectGroupActor(asset)}
|
2021-09-29 12:54:38 -07:00
|
|
|
onSearch={handleGroupSearch}
|
2022-03-04 12:19:37 -08:00
|
|
|
filterOption={false}
|
2021-09-02 19:05:13 -07:00
|
|
|
tagRender={(tagProps) => (
|
|
|
|
<Tag closable={tagProps.closable} onClose={tagProps.onClose}>
|
|
|
|
{tagProps.value}
|
|
|
|
</Tag>
|
|
|
|
)}
|
|
|
|
>
|
|
|
|
{groupSearchResults?.map((result) => (
|
|
|
|
<Select.Option value={result.entity.urn}>{renderSearchResult(result)}</Select.Option>
|
|
|
|
))}
|
|
|
|
<Select.Option value="All">All Groups</Select.Option>
|
|
|
|
</Select>
|
|
|
|
</Form.Item>
|
|
|
|
</ActorForm>
|
|
|
|
);
|
|
|
|
}
|