feat: activate and disable objects (#2194)
Closes #2144, Closes #2148, Closes #2154
This commit is contained in:
@ -1,15 +1,35 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { MetadataObject } from '../types/MetadataObject';
|
||||
|
||||
import { activeMetadataObjectsSelector } from '../states/selectors/activeMetadataObjectsSelector';
|
||||
import { disabledMetadataObjectsSelector } from '../states/selectors/disabledMetadataObjectsSelector';
|
||||
import { useFindManyMetadataObjects } from './useFindManyMetadataObjects';
|
||||
import { useUpdateOneMetadataObject } from './useUpdateOneMetadataObject';
|
||||
|
||||
export const useObjectMetadata = () => {
|
||||
const activeMetadataObjects = useRecoilValue(activeMetadataObjectsSelector);
|
||||
const disabledMetadataObjects = useRecoilValue(
|
||||
disabledMetadataObjectsSelector,
|
||||
const { metadataObjects } = useFindManyMetadataObjects();
|
||||
|
||||
const activeMetadataObjects = metadataObjects.filter(
|
||||
({ isActive }) => isActive,
|
||||
);
|
||||
const disabledMetadataObjects = metadataObjects.filter(
|
||||
({ isActive }) => !isActive,
|
||||
);
|
||||
|
||||
const { updateOneMetadataObject } = useUpdateOneMetadataObject();
|
||||
|
||||
const activateObject = (metadataObject: MetadataObject) =>
|
||||
updateOneMetadataObject({
|
||||
idToUpdate: metadataObject.id,
|
||||
updatePayload: { isActive: true },
|
||||
});
|
||||
|
||||
const disableObject = (metadataObject: MetadataObject) =>
|
||||
updateOneMetadataObject({
|
||||
idToUpdate: metadataObject.id,
|
||||
updatePayload: { isActive: false },
|
||||
});
|
||||
|
||||
return {
|
||||
activateObject,
|
||||
disableObject,
|
||||
activeObjects: activeMetadataObjects,
|
||||
disabledObjects: disabledMetadataObjects,
|
||||
};
|
||||
|
||||
@ -1,81 +1,113 @@
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { IconDotsVertical } from '@/ui/display/icon';
|
||||
import { IconArchive, IconDotsVertical, IconPencil } from '@/ui/display/icon';
|
||||
import { Tag } from '@/ui/display/tag/components/Tag';
|
||||
import { H2Title } from '@/ui/display/typography/components/H2Title';
|
||||
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
|
||||
import { useLazyLoadIcon } from '@/ui/input/hooks/useLazyLoadIcon';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
||||
import { Section } from '@/ui/layout/section/components/Section';
|
||||
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
|
||||
|
||||
type SettingsAboutSectionProps = {
|
||||
iconKey?: string;
|
||||
isCustom: boolean;
|
||||
name: string;
|
||||
onDisable: () => void;
|
||||
onEdit: () => void;
|
||||
};
|
||||
|
||||
const StyledIconTableCell = styled(TableCell)`
|
||||
justify-content: center;
|
||||
padding-right: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const StyledTableRow = styled(TableRow)`
|
||||
const StyledCard = styled.div`
|
||||
align-items: center;
|
||||
background-color: ${({ theme }) => theme.background.secondary};
|
||||
border: ${({ theme }) => `1px solid ${theme.border.color.medium}`};
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
padding: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
const StyledNameTableCell = styled(TableCell)`
|
||||
const StyledName = styled.div`
|
||||
color: ${({ theme }) => theme.font.color.primary};
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
margin-right: auto;
|
||||
`;
|
||||
|
||||
const StyledTag = styled(Tag)`
|
||||
box-sizing: border-box;
|
||||
height: ${({ theme }) => theme.spacing(4)};
|
||||
height: ${({ theme }) => theme.spacing(6)};
|
||||
`;
|
||||
|
||||
const StyledIconDotsVertical = styled(IconDotsVertical)`
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
`;
|
||||
|
||||
const StyledFlexContainer = styled.div`
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
`;
|
||||
const dropdownScopeId = 'settings-object-edit-about-menu-dropdown';
|
||||
|
||||
export const SettingsAboutSection = ({
|
||||
iconKey = '',
|
||||
isCustom,
|
||||
name,
|
||||
onDisable,
|
||||
onEdit,
|
||||
}: SettingsAboutSectionProps) => {
|
||||
const theme = useTheme();
|
||||
const { Icon } = useLazyLoadIcon(iconKey);
|
||||
|
||||
const { closeDropdown } = useDropdown({ dropdownScopeId });
|
||||
|
||||
const handleEdit = () => {
|
||||
onEdit();
|
||||
closeDropdown();
|
||||
};
|
||||
|
||||
const handleDisable = () => {
|
||||
onDisable();
|
||||
closeDropdown();
|
||||
};
|
||||
|
||||
return (
|
||||
<Section>
|
||||
<H2Title title="About" description="Manage your object" />
|
||||
<StyledTableRow>
|
||||
<StyledNameTableCell>
|
||||
<StyledCard>
|
||||
<StyledName>
|
||||
{!!Icon && <Icon size={theme.icon.size.md} />}
|
||||
{name}
|
||||
</StyledNameTableCell>
|
||||
<StyledFlexContainer>
|
||||
<TableCell>
|
||||
{isCustom ? (
|
||||
<StyledTag color="orange" text="Custom" />
|
||||
) : (
|
||||
<StyledTag color="blue" text="Standard" />
|
||||
)}
|
||||
</TableCell>
|
||||
<StyledIconTableCell>
|
||||
<StyledIconDotsVertical
|
||||
size={theme.icon.size.md}
|
||||
stroke={theme.icon.stroke.sm}
|
||||
/>
|
||||
</StyledIconTableCell>
|
||||
</StyledFlexContainer>
|
||||
</StyledTableRow>
|
||||
</StyledName>
|
||||
{isCustom ? (
|
||||
<StyledTag color="orange" text="Custom" />
|
||||
) : (
|
||||
<StyledTag color="blue" text="Standard" />
|
||||
)}
|
||||
<DropdownScope dropdownScopeId={dropdownScopeId}>
|
||||
<Dropdown
|
||||
clickableComponent={
|
||||
<LightIconButton Icon={IconDotsVertical} accent="tertiary" />
|
||||
}
|
||||
dropdownComponents={
|
||||
<DropdownMenu width="160px">
|
||||
<DropdownMenuItemsContainer>
|
||||
<MenuItem
|
||||
text="Edit"
|
||||
LeftIcon={IconPencil}
|
||||
onClick={handleEdit}
|
||||
/>
|
||||
<MenuItem
|
||||
text="Disable"
|
||||
LeftIcon={IconArchive}
|
||||
onClick={handleDisable}
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
}
|
||||
dropdownHotkeyScope={{
|
||||
scope: dropdownScopeId,
|
||||
}}
|
||||
/>
|
||||
</DropdownScope>
|
||||
</StyledCard>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
@ -4,24 +4,37 @@ import { IconArchiveOff } from '@/ui/input/constants/icons';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
||||
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
|
||||
|
||||
type SettingsObjectDisabledMenuDropDownProps = {
|
||||
scopeKey: string;
|
||||
handleActivate: () => void;
|
||||
handleErase: () => void;
|
||||
onActivate: () => void;
|
||||
onErase: () => void;
|
||||
};
|
||||
|
||||
export const SettingsObjectDisabledMenuDropDown = ({
|
||||
scopeKey,
|
||||
handleActivate,
|
||||
handleErase,
|
||||
onActivate,
|
||||
onErase,
|
||||
}: SettingsObjectDisabledMenuDropDownProps) => {
|
||||
const dropdownScopeId = scopeKey + '-settings-object-disabled-menu-dropdown';
|
||||
|
||||
const { closeDropdown } = useDropdown({ dropdownScopeId });
|
||||
|
||||
const handleActivate = () => {
|
||||
onActivate();
|
||||
closeDropdown();
|
||||
};
|
||||
|
||||
const handleErase = () => {
|
||||
onErase();
|
||||
closeDropdown();
|
||||
};
|
||||
|
||||
return (
|
||||
<DropdownScope
|
||||
dropdownScopeId={scopeKey + '-settings-object-disabled-menu-dropdown'}
|
||||
>
|
||||
<DropdownScope dropdownScopeId={dropdownScopeId}>
|
||||
<Dropdown
|
||||
clickableComponent={
|
||||
<LightIconButton Icon={IconDotsVertical} accent="tertiary" />
|
||||
@ -44,7 +57,7 @@ export const SettingsObjectDisabledMenuDropDown = ({
|
||||
</DropdownMenu>
|
||||
}
|
||||
dropdownHotkeyScope={{
|
||||
scope: scopeKey + '-settings-object-disabled-menu-dropdown',
|
||||
scope: dropdownScopeId,
|
||||
}}
|
||||
/>
|
||||
</DropdownScope>
|
||||
|
||||
@ -23,8 +23,8 @@ const meta: Meta<typeof SettingsObjectDisabledMenuDropDown> = {
|
||||
component: SettingsObjectDisabledMenuDropDown,
|
||||
args: {
|
||||
scopeKey: 'settings-object-disabled-menu-dropdown',
|
||||
handleActivate: handleActivateMockFunction,
|
||||
handleErase: handleEraseMockFunction,
|
||||
onActivate: handleActivateMockFunction,
|
||||
onErase: handleEraseMockFunction,
|
||||
},
|
||||
decorators: [ComponentDecorator, ClearMocksDecorator],
|
||||
parameters: {
|
||||
|
||||
@ -30,7 +30,7 @@ export const SettingsObjectDetail = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { pluralObjectName = '' } = useParams();
|
||||
const { activeObjects } = useObjectMetadata();
|
||||
const { activeObjects, disableObject } = useObjectMetadata();
|
||||
const activeObject = activeObjects.find(
|
||||
(activeObject) => activeObject.namePlural === pluralObjectName,
|
||||
);
|
||||
@ -62,6 +62,13 @@ export const SettingsObjectDetail = () => {
|
||||
iconKey={activeObject.icon ?? undefined}
|
||||
name={activeObject.labelPlural || ''}
|
||||
isCustom={activeObject.isCustom}
|
||||
onDisable={() => {
|
||||
disableObject(activeObject);
|
||||
navigate('/settings/objects');
|
||||
}}
|
||||
onEdit={() =>
|
||||
navigate(`/settings/objects/${pluralObjectName}/edit`)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Section>
|
||||
@ -76,15 +83,17 @@ export const SettingsObjectDetail = () => {
|
||||
<TableHeader>Data type</TableHeader>
|
||||
<TableHeader></TableHeader>
|
||||
</StyledObjectFieldTableRow>
|
||||
<TableSection title="Active">
|
||||
{activeFields?.map((fieldItem) => (
|
||||
<SettingsObjectFieldItemTableRow
|
||||
key={fieldItem.id}
|
||||
fieldItem={fieldItem}
|
||||
ActionIcon={IconDotsVertical}
|
||||
/>
|
||||
))}
|
||||
</TableSection>
|
||||
{!!activeFields?.length && (
|
||||
<TableSection title="Active">
|
||||
{activeFields.map((fieldItem) => (
|
||||
<SettingsObjectFieldItemTableRow
|
||||
key={fieldItem.id}
|
||||
fieldItem={fieldItem}
|
||||
ActionIcon={IconDotsVertical}
|
||||
/>
|
||||
))}
|
||||
</TableSection>
|
||||
)}
|
||||
{!!disabledFields?.length && (
|
||||
<TableSection isInitiallyExpanded={false} title="Disabled">
|
||||
{disabledFields.map((fieldItem) => (
|
||||
|
||||
@ -17,7 +17,7 @@ export const SettingsObjectEdit = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { pluralObjectName = '' } = useParams();
|
||||
const { activeObjects } = useObjectMetadata();
|
||||
const { activeObjects, disableObject } = useObjectMetadata();
|
||||
const activeObject = activeObjects.find(
|
||||
(activeObject) => activeObject.namePlural === pluralObjectName,
|
||||
);
|
||||
@ -52,17 +52,20 @@ export const SettingsObjectEdit = () => {
|
||||
pluralName={activeObject.labelPlural}
|
||||
description={activeObject.description ?? undefined}
|
||||
/>
|
||||
<Section>
|
||||
<H2Title title="Danger zone" description="Disable object" />
|
||||
<Button
|
||||
Icon={IconArchive}
|
||||
title="Disable"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
disableObject(activeObject);
|
||||
navigate('/settings/objects');
|
||||
}}
|
||||
/>
|
||||
</Section>
|
||||
</>
|
||||
)}
|
||||
<Section>
|
||||
<H2Title title="Danger zone" description="Disable object" />
|
||||
<Button
|
||||
Icon={IconArchive}
|
||||
title="Disable"
|
||||
size="small"
|
||||
onClick={() => undefined}
|
||||
/>
|
||||
</Section>
|
||||
</SettingsPageContainer>
|
||||
</SubMenuTopBarContainer>
|
||||
);
|
||||
|
||||
@ -87,15 +87,17 @@ export const SettingsObjectNewFieldStep1 = () => {
|
||||
<TableHeader>Data type</TableHeader>
|
||||
<TableHeader></TableHeader>
|
||||
</StyledObjectFieldTableRow>
|
||||
<TableSection isInitiallyExpanded={false} title="Active">
|
||||
{activeFields?.map((fieldItem) => (
|
||||
<SettingsObjectFieldItemTableRow
|
||||
key={fieldItem.id}
|
||||
fieldItem={fieldItem}
|
||||
ActionIcon={IconMinus}
|
||||
/>
|
||||
))}
|
||||
</TableSection>
|
||||
{!!activeFields?.length && (
|
||||
<TableSection isInitiallyExpanded={false} title="Active">
|
||||
{activeFields.map((fieldItem) => (
|
||||
<SettingsObjectFieldItemTableRow
|
||||
key={fieldItem.id}
|
||||
fieldItem={fieldItem}
|
||||
ActionIcon={IconMinus}
|
||||
/>
|
||||
))}
|
||||
</TableSection>
|
||||
)}
|
||||
{!!disabledFields?.length && (
|
||||
<TableSection title="Disabled">
|
||||
{disabledFields.map((fieldItem) => (
|
||||
|
||||
@ -33,7 +33,8 @@ export const SettingsObjects = () => {
|
||||
const theme = useTheme();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { activeObjects, disabledObjects } = useObjectMetadata();
|
||||
const { activateObject, activeObjects, disabledObjects } =
|
||||
useObjectMetadata();
|
||||
|
||||
return (
|
||||
<SubMenuTopBarContainer Icon={IconSettings} title="Settings">
|
||||
@ -62,23 +63,25 @@ export const SettingsObjects = () => {
|
||||
<TableHeader align="right">Instances</TableHeader>
|
||||
<TableHeader></TableHeader>
|
||||
</StyledObjectTableRow>
|
||||
<TableSection title="Active">
|
||||
{activeObjects.map((objectItem) => (
|
||||
<SettingsObjectItemTableRow
|
||||
key={objectItem.namePlural}
|
||||
objectItem={objectItem}
|
||||
action={
|
||||
<StyledIconChevronRight
|
||||
size={theme.icon.size.md}
|
||||
stroke={theme.icon.stroke.sm}
|
||||
/>
|
||||
}
|
||||
onClick={() =>
|
||||
navigate(`/settings/objects/${objectItem.namePlural}`)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</TableSection>
|
||||
{!!activeObjects.length && (
|
||||
<TableSection title="Active">
|
||||
{activeObjects.map((objectItem) => (
|
||||
<SettingsObjectItemTableRow
|
||||
key={objectItem.namePlural}
|
||||
objectItem={objectItem}
|
||||
action={
|
||||
<StyledIconChevronRight
|
||||
size={theme.icon.size.md}
|
||||
stroke={theme.icon.stroke.sm}
|
||||
/>
|
||||
}
|
||||
onClick={() =>
|
||||
navigate(`/settings/objects/${objectItem.namePlural}`)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</TableSection>
|
||||
)}
|
||||
{!!disabledObjects.length && (
|
||||
<TableSection title="Disabled">
|
||||
{disabledObjects.map((objectItem) => (
|
||||
@ -88,8 +91,8 @@ export const SettingsObjects = () => {
|
||||
action={
|
||||
<SettingsObjectDisabledMenuDropDown
|
||||
scopeKey={objectItem.namePlural}
|
||||
handleActivate={() => undefined}
|
||||
handleErase={() => undefined}
|
||||
onActivate={() => activateObject(objectItem)}
|
||||
onErase={() => undefined}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user