Open recent dropwdown (#588)

* set up open recent basic UI

* fix sorting bug

* add overflow

* handle no saved diagrams

* better dates and translations

* bug fix open recent not updating when diagram opened through modal

* fix for test cases

* updates as guided

* bumped down luxon changed diagrams variable name and added translation usage for see all

* Update src/components/EditorHeader/ControlPanel.jsx

Co-authored-by: 1ilit <1ilit@proton.me>

* Update src/components/EditorHeader/ControlPanel.jsx

Co-authored-by: 1ilit <1ilit@proton.me>

* Update src/components/EditorHeader/ControlPanel.jsx

Co-authored-by: 1ilit <1ilit@proton.me>

* Update src/components/EditorHeader/ControlPanel.jsx

Co-authored-by: 1ilit <1ilit@proton.me>

* Update src/components/EditorHeader/ControlPanel.jsx

Co-authored-by: 1ilit <1ilit@proton.me>

* Update src/components/EditorHeader/ControlPanel.jsx

Co-authored-by: 1ilit <1ilit@proton.me>

* cleanup suggestions

* reveret non required changes

---------

Co-authored-by: 1ilit <1ilit@proton.me>
This commit is contained in:
Nimit Sharma
2025-09-27 02:39:38 +05:30
committed by GitHub
parent a2e453f398
commit 7359cb72c6
4 changed files with 118 additions and 26 deletions

View File

@@ -63,6 +63,7 @@ import {
useAreas,
useEnums,
useFullscreen,
useTasks,
} from "../../hooks";
import { enterFullscreen, exitFullscreen } from "../../utils/fullscreen";
import { dataURItoBlob } from "../../utils/utils";
@@ -83,7 +84,8 @@ import { exportSavedData } from "../../utils/exportSavedData";
import { nanoid } from "nanoid";
import { getTableHeight } from "../../utils/utils";
import { deleteFromCache, STORAGE_KEY } from "../../utils/cache";
import { useLiveQuery } from "dexie-react-hooks";
import { DateTime } from "luxon";
export default function ControlPanel({
diagramId,
setDiagramId,
@@ -118,6 +120,7 @@ export default function ControlPanel({
deleteRelationship,
updateRelationship,
database,
setDatabase,
} = useDiagram();
const { enums, setEnums, deleteEnum, addEnum, updateEnum } = useEnums();
const { types, addType, deleteType, updateType, setTypes } = useTypes();
@@ -738,10 +741,54 @@ export default function ControlPanel({
setLayout((prev) => ({ ...prev, dbmlEditor: !prev.dbmlEditor }));
};
const save = () => setSaveState(State.SAVING);
const recentlyOpenedDiagrams = useLiveQuery(() =>
db.diagrams.orderBy("lastModified").reverse().limit(10).toArray(),
);
const open = () => setModal(MODAL.OPEN);
const saveDiagramAs = () => setModal(MODAL.SAVEAS);
const fullscreen = useFullscreen();
const { setTasks } = useTasks();
const loadDiagram = async (id) => {
await db.diagrams
.get(id)
.then((diagram) => {
if (diagram) {
if (diagram.database) {
setDatabase(diagram.database);
} else {
setDatabase(DB.GENERIC);
}
setDiagramId(diagram.id);
setTitle(diagram.name);
setTables(diagram.tables);
setRelationships(diagram.references);
setAreas(diagram.areas);
setNotes(diagram.notes);
setTasks(diagram.todos ?? []);
setTransform({
pan: diagram.pan,
zoom: diagram.zoom,
});
setUndoStack([]);
setRedoStack([]);
if (databases[database].hasTypes) {
setTypes(diagram.types ?? []);
}
if (databases[database].hasEnums) {
setEnums(diagram.enums ?? []);
}
window.name = `d ${diagram.id}`;
} else {
window.name = "";
Toast.error(t("didnt_find_diagram"));
}
})
.catch((error) => {
console.log(error);
Toast.error(t("didnt_find_diagram"));
});
};
const menu = {
file: {
new: {
@@ -757,6 +804,36 @@ export default function ControlPanel({
function: open,
shortcut: "Ctrl+O",
},
open_recent: {
children: [
...(recentlyOpenedDiagrams && recentlyOpenedDiagrams.length > 0
? [
...recentlyOpenedDiagrams.map((diagram) => ({
name: diagram.name,
label: DateTime.fromJSDate(new Date(diagram.lastModified))
.setLocale(i18n.language)
.toRelative(),
function: async () => {
await loadDiagram(diagram.id);
save();
},
})),
{ divider: true },
{
name: t("see_all"),
function: () => open(),
},
]
: [
{
name: t("no_saved_diagrams"),
disabled: true,
},
]),
],
function: () => {},
},
save: {
function: save,
shortcut: "Ctrl+S",
@@ -1835,30 +1912,41 @@ export default function ControlPanel({
if (menu[category][item].children) {
return (
<Dropdown
style={{ width: "150px" }}
className="min-w-36 max-w-72"
key={item}
position="rightTop"
render={
<Dropdown.Menu>
{menu[category][item].children.map(
(e, i) => (
<Dropdown.Item
key={i}
onClick={e.function}
className="flex justify-between"
disabled={e.disabled}
>
<span>{e.name}</span>
{e.label && (
<Tag
size="small"
color="light-blue"
>
{e.label}
</Tag>
)}
</Dropdown.Item>
),
(e, i) => {
if (e.divider) {
return (
<Dropdown.Divider
key={`divider-${i}`}
/>
);
}
return (
<Dropdown.Item
key={i}
onClick={e.function}
className="flex w-full items-center justify-between gap-1"
disabled={e.disabled}
>
<span className="truncate flex-1 min-w-0">
{e.name}
</span>
{e.label && (
<Tag
size="small"
className="flex-shrink-0"
>
{e.label}
</Tag>
)}
</Dropdown.Item>
);
},
)}
</Dropdown.Menu>
}

View File

@@ -5,7 +5,7 @@ import {
Toast,
Modal as SemiUIModal,
} from "@douyinfe/semi-ui";
import { DB, MODAL, STATUS } from "../../../data/constants";
import { DB, MODAL, STATUS, State } from "../../../data/constants";
import { useState } from "react";
import { db } from "../../../data/db";
import {
@@ -17,6 +17,7 @@ import {
useTypes,
useUndoRedo,
useTasks,
useSaveState,
} from "../../../hooks";
import { saveAs } from "file-saver";
import { Parser } from "node-sql-parser";
@@ -67,6 +68,7 @@ export default function Modal({
const { setTasks } = useTasks();
const { setTransform } = useTransform();
const { setUndoStack, setRedoStack } = useUndoRedo();
const { setSaveState } = useSaveState();
const [uncontrolledTitle, setUncontrolledTitle] = useState(title);
const [importSource, setImportSource] = useState({
src: "",
@@ -127,6 +129,7 @@ export default function Modal({
setEnums(diagram.enums ?? []);
}
window.name = `d ${diagram.id}`;
setSaveState(State.SAVING);
} else {
window.name = "";
Toast.error(t("didnt_find_diagram"));

View File

@@ -28,7 +28,7 @@ export default function Open({ selectedDiagramId, setSelectedDiagramId }) {
bordered
icon={null}
closeIcon={null}
description={<div>You have no saved diagrams.</div>}
description={<div>{t("no_saved_diagrams")}</div>}
/>
) : (
<div className="max-h-[360px]">
@@ -47,9 +47,7 @@ export default function Open({ selectedDiagramId, setSelectedDiagramId }) {
<tr
key={d.id}
className={`${
selectedDiagramId === d.id
? "bg-blue-300/30"
: "hover-1"
selectedDiagramId === d.id ? "bg-blue-300/30" : "hover-1"
}`}
onClick={() => {
setSelectedDiagramId(d.id);

View File

@@ -15,7 +15,9 @@ const en = {
file: "File",
new: "New",
new_window: "New window",
no_saved_diagrams: "You have no saved diagrams",
open: "Open",
open_recent: "Open Recent",
save: "Save",
save_as: "Save as",
save_as_template: "Save as template",
@@ -276,6 +278,7 @@ const en = {
cache_cleared: "Cache cleared",
failed_to_record_version: "Failed to record version",
failed_to_load_diagram: "Failed to load diagram",
see_all: "See all",
},
};