[Dashboards] - add iframe widget (#14251)
closes https://github.com/twentyhq/core-team-issues/issues/1415
This commit is contained in:
@@ -4,6 +4,7 @@ import { CommandMenuAskAIPage } from '@/command-menu/pages/ask-ai/components/Com
|
||||
import { CommandMenuCalendarEventPage } from '@/command-menu/pages/calendar-event/components/CommandMenuCalendarEventPage';
|
||||
import { CommandMenuMessageThreadPage } from '@/command-menu/pages/message-thread/components/CommandMenuMessageThreadPage';
|
||||
import { CommandMenuPageLayoutGraphTypeSelect } from '@/command-menu/pages/page-layout/components/CommandMenuPageLayoutGraphTypeSelect';
|
||||
import { CommandMenuPageLayoutIframeConfig } from '@/command-menu/pages/page-layout/components/CommandMenuPageLayoutIframeConfig';
|
||||
import { CommandMenuPageLayoutWidgetTypeSelect } from '@/command-menu/pages/page-layout/components/CommandMenuPageLayoutWidgetTypeSelect';
|
||||
import { CommandMenuMergeRecordPage } from '@/command-menu/pages/record-page/components/CommandMenuMergeRecordPage';
|
||||
import { CommandMenuRecordPage } from '@/command-menu/pages/record-page/components/CommandMenuRecordPage';
|
||||
@@ -48,4 +49,8 @@ export const COMMAND_MENU_PAGES_CONFIG = new Map<
|
||||
CommandMenuPages.PageLayoutGraphTypeSelect,
|
||||
<CommandMenuPageLayoutGraphTypeSelect />,
|
||||
],
|
||||
[
|
||||
CommandMenuPages.PageLayoutIframeConfig,
|
||||
<CommandMenuPageLayoutIframeConfig />,
|
||||
],
|
||||
]);
|
||||
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { FormTextFieldInput } from '@/object-record/record-field/ui/form-types/components/FormTextFieldInput';
|
||||
import { useCreatePageLayoutIframeWidget } from '@/settings/page-layout/hooks/useCreatePageLayoutIframeWidget';
|
||||
import { usePageLayoutWidgetUpdate } from '@/settings/page-layout/hooks/usePageLayoutWidgetUpdate';
|
||||
import { pageLayoutEditingWidgetIdState } from '@/settings/page-layout/states/pageLayoutEditingWidgetIdState';
|
||||
import { pageLayoutWidgetsState } from '@/settings/page-layout/states/pageLayoutWidgetsState';
|
||||
import styled from '@emotion/styled';
|
||||
import { useState } from 'react';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { isValidUrl } from 'twenty-shared/utils';
|
||||
import { Button } from 'twenty-ui/input';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: ${({ theme }) => theme.spacing(2)};
|
||||
gap: ${({ theme }) => theme.spacing(3)};
|
||||
`;
|
||||
|
||||
const StyledSectionTitle = styled.div`
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
font-size: ${({ theme }) => theme.font.size.sm};
|
||||
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||
padding-left: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const StyledButtonContainer = styled.div`
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
export const CommandMenuPageLayoutIframeConfig = () => {
|
||||
const { closeCommandMenu } = useCommandMenu();
|
||||
const { createPageLayoutIframeWidget } = useCreatePageLayoutIframeWidget();
|
||||
const { handleUpdateWidget } = usePageLayoutWidgetUpdate();
|
||||
const [pageLayoutEditingWidgetId, setPageLayoutEditingWidgetId] =
|
||||
useRecoilState(pageLayoutEditingWidgetIdState);
|
||||
const pageLayoutWidgets = useRecoilValue(pageLayoutWidgetsState);
|
||||
|
||||
const editingWidget = pageLayoutWidgets.find(
|
||||
(w) => w.id === pageLayoutEditingWidgetId,
|
||||
);
|
||||
const isEditMode = !!editingWidget;
|
||||
|
||||
const [title, setTitle] = useState(editingWidget?.title || '');
|
||||
const [url, setUrl] = useState(editingWidget?.configuration?.url || '');
|
||||
const [urlError, setUrlError] = useState('');
|
||||
|
||||
const validateUrl = (urlString: string): boolean => {
|
||||
const trimmedUrl = urlString.trim();
|
||||
|
||||
if (!isValidUrl(trimmedUrl)) {
|
||||
setUrlError('Please enter a valid URL');
|
||||
return false;
|
||||
}
|
||||
|
||||
setUrlError('');
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleUrlChange = (value: string) => {
|
||||
setUrl(value);
|
||||
validateUrl(value);
|
||||
};
|
||||
|
||||
const handleSubmit = () => {
|
||||
if (!title.trim()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateUrl(url)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isEditMode && pageLayoutEditingWidgetId !== null) {
|
||||
handleUpdateWidget(pageLayoutEditingWidgetId, {
|
||||
title: title.trim(),
|
||||
configuration: {
|
||||
...editingWidget?.configuration,
|
||||
url: url.trim(),
|
||||
},
|
||||
});
|
||||
setPageLayoutEditingWidgetId(null);
|
||||
} else {
|
||||
createPageLayoutIframeWidget(title.trim(), url.trim());
|
||||
}
|
||||
|
||||
closeCommandMenu();
|
||||
};
|
||||
|
||||
const isFormValid = title.trim() && url.trim() && !urlError;
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<StyledSectionTitle>
|
||||
{isEditMode ? 'Edit iFrame Widget' : 'Configure iFrame Widget'}
|
||||
</StyledSectionTitle>
|
||||
|
||||
<FormTextFieldInput
|
||||
label="Widget Title"
|
||||
placeholder="e.g., Analytics Dashboard"
|
||||
defaultValue={title}
|
||||
onChange={setTitle}
|
||||
/>
|
||||
|
||||
<FormTextFieldInput
|
||||
label="URL to Embed"
|
||||
placeholder="https://example.com/embed"
|
||||
defaultValue={url}
|
||||
onChange={handleUrlChange}
|
||||
error={urlError}
|
||||
/>
|
||||
|
||||
<StyledButtonContainer>
|
||||
<Button
|
||||
title={isEditMode ? 'Save Changes' : 'Create Widget'}
|
||||
onClick={handleSubmit}
|
||||
disabled={!isFormValid}
|
||||
variant="primary"
|
||||
size="small"
|
||||
/>
|
||||
</StyledButtonContainer>
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
+19
-9
@@ -45,7 +45,7 @@ const widgetTypeOptions = [
|
||||
type: WidgetType.IFRAME,
|
||||
icon: IconFrame,
|
||||
title: 'Add an iframe',
|
||||
disabled: true,
|
||||
disabled: false,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -56,14 +56,24 @@ export const CommandMenuPageLayoutWidgetTypeSelect = () => {
|
||||
);
|
||||
|
||||
const handleSelectWidget = (widgetType: WidgetType) => {
|
||||
if (widgetType === WidgetType.GRAPH) {
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.PageLayoutGraphTypeSelect,
|
||||
pageTitle: 'Select Graph Type',
|
||||
pageIcon: IconChartPie,
|
||||
});
|
||||
} else {
|
||||
setPageLayoutDraggedArea(null);
|
||||
switch (widgetType) {
|
||||
case WidgetType.GRAPH:
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.PageLayoutGraphTypeSelect,
|
||||
pageTitle: 'Select Graph Type',
|
||||
pageIcon: IconChartPie,
|
||||
});
|
||||
break;
|
||||
case WidgetType.IFRAME:
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.PageLayoutIframeConfig,
|
||||
pageTitle: 'Configure iFrame',
|
||||
pageIcon: IconFrame,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
setPageLayoutDraggedArea(null);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -16,4 +16,5 @@ export enum CommandMenuPages {
|
||||
ViewPreviousAIChats = 'view-previous-ai-chats',
|
||||
PageLayoutWidgetTypeSelect = 'page-layout-widget-type-select',
|
||||
PageLayoutGraphTypeSelect = 'page-layout-graph-type-select',
|
||||
PageLayoutIframeConfig = 'page-layout-iframe-config',
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user