feat: dashboard card title allow edit
This commit is contained in:
parent
90f22afe28
commit
d03f60f6a1
38
src/client/components/EditableText.tsx
Normal file
38
src/client/components/EditableText.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import { Input } from 'antd';
|
||||
import clsx from 'clsx';
|
||||
import React, { useState } from 'react';
|
||||
import { useWatch } from '../hooks/useWatch';
|
||||
|
||||
interface EditableTextProps {
|
||||
className?: string;
|
||||
enable?: boolean;
|
||||
defaultValue: string;
|
||||
onSave: (text: string) => void;
|
||||
}
|
||||
export const EditableText: React.FC<EditableTextProps> = React.memo((props) => {
|
||||
const [text, setText] = useState(props.defaultValue);
|
||||
const enable = props.enable ?? true;
|
||||
|
||||
useWatch([props.defaultValue], () => {
|
||||
setText(props.defaultValue);
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{enable ? (
|
||||
<Input
|
||||
className={clsx(
|
||||
props.className,
|
||||
'border-0 p-0 outline-0 !shadow-none rounded-none'
|
||||
)}
|
||||
value={text}
|
||||
onChange={(e) => setText(e.target.value)}
|
||||
onBlur={(e) => props.onSave(e.target.value)}
|
||||
/>
|
||||
) : (
|
||||
<span className={props.className}>{text}</span>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
});
|
||||
EditableText.displayName = 'EditableText';
|
@ -23,6 +23,7 @@ export const DashboardGrid: React.FC<DashboardGridProps> = React.memo(
|
||||
className={clsx('layout', isEditMode && 'select-none')}
|
||||
layouts={layouts}
|
||||
rowHeight={50}
|
||||
draggableCancel=".non-draggable"
|
||||
isDraggable={isEditMode}
|
||||
isResizable={isEditMode}
|
||||
breakpoints={{ lg: 1200, md: 768, sm: 0 }}
|
||||
|
@ -2,7 +2,7 @@ import { useMemo } from 'react';
|
||||
import { DashboardItem, useDashboardStore } from '../../../store/dashboard';
|
||||
import { WebsiteOverviewItem } from './WebsiteOverviewItem';
|
||||
import { NotFoundTip } from '../../NotFoundTip';
|
||||
import { Button, Card } from 'antd';
|
||||
import { Button, Card, Input, Typography } from 'antd';
|
||||
import React from 'react';
|
||||
import { DeleteOutlined } from '@ant-design/icons';
|
||||
import { useEvent } from '../../../hooks/useEvent';
|
||||
@ -11,13 +11,14 @@ import { MonitorHealthBarItem } from './MonitorHealthBarItem';
|
||||
import { MonitorMetricsItem } from './MonitorMetricsItem';
|
||||
import { MonitorChartItem } from './MonitorChartItem';
|
||||
import { MonitorEventsItem } from './MonitorEventsItem';
|
||||
import { EditableText } from '../../EditableText';
|
||||
|
||||
interface DashboardGridItemProps {
|
||||
item: DashboardItem;
|
||||
}
|
||||
export const DashboardGridItem: React.FC<DashboardGridItemProps> = React.memo(
|
||||
(props) => {
|
||||
const { isEditMode, removeItem } = useDashboardStore();
|
||||
const { isEditMode, removeItem, changeItemTitle } = useDashboardStore();
|
||||
const { key, id, title, type } = props.item;
|
||||
|
||||
const inner = useMemo(() => {
|
||||
@ -40,7 +41,6 @@ export const DashboardGridItem: React.FC<DashboardGridItemProps> = React.memo(
|
||||
|
||||
const handleDelete = useEvent(
|
||||
(e: React.MouseEvent<HTMLElement, MouseEvent>) => {
|
||||
console.log('e', e, key);
|
||||
e.stopPropagation();
|
||||
removeItem(key);
|
||||
}
|
||||
@ -49,7 +49,14 @@ export const DashboardGridItem: React.FC<DashboardGridItemProps> = React.memo(
|
||||
return (
|
||||
<Card
|
||||
className="h-full w-full overflow-auto"
|
||||
title={title}
|
||||
title={
|
||||
<EditableText
|
||||
className="non-draggable"
|
||||
enable={isEditMode}
|
||||
defaultValue={title}
|
||||
onSave={(text) => changeItemTitle(key, text)}
|
||||
/>
|
||||
}
|
||||
headStyle={{ padding: 10, minHeight: 40 }}
|
||||
bodyStyle={{ padding: 10 }}
|
||||
extra={
|
||||
|
@ -2,7 +2,7 @@ import { DependencyList, useLayoutEffect } from 'react';
|
||||
import { useEvent } from './useEvent';
|
||||
|
||||
/**
|
||||
* 监听变更并触发回调
|
||||
* Listen for changes and trigger callbacks
|
||||
*/
|
||||
export function useWatch(deps: DependencyList, cb: () => void) {
|
||||
const memoizedFn = useEvent(cb);
|
||||
|
@ -25,6 +25,7 @@ interface DashboardState {
|
||||
items: DashboardItem[];
|
||||
addItem: (type: DashboardItemType, id: string, title: string) => void;
|
||||
removeItem: (key: string) => void;
|
||||
changeItemTitle: (key: string, title: string) => void;
|
||||
}
|
||||
|
||||
export const defaultBlankLayouts = {
|
||||
@ -69,6 +70,22 @@ export const useDashboardStore = create<DashboardState>((set, get) => ({
|
||||
};
|
||||
});
|
||||
},
|
||||
changeItemTitle: (key: string, title: string) => {
|
||||
set((state) => {
|
||||
return {
|
||||
items: state.items.map((item) => {
|
||||
if (item.key === key) {
|
||||
return {
|
||||
...item,
|
||||
title,
|
||||
};
|
||||
} else {
|
||||
return item;
|
||||
}
|
||||
}),
|
||||
};
|
||||
});
|
||||
},
|
||||
}));
|
||||
|
||||
export const defaultItemLayout: Record<DashboardItemType, Omit<Layout, 'i'>> = {
|
||||
|
@ -11,7 +11,7 @@ import {
|
||||
TitleContentToken,
|
||||
} from './type';
|
||||
|
||||
export { ContentToken };
|
||||
export type { ContentToken };
|
||||
|
||||
export const token = {
|
||||
text: (content: string): TextContentToken => ({
|
||||
|
Loading…
Reference in New Issue
Block a user