mirror of
https://github.com/certimate-go/certimate.git
synced 2026-09-24 23:10:13 +08:00
feat(ui): add default workflow designer layout setting
This commit is contained in:
@@ -4,12 +4,12 @@ import {
|
||||
EditorRenderer,
|
||||
EditorState,
|
||||
FixedLayoutEditorProvider,
|
||||
FlowLayoutDefault,
|
||||
type FixedLayoutPluginContext,
|
||||
type FixedLayoutProps,
|
||||
type FlowDocumentJSON,
|
||||
type FlowNodeEntity,
|
||||
FlowTextKey,
|
||||
getNodeForm,
|
||||
} from "@flowgram.ai/fixed-layout-editor";
|
||||
import { createMinimapPlugin } from "@flowgram.ai/minimap-plugin";
|
||||
import "@flowgram.ai/fixed-layout-editor/index.css";
|
||||
@@ -139,9 +139,11 @@ const Designer = forwardRef<DesignerInstance, DesignerProps>(
|
||||
rendered.current = true;
|
||||
|
||||
// 画布初始化后向下滚动一点,露出可能被 Alert 遮挡的部分
|
||||
setTimeout(() => {
|
||||
ctx.playground.config.scroll({ scrollY: -80 });
|
||||
}, 1);
|
||||
if (defaultLayout === FlowLayoutDefault.VERTICAL_FIXED_LAYOUT) {
|
||||
setTimeout(() => {
|
||||
ctx.playground.config.scroll({ scrollY: -80 });
|
||||
}, 1);
|
||||
}
|
||||
},
|
||||
}),
|
||||
[defaultEditorState, defaultLayout, initialData, readonly, onDocumentChange, themeToken]
|
||||
@@ -195,12 +197,12 @@ const Designer = forwardRef<DesignerInstance, DesignerProps>(
|
||||
node = flowgramEditorRef.current!.document.getNode(node)!;
|
||||
}
|
||||
|
||||
const form = getNodeForm(node);
|
||||
const form = node.form;
|
||||
return form ? form.validate().then((res) => res && !form.state.invalid) : Promise.resolve(true);
|
||||
},
|
||||
validateAllNodes() {
|
||||
const nodes = flowgramEditorRef.current!.document.getAllNodes();
|
||||
const forms = nodes.map((node) => getNodeForm(node)).filter((form) => form != null);
|
||||
const forms = nodes.map((node) => node.form).filter((form) => form != null);
|
||||
return Promise.allSettled(forms.map((form) => form.validate())).then((res) => forms.every((form, index) => res[index] && !form.state.invalid));
|
||||
},
|
||||
};
|
||||
|
||||
@@ -7,8 +7,14 @@ if (!localStorage.getItem(LOCAL_STORAGE_KEY)) {
|
||||
}
|
||||
|
||||
type AppSettings = {
|
||||
// 每页显示的默认条目数
|
||||
/**
|
||||
* 每页显示的默认条目数。
|
||||
*/
|
||||
defaultPerPage?: number;
|
||||
/**
|
||||
* 工作流默认布局。
|
||||
*/
|
||||
defaultWorkflowLayout?: "horizontal" | "vertical";
|
||||
};
|
||||
|
||||
export type UseAppSettingsReturns = {
|
||||
@@ -26,6 +32,7 @@ const useAppSettings = (): UseAppSettingsReturns => {
|
||||
defaultValue: {},
|
||||
});
|
||||
state.defaultPerPage ??= 15;
|
||||
state.defaultWorkflowLayout ??= "vertical";
|
||||
|
||||
const resetState = useCallback(() => {
|
||||
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
||||
|
||||
@@ -29,6 +29,11 @@
|
||||
"settings.appearance.pagination.form.default_per_page.label": "Default items per page",
|
||||
"settings.appearance.pagination.form.default_per_page.placeholder": "Please enter default items per page",
|
||||
"settings.appearance.pagination.form.default_per_page.unit": "items per page",
|
||||
"settings.appearance.workflow.title": "Workflow",
|
||||
"settings.appearance.workflow.form.default_designer_layout.label": "Default designer layout",
|
||||
"settings.appearance.workflow.form.default_designer_layout.placeholder": "Please select default designer layout",
|
||||
"settings.appearance.workflow.form.default_designer_layout.option.horizontal": "Horizontal layout",
|
||||
"settings.appearance.workflow.form.default_designer_layout.option.vertical": "Vertical layout",
|
||||
|
||||
"settings.sslprovider.tab": "Certificate authority",
|
||||
"settings.sslprovider.ca.title": "System-wide CA",
|
||||
|
||||
@@ -29,6 +29,11 @@
|
||||
"settings.appearance.pagination.form.default_per_page.label": "列表页默认显示数量",
|
||||
"settings.appearance.pagination.form.default_per_page.placeholder": "请输入列表页默认显示数量",
|
||||
"settings.appearance.pagination.form.default_per_page.unit": "条每页",
|
||||
"settings.appearance.workflow.title": "工作流",
|
||||
"settings.appearance.workflow.form.default_designer_layout.label": "编辑器默认布局",
|
||||
"settings.appearance.workflow.form.default_designer_layout.placeholder": "请选择编辑器默认布局",
|
||||
"settings.appearance.workflow.form.default_designer_layout.option.horizontal": "水平布局",
|
||||
"settings.appearance.workflow.form.default_designer_layout.option.vertical": "垂直布局",
|
||||
|
||||
"settings.sslprovider.tab": "证书颁发机构",
|
||||
"settings.sslprovider.ca.title": "全局证书颁发机构",
|
||||
|
||||
@@ -24,6 +24,11 @@ const SettingsAppearance = () => {
|
||||
|
||||
<h2>{t("settings.appearance.pagination.title")}</h2>
|
||||
<SettingsAppearancePagination className="md:max-w-160" />
|
||||
|
||||
<Divider />
|
||||
|
||||
<h2>{t("settings.appearance.workflow.title")}</h2>
|
||||
<SettingsAppearanceWorkflow className="md:max-w-160" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -105,7 +110,7 @@ const SettingsAppearancePagination = ({ className, style }: { className?: string
|
||||
|
||||
const { appSettings: globalAppSettings, setAppSettings: setGlobalAppSettings } = useAppSettings();
|
||||
|
||||
const handleChange = (value: number) => {
|
||||
const handleChange = (value: (typeof globalAppSettings)["defaultPerPage"]) => {
|
||||
setGlobalAppSettings(
|
||||
produce(globalAppSettings, (draft) => {
|
||||
draft.defaultPerPage = value;
|
||||
@@ -133,4 +138,37 @@ const SettingsAppearancePagination = ({ className, style }: { className?: string
|
||||
);
|
||||
};
|
||||
|
||||
const SettingsAppearanceWorkflow = ({ className, style }: { className?: string; style?: React.CSSProperties }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { appSettings: globalAppSettings, setAppSettings: setGlobalAppSettings } = useAppSettings();
|
||||
|
||||
const handleChange = (value: (typeof globalAppSettings)["defaultWorkflowLayout"]) => {
|
||||
setGlobalAppSettings(
|
||||
produce(globalAppSettings, (draft) => {
|
||||
draft.defaultWorkflowLayout = value;
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={className} style={style}>
|
||||
<Form layout="vertical">
|
||||
<Form.Item label={t("settings.appearance.workflow.form.default_designer_layout.label")}>
|
||||
<Select
|
||||
options={["horizontal", "vertical"].map((value) => ({
|
||||
key: value,
|
||||
value: value,
|
||||
label: t(`settings.appearance.workflow.form.default_designer_layout.option.${value}`),
|
||||
}))}
|
||||
placeholder={t("settings.appearance.workflow.form.default_designer_layout.placeholder")}
|
||||
defaultValue={globalAppSettings.defaultWorkflowLayout}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsAppearance;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useMemo, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { FlowLayoutDefault } from "@flowgram.ai/fixed-layout-editor";
|
||||
import { IconArrowBackUp, IconDots, IconTransferIn, IconTransferOut } from "@tabler/icons-react";
|
||||
import { useDeepCompareEffect } from "ahooks";
|
||||
import { Alert, App, Button, Card, Dropdown, Result, Space, theme } from "antd";
|
||||
@@ -9,7 +10,7 @@ import Show from "@/components/Show";
|
||||
import { WorkflowDesigner, type WorkflowDesignerInstance, WorkflowNodeDrawer, WorkflowToolbar } from "@/components/workflow/designer";
|
||||
import WorkflowGraphExportModal from "@/components/workflow/WorkflowGraphExportModal";
|
||||
import WorkflowGraphImportModal from "@/components/workflow/WorkflowGraphImportModal";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
import { useAppSettings, useZustandShallowSelector } from "@/hooks";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { getErrMsg } from "@/utils/error";
|
||||
|
||||
@@ -19,6 +20,8 @@ const WorkflowDetailDesign = () => {
|
||||
const { token: themeToken } = theme.useToken();
|
||||
const { message, modal, notification } = App.useApp();
|
||||
|
||||
const { appSettings: globalAppSettings } = useAppSettings();
|
||||
|
||||
const { workflow, ...workflowStore } = useWorkflowStore(useZustandShallowSelector(["workflow", "orchestrate", "publish", "rollback"]));
|
||||
|
||||
const workflowRollbackDisabled = useMemo(() => !workflow.hasDraft || !workflow.hasContent, [workflow.hasDraft, workflow.hasContent]);
|
||||
@@ -134,7 +137,18 @@ const WorkflowDetailDesign = () => {
|
||||
},
|
||||
}}
|
||||
>
|
||||
<WorkflowDesigner ref={designerRef} onDocumentChange={handleDesignerDocumentChange} onNodeClick={(_, node) => designerNodeDrawer.open(node)}>
|
||||
<WorkflowDesigner
|
||||
ref={designerRef}
|
||||
defaultLayout={
|
||||
globalAppSettings.defaultWorkflowLayout === "horizontal"
|
||||
? FlowLayoutDefault.HORIZONTAL_FIXED_LAYOUT
|
||||
: globalAppSettings.defaultWorkflowLayout === "vertical"
|
||||
? FlowLayoutDefault.VERTICAL_FIXED_LAYOUT
|
||||
: void 0
|
||||
}
|
||||
onDocumentChange={handleDesignerDocumentChange}
|
||||
onNodeClick={(_, node) => designerNodeDrawer.open(node)}
|
||||
>
|
||||
<div className="absolute top-8 z-10 w-full px-4">
|
||||
<div className="container">
|
||||
<div className="flex items-center justify-end gap-4">
|
||||
|
||||
Reference in New Issue
Block a user