feat: activate, disable and erase fields in Object Detail (#2200)
* feat: activate and disable objects Closes #2144, Closes #2148, Closes #2154 * feat: activate, disable and erase fields in Object Detail Closes #2158 --------- Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
This commit is contained in:
30
front/src/modules/metadata/hooks/useFieldMetadata.ts
Normal file
30
front/src/modules/metadata/hooks/useFieldMetadata.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { Field } from '~/generated/graphql';
|
||||||
|
|
||||||
|
import { useDeleteOneMetadataField } from './useDeleteOneMetadataField';
|
||||||
|
import { useUpdateOneMetadataField } from './useUpdateOneMetadataField';
|
||||||
|
|
||||||
|
export const useFieldMetadata = () => {
|
||||||
|
const { updateOneMetadataField } = useUpdateOneMetadataField();
|
||||||
|
const { deleteOneMetadataField } = useDeleteOneMetadataField();
|
||||||
|
|
||||||
|
const activateField = (metadataField: Field) =>
|
||||||
|
updateOneMetadataField({
|
||||||
|
fieldIdToUpdate: metadataField.id,
|
||||||
|
updatePayload: { isActive: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
const disableField = (metadataField: Field) =>
|
||||||
|
updateOneMetadataField({
|
||||||
|
fieldIdToUpdate: metadataField.id,
|
||||||
|
updatePayload: { isActive: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
const eraseField = (metadataField: Field) =>
|
||||||
|
deleteOneMetadataField(metadataField.id);
|
||||||
|
|
||||||
|
return {
|
||||||
|
activateField,
|
||||||
|
disableField,
|
||||||
|
eraseField,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -35,6 +35,7 @@ export const useUpdateOneMetadataField = () => {
|
|||||||
variables: {
|
variables: {
|
||||||
idToUpdate: fieldIdToUpdate,
|
idToUpdate: fieldIdToUpdate,
|
||||||
updatePayload: {
|
updatePayload: {
|
||||||
|
...updatePayload,
|
||||||
label: updatePayload.label ?? undefined,
|
label: updatePayload.label ?? undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -0,0 +1,70 @@
|
|||||||
|
import {
|
||||||
|
IconArchive,
|
||||||
|
IconDotsVertical,
|
||||||
|
IconEye,
|
||||||
|
IconPencil,
|
||||||
|
} from '@/ui/display/icon';
|
||||||
|
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
|
||||||
|
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 SettingsObjectFieldActiveActionDropdownProps = {
|
||||||
|
isCustomField: boolean;
|
||||||
|
onDisable: () => void;
|
||||||
|
onEdit: () => void;
|
||||||
|
scopeKey: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SettingsObjectFieldActiveActionDropdown = ({
|
||||||
|
isCustomField,
|
||||||
|
onDisable,
|
||||||
|
onEdit,
|
||||||
|
scopeKey,
|
||||||
|
}: SettingsObjectFieldActiveActionDropdownProps) => {
|
||||||
|
const dropdownScopeId = `${scopeKey}-settings-field-active-action-dropdown`;
|
||||||
|
|
||||||
|
const { closeDropdown } = useDropdown({ dropdownScopeId });
|
||||||
|
|
||||||
|
const handleEdit = () => {
|
||||||
|
onEdit();
|
||||||
|
closeDropdown();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDisable = () => {
|
||||||
|
onDisable();
|
||||||
|
closeDropdown();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownScope dropdownScopeId={dropdownScopeId}>
|
||||||
|
<Dropdown
|
||||||
|
clickableComponent={
|
||||||
|
<LightIconButton Icon={IconDotsVertical} accent="tertiary" />
|
||||||
|
}
|
||||||
|
dropdownComponents={
|
||||||
|
<DropdownMenu width="160px">
|
||||||
|
<DropdownMenuItemsContainer>
|
||||||
|
<MenuItem
|
||||||
|
text={isCustomField ? 'Edit' : 'View'}
|
||||||
|
LeftIcon={isCustomField ? IconPencil : IconEye}
|
||||||
|
onClick={handleEdit}
|
||||||
|
/>
|
||||||
|
<MenuItem
|
||||||
|
text="Disable"
|
||||||
|
LeftIcon={IconArchive}
|
||||||
|
onClick={handleDisable}
|
||||||
|
/>
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownMenu>
|
||||||
|
}
|
||||||
|
dropdownHotkeyScope={{
|
||||||
|
scope: dropdownScopeId,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</DropdownScope>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
import { IconArchiveOff, IconDotsVertical, IconTrash } from '@/ui/display/icon';
|
||||||
|
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
|
||||||
|
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 SettingsObjectFieldDisabledActionDropdownProps = {
|
||||||
|
isCustomField: boolean;
|
||||||
|
onActivate: () => void;
|
||||||
|
onErase: () => void;
|
||||||
|
scopeKey: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SettingsObjectFieldDisabledActionDropdown = ({
|
||||||
|
isCustomField,
|
||||||
|
onActivate,
|
||||||
|
onErase,
|
||||||
|
scopeKey,
|
||||||
|
}: SettingsObjectFieldDisabledActionDropdownProps) => {
|
||||||
|
const dropdownScopeId = `${scopeKey}-settings-field-disabled-action-dropdown`;
|
||||||
|
|
||||||
|
const { closeDropdown } = useDropdown({ dropdownScopeId });
|
||||||
|
|
||||||
|
const handleActivate = () => {
|
||||||
|
onActivate();
|
||||||
|
closeDropdown();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleErase = () => {
|
||||||
|
onErase();
|
||||||
|
closeDropdown();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownScope dropdownScopeId={dropdownScopeId}>
|
||||||
|
<Dropdown
|
||||||
|
clickableComponent={
|
||||||
|
<LightIconButton Icon={IconDotsVertical} accent="tertiary" />
|
||||||
|
}
|
||||||
|
dropdownComponents={
|
||||||
|
<DropdownMenu width="160px">
|
||||||
|
<DropdownMenuItemsContainer>
|
||||||
|
<MenuItem
|
||||||
|
text="Activate"
|
||||||
|
LeftIcon={IconArchiveOff}
|
||||||
|
onClick={handleActivate}
|
||||||
|
/>
|
||||||
|
{isCustomField && (
|
||||||
|
<MenuItem
|
||||||
|
text="Erase"
|
||||||
|
accent="danger"
|
||||||
|
LeftIcon={IconTrash}
|
||||||
|
onClick={handleErase}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</DropdownMenu>
|
||||||
|
}
|
||||||
|
dropdownHotkeyScope={{
|
||||||
|
scope: dropdownScopeId,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</DropdownScope>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,8 +1,7 @@
|
|||||||
|
import { ReactNode } from 'react';
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
|
||||||
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
|
|
||||||
import { useLazyLoadIcon } from '@/ui/input/hooks/useLazyLoadIcon';
|
import { useLazyLoadIcon } from '@/ui/input/hooks/useLazyLoadIcon';
|
||||||
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||||
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||||
@ -13,7 +12,7 @@ import { ObjectFieldDataType } from '../../types/ObjectFieldDataType';
|
|||||||
import { SettingsObjectFieldDataType } from './SettingsObjectFieldDataType';
|
import { SettingsObjectFieldDataType } from './SettingsObjectFieldDataType';
|
||||||
|
|
||||||
type SettingsObjectFieldItemTableRowProps = {
|
type SettingsObjectFieldItemTableRowProps = {
|
||||||
ActionIcon: IconComponent;
|
ActionIcon: ReactNode;
|
||||||
fieldItem: Field;
|
fieldItem: Field;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -50,9 +49,7 @@ export const SettingsObjectFieldItemTableRow = ({
|
|||||||
value={fieldItem.type as ObjectFieldDataType}
|
value={fieldItem.type as ObjectFieldDataType}
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<StyledIconTableCell>
|
<StyledIconTableCell>{ActionIcon}</StyledIconTableCell>
|
||||||
<LightIconButton Icon={ActionIcon} accent="tertiary" />
|
|
||||||
</StyledIconTableCell>
|
|
||||||
</StyledObjectFieldTableRow>
|
</StyledObjectFieldTableRow>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -19,7 +19,7 @@ export const SettingsObjectDisabledMenuDropDown = ({
|
|||||||
onActivate,
|
onActivate,
|
||||||
onErase,
|
onErase,
|
||||||
}: SettingsObjectDisabledMenuDropDownProps) => {
|
}: SettingsObjectDisabledMenuDropDownProps) => {
|
||||||
const dropdownScopeId = scopeKey + '-settings-object-disabled-menu-dropdown';
|
const dropdownScopeId = `${scopeKey}-settings-object-disabled-menu-dropdown`;
|
||||||
|
|
||||||
const { closeDropdown } = useDropdown({ dropdownScopeId });
|
const { closeDropdown } = useDropdown({ dropdownScopeId });
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ export {
|
|||||||
IconAlertCircle,
|
IconAlertCircle,
|
||||||
IconAlertTriangle,
|
IconAlertTriangle,
|
||||||
IconArchive,
|
IconArchive,
|
||||||
|
IconArchiveOff,
|
||||||
IconArrowBack,
|
IconArrowBack,
|
||||||
IconArrowDown,
|
IconArrowDown,
|
||||||
IconArrowLeft,
|
IconArrowLeft,
|
||||||
|
|||||||
@ -2,15 +2,18 @@ import { useEffect } from 'react';
|
|||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { useFieldMetadata } from '@/metadata/hooks/useFieldMetadata';
|
||||||
import { useObjectMetadata } from '@/metadata/hooks/useObjectMetadata';
|
import { useObjectMetadata } from '@/metadata/hooks/useObjectMetadata';
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
import { SettingsAboutSection } from '@/settings/data-model/object-details/components/SettingsObjectAboutSection';
|
import { SettingsAboutSection } from '@/settings/data-model/object-details/components/SettingsObjectAboutSection';
|
||||||
|
import { SettingsObjectFieldActiveActionDropdown } from '@/settings/data-model/object-details/components/SettingsObjectFieldActiveActionDropdown';
|
||||||
|
import { SettingsObjectFieldDisabledActionDropdown } from '@/settings/data-model/object-details/components/SettingsObjectFieldDisabledActionDropdown';
|
||||||
import {
|
import {
|
||||||
SettingsObjectFieldItemTableRow,
|
SettingsObjectFieldItemTableRow,
|
||||||
StyledObjectFieldTableRow,
|
StyledObjectFieldTableRow,
|
||||||
} from '@/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow';
|
} from '@/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { IconDotsVertical, IconPlus, IconSettings } from '@/ui/display/icon';
|
import { IconPlus, IconSettings } from '@/ui/display/icon';
|
||||||
import { H2Title } from '@/ui/display/typography/components/H2Title';
|
import { H2Title } from '@/ui/display/typography/components/H2Title';
|
||||||
import { Button } from '@/ui/input/button/components/Button';
|
import { Button } from '@/ui/input/button/components/Button';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
@ -41,6 +44,7 @@ export const SettingsObjectDetail = () => {
|
|||||||
}
|
}
|
||||||
}, [activeObject, activeObjects.length, navigate]);
|
}, [activeObject, activeObjects.length, navigate]);
|
||||||
|
|
||||||
|
const { activateField, disableField, eraseField } = useFieldMetadata();
|
||||||
const activeFields = activeObject?.fields.filter(
|
const activeFields = activeObject?.fields.filter(
|
||||||
(fieldItem) => fieldItem.isActive,
|
(fieldItem) => fieldItem.isActive,
|
||||||
);
|
);
|
||||||
@ -89,7 +93,18 @@ export const SettingsObjectDetail = () => {
|
|||||||
<SettingsObjectFieldItemTableRow
|
<SettingsObjectFieldItemTableRow
|
||||||
key={fieldItem.id}
|
key={fieldItem.id}
|
||||||
fieldItem={fieldItem}
|
fieldItem={fieldItem}
|
||||||
ActionIcon={IconDotsVertical}
|
ActionIcon={
|
||||||
|
<SettingsObjectFieldActiveActionDropdown
|
||||||
|
isCustomField={fieldItem.isCustom}
|
||||||
|
scopeKey={fieldItem.id}
|
||||||
|
onEdit={() =>
|
||||||
|
navigate(
|
||||||
|
`/settings/objects/${pluralObjectName}/${fieldItem.name}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
onDisable={() => disableField(fieldItem)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</TableSection>
|
</TableSection>
|
||||||
@ -100,7 +115,14 @@ export const SettingsObjectDetail = () => {
|
|||||||
<SettingsObjectFieldItemTableRow
|
<SettingsObjectFieldItemTableRow
|
||||||
key={fieldItem.id}
|
key={fieldItem.id}
|
||||||
fieldItem={fieldItem}
|
fieldItem={fieldItem}
|
||||||
ActionIcon={IconDotsVertical}
|
ActionIcon={
|
||||||
|
<SettingsObjectFieldDisabledActionDropdown
|
||||||
|
isCustomField={fieldItem.isCustom}
|
||||||
|
scopeKey={fieldItem.id}
|
||||||
|
onActivate={() => activateField(fieldItem)}
|
||||||
|
onErase={() => eraseField(fieldItem)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</TableSection>
|
</TableSection>
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import { AppPath } from '@/types/AppPath';
|
|||||||
import { IconMinus, IconPlus, IconSettings } from '@/ui/display/icon';
|
import { IconMinus, IconPlus, IconSettings } from '@/ui/display/icon';
|
||||||
import { H2Title } from '@/ui/display/typography/components/H2Title';
|
import { H2Title } from '@/ui/display/typography/components/H2Title';
|
||||||
import { Button } from '@/ui/input/button/components/Button';
|
import { Button } from '@/ui/input/button/components/Button';
|
||||||
|
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
import { Table } from '@/ui/layout/table/components/Table';
|
import { Table } from '@/ui/layout/table/components/Table';
|
||||||
@ -93,7 +94,9 @@ export const SettingsObjectNewFieldStep1 = () => {
|
|||||||
<SettingsObjectFieldItemTableRow
|
<SettingsObjectFieldItemTableRow
|
||||||
key={fieldItem.id}
|
key={fieldItem.id}
|
||||||
fieldItem={fieldItem}
|
fieldItem={fieldItem}
|
||||||
ActionIcon={IconMinus}
|
ActionIcon={
|
||||||
|
<LightIconButton Icon={IconMinus} accent="tertiary" />
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</TableSection>
|
</TableSection>
|
||||||
@ -104,7 +107,9 @@ export const SettingsObjectNewFieldStep1 = () => {
|
|||||||
<SettingsObjectFieldItemTableRow
|
<SettingsObjectFieldItemTableRow
|
||||||
key={fieldItem.name}
|
key={fieldItem.name}
|
||||||
fieldItem={fieldItem}
|
fieldItem={fieldItem}
|
||||||
ActionIcon={IconPlus}
|
ActionIcon={
|
||||||
|
<LightIconButton Icon={IconPlus} accent="tertiary" />
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</TableSection>
|
</TableSection>
|
||||||
|
|||||||
Reference in New Issue
Block a user