1518 extensibility front add an application section in settings (#15056)
Protected by IS_APPLICATION_ENABLED featureFlag Add `Application` section in settings <img width="301" height="137" alt="image" src="https://github.com/user-attachments/assets/ee53bdd2-36f6-45c6-8646-17b1e08abf00" /> A `settings/applications` route listing all installed applications <img width="661" height="428" alt="image" src="https://github.com/user-attachments/assets/69d534c4-4e9e-452a-a3d9-ded0223bb457" /> Introduce a new Tag for application managed items <img width="885" height="759" alt="image" src="https://github.com/user-attachments/assets/19767be5-61e5-4bd2-a51d-54ed9bfb1923" /> A `settings/applications/<application_id>` details setting page listing all objects, serverlessFunctions and agents created by the application: <img width="917" height="778" alt="image" src="https://github.com/user-attachments/assets/7fc056a6-1d73-4242-b2eb-6f8955d8597d" /> A `settings/applications/<application_id>/<serverless_function_id>` <img width="905" height="652" alt="image" src="https://github.com/user-attachments/assets/56ca0021-26bf-42cb-9abf-34879f16050a" /> Add trigger tab in serverless function details (readonly for now) <img width="899" height="724" alt="image" src="https://github.com/user-attachments/assets/5eeefa35-f2a4-4fd8-a640-7b5c5891f226" /> Set object, serverless and agent setting detail pages readonly for managed items <img width="1075" height="859" alt="image" src="https://github.com/user-attachments/assets/57c73d69-4980-47a2-b752-8dc5ab494530" /> <img width="648" height="582" alt="image" src="https://github.com/user-attachments/assets/5ad5f3f7-3bc3-4e40-870a-4981c6492524" /> <img width="982" height="692" alt="image" src="https://github.com/user-attachments/assets/7ad756c4-5d33-4a0a-9eb8-416c040362b9" /> <img width="1077" height="647" alt="image" src="https://github.com/user-attachments/assets/e086b9f5-4062-4d10-82a9-4023de3cad3f" />
This commit is contained in:
+8
-88
@@ -1,19 +1,15 @@
|
||||
import { Controller, FormProvider } from 'react-hook-form';
|
||||
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||
import { SettingsSkeletonLoader } from '@/settings/components/SettingsSkeletonLoader';
|
||||
import { type WebhookFormMode } from '@/settings/developers/constants/WebhookFormMode';
|
||||
import { useWebhookForm } from '@/settings/developers/hooks/useWebhookForm';
|
||||
import { Select } from '@/ui/input/components/Select';
|
||||
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
|
||||
import { TextArea } from '@/ui/input/components/TextArea';
|
||||
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
||||
import { useModal } from '@/ui/layout/modal/hooks/useModal';
|
||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import styled from '@emotion/styled';
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import { SettingsPath } from 'twenty-shared/types';
|
||||
import {
|
||||
@@ -22,38 +18,11 @@ import {
|
||||
isDefined,
|
||||
isValidUrl,
|
||||
} from 'twenty-shared/utils';
|
||||
import {
|
||||
H2Title,
|
||||
IconBox,
|
||||
IconNorthStar,
|
||||
IconPlus,
|
||||
IconTrash,
|
||||
useIcons,
|
||||
} from 'twenty-ui/display';
|
||||
import { Button, IconButton, type SelectOption } from 'twenty-ui/input';
|
||||
import { H2Title, IconTrash } from 'twenty-ui/display';
|
||||
import { Button } from 'twenty-ui/input';
|
||||
import { Section } from 'twenty-ui/layout';
|
||||
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
||||
|
||||
const OBJECT_DROPDOWN_WIDTH = 340;
|
||||
const ACTION_DROPDOWN_WIDTH = 140;
|
||||
const OBJECT_MOBILE_WIDTH = 150;
|
||||
const ACTION_MOBILE_WIDTH = 140;
|
||||
|
||||
const StyledFilterRow = styled.div<{ isMobile: boolean }>`
|
||||
display: grid;
|
||||
grid-template-columns: ${({ isMobile }) =>
|
||||
isMobile
|
||||
? `${OBJECT_MOBILE_WIDTH}px ${ACTION_MOBILE_WIDTH}px auto`
|
||||
: `${OBJECT_DROPDOWN_WIDTH}px ${ACTION_DROPDOWN_WIDTH}px auto`};
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
margin-bottom: ${({ theme }) => theme.spacing(2)};
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const StyledPlaceholder = styled.div`
|
||||
height: ${({ theme }) => theme.spacing(8)};
|
||||
width: ${({ theme }) => theme.spacing(8)};
|
||||
`;
|
||||
import { SettingsDatabaseEventsForm } from '@/settings/components/SettingsDatabaseEventsForm';
|
||||
|
||||
const DELETE_WEBHOOK_MODAL_ID = 'delete-webhook-modal';
|
||||
|
||||
@@ -68,9 +37,6 @@ export const SettingsDevelopersWebhookForm = ({
|
||||
}: SettingsDevelopersWebhookFormProps) => {
|
||||
const { t } = useLingui();
|
||||
const navigate = useNavigateSettings();
|
||||
const { objectMetadataItems } = useObjectMetadataItems();
|
||||
const isMobile = useIsMobile();
|
||||
const { getIcon } = useIcons();
|
||||
const { openModal } = useModal();
|
||||
const {
|
||||
formConfig,
|
||||
@@ -99,22 +65,6 @@ export const SettingsDevelopersWebhookForm = ({
|
||||
return <SettingsSkeletonLoader />;
|
||||
}
|
||||
|
||||
const objectOptions: SelectOption<string>[] = [
|
||||
{ label: 'All Objects', value: '*', Icon: IconNorthStar },
|
||||
...objectMetadataItems.map((item) => ({
|
||||
label: item.labelPlural,
|
||||
value: item.nameSingular,
|
||||
Icon: getIcon(item.icon),
|
||||
})),
|
||||
];
|
||||
|
||||
const actionOptions: SelectOption<string>[] = [
|
||||
{ label: 'All', value: '*', Icon: IconNorthStar },
|
||||
{ label: 'Created', value: 'created', Icon: IconPlus },
|
||||
{ label: 'Updated', value: 'updated', Icon: IconBox },
|
||||
{ label: 'Deleted', value: 'deleted', Icon: IconTrash },
|
||||
];
|
||||
|
||||
const descriptionTextAreaId = `${webhookId}-description`;
|
||||
const targetUrlTextInputId = `${webhookId}-target-url`;
|
||||
const secretTextInputId = `${webhookId}-secret`;
|
||||
@@ -200,41 +150,11 @@ export const SettingsDevelopersWebhookForm = ({
|
||||
name="operations"
|
||||
control={formConfig.control}
|
||||
render={({ field: { value } }) => (
|
||||
<>
|
||||
{value.map((operation, index) => (
|
||||
<StyledFilterRow key={index} isMobile={isMobile}>
|
||||
<Select
|
||||
dropdownId={`object-webhook-type-select-${index}`}
|
||||
value={operation.object}
|
||||
options={objectOptions}
|
||||
onChange={(newValue) =>
|
||||
updateOperation(index, 'object', newValue)
|
||||
}
|
||||
fullWidth
|
||||
emptyOption={{ label: 'Object', value: null }}
|
||||
/>
|
||||
<Select
|
||||
dropdownId={`operation-webhook-type-select-${index}`}
|
||||
value={operation.action}
|
||||
options={actionOptions}
|
||||
onChange={(newValue) =>
|
||||
updateOperation(index, 'action', newValue)
|
||||
}
|
||||
fullWidth
|
||||
/>
|
||||
{isDefined(operation.object) ? (
|
||||
<IconButton
|
||||
Icon={IconTrash}
|
||||
variant="tertiary"
|
||||
size="medium"
|
||||
onClick={() => removeOperation(index)}
|
||||
/>
|
||||
) : (
|
||||
<StyledPlaceholder />
|
||||
)}
|
||||
</StyledFilterRow>
|
||||
))}
|
||||
</>
|
||||
<SettingsDatabaseEventsForm
|
||||
events={value}
|
||||
updateOperation={updateOperation}
|
||||
removeOperation={removeOperation}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
Reference in New Issue
Block a user