Improve: 记住单元格详情 JSON 格式化状态 (#2252)

Co-authored-by: staff <staff@qimaos-MacBook-Pro.local>
This commit is contained in:
zipgandstaff authored and GitHub committed 2026-06-30 22:38:45 +08:00
1 parent 427d0c548b
commit c4de3738fc
10 files changed
+32 -15

No files matched your search

+17 -12
View File
@@ -158,7 +158,8 @@ import { formatShortcut } from "@/lib/shortcutRegistry";
import { SearchableSelect } from "@/components/ui/searchable-select";
const SqlPreviewPanel = defineAsyncComponent(() => import("@/components/editor/SqlPreviewPanel.vue"));
const FORMATTED_JSON_EDIT_WARNING_STORAGE_KEY = "dbx-cell-detail-formatted-json-edit-warning-shown";
const FORMATTED_JSON_EDIT_WARNING_COUNT_STORAGE_KEY = "dbx-cell-detail-formatted-json-edit-warning-count";
const FORMATTED_JSON_EDIT_WARNING_MAX_COUNT = 10;
const { t } = useI18n();
const slots = useSlots();
@@ -448,8 +449,6 @@ const rowDetailDialogOpen = ref(false);
const rowDetailDialogRowId = ref<number | null>(null);
const columnDetailDialogOpen = ref(false);
const columnDetailDialogColumnIndex = ref<number | null>(null);
const cellDetailJsonView = ref(false);
const sideDetailJsonView = ref(false);
const rowDetailSearch = ref("");
const columnDetailSearch = ref("");
const isResizingDetail = ref(false);
@@ -3810,6 +3809,10 @@ const dialogCellDetail = computed(() => {
return target ? cellDetailFor(target.rowIndex, target.col) : null;
});
const cellDetailJsonFormatted = computed(() => settingsStore.editorSettings.cellDetailJsonFormatted);
const sideDetailJsonView = computed(() => cellDetailJsonFormatted.value && !!activeCellDetail.value?.formattedJson);
const cellDetailJsonView = computed(() => cellDetailJsonFormatted.value && !!dialogCellDetail.value?.formattedJson);
const rowDetail = computed(() => {
if (rowDetailDialogRowId.value === null) return null;
const item = getRowItem(rowDetailDialogRowId.value);
@@ -3854,8 +3857,7 @@ const filteredRowDetailFields = computed(() => (rowDetail.value ? filterDataGrid
const filteredColumnDetailFields = computed(() => (columnDetail.value ? filterDataGridDetailFields(columnDetail.value.fields, columnDetailSearch.value) : []));
watch(cellDetailDialogOpen, (open) => {
if (open) cellDetailJsonView.value = false;
else cellDetailDialogTarget.value = null;
if (!open) cellDetailDialogTarget.value = null;
});
watch(rowDetailDialogOpen, (open) => {
@@ -4014,7 +4016,6 @@ async function prefetchDetailSqlCondition() {
watch(activeCellDetail, (detail) => {
void prefetchDetailSqlCondition();
sideDetailJsonView.value = false;
if (activeCellDetailTab.value !== "valueEditor") return;
if (!detail?.isEditable) {
resetDetailEdit();
@@ -4174,9 +4175,14 @@ function cellDetailEditText(detail: DataGridCellDetail): string {
function warnFormattedJsonEditIfNeeded(detail: DataGridCellDetail, force = false) {
if (!force && (!sideDetailJsonView.value || !detail.formattedJson)) return;
if (safeLocalStorageGet(FORMATTED_JSON_EDIT_WARNING_STORAGE_KEY) === "1") return;
const count = Number(safeLocalStorageGet(FORMATTED_JSON_EDIT_WARNING_COUNT_STORAGE_KEY)) || 0;
if (count >= FORMATTED_JSON_EDIT_WARNING_MAX_COUNT) return;
toast(t("grid.formattedJsonEditWarning"), 10000);
safeLocalStorageSet(FORMATTED_JSON_EDIT_WARNING_STORAGE_KEY, "1");
safeLocalStorageSet(FORMATTED_JSON_EDIT_WARNING_COUNT_STORAGE_KEY, String(count + 1));
}
function toggleCellDetailJsonFormatted() {
settingsStore.updateEditorSettings({ cellDetailJsonFormatted: !cellDetailJsonFormatted.value });
}
function startDetailEdit() {
@@ -6038,7 +6044,6 @@ async function openDialogCellInSidePanel() {
showCellDetails(detail.rowNumber - 1, detail.colIndex);
cellDetailDialogOpen.value = false;
await nextTick();
sideDetailJsonView.value = cellDetailJsonView.value && !!detail.formattedJson;
if (detail.isEditable) startDetailEdit();
}
@@ -8917,7 +8922,7 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
<div class="flex min-h-5 items-center justify-between gap-2">
<div class="text-muted-foreground">{{ t("grid.cellValue") }}</div>
<div v-if="!isEditingDetail" class="flex items-center gap-1">
<Button v-if="activeCellDetail.formattedJson" :variant="sideDetailJsonView ? 'secondary' : 'ghost'" size="sm" class="h-5 gap-1 px-1.5 text-xs" :title="t('grid.formattedJson')" @click="sideDetailJsonView = !sideDetailJsonView">
<Button v-if="activeCellDetail.formattedJson" :variant="sideDetailJsonView ? 'secondary' : 'ghost'" size="sm" class="h-5 gap-1 px-1.5 text-xs" :title="t('grid.formattedJson')" @click="toggleCellDetailJsonFormatted">
<Code2 class="h-3 w-3" />
{{ t("grid.formattedJson") }}
</Button>
@@ -8959,7 +8964,7 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
</a>
</div>
<template v-if="isEditingDetail">
<div class="min-h-32 shrink-0" :class="cellDetailPanelIsBottom ? 'h-32' : ''" :style="sideDetailEditorStyle">
<div :class="cellDetailPanelIsBottom ? 'min-h-0 flex-1' : 'min-h-32 shrink-0'" :style="sideDetailEditorStyle">
<TemporalCellEditor v-if="detailTemporalEditorKind" v-model="detailEditValue" :kind="detailTemporalEditorKind" variant="inline" :commit-on-close="false" @cancel="cancelDetailEdit" @commit="commitDetailEdit" />
<div v-else ref="detailsEditorContainer" data-cell-detail-editor-root class="min-h-0 h-full w-full rounded border overflow-hidden" />
</div>
@@ -9224,7 +9229,7 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
<div class="flex items-center justify-between gap-2">
<div class="text-muted-foreground">{{ t("grid.cellValue") }}</div>
<div class="flex items-center gap-1">
<Button v-if="dialogCellDetail.formattedJson" :variant="cellDetailJsonView ? 'secondary' : 'ghost'" size="sm" class="h-6 gap-1 px-2 text-xs" :title="t('grid.formattedJson')" @click="cellDetailJsonView = !cellDetailJsonView">
<Button v-if="dialogCellDetail.formattedJson" :variant="cellDetailJsonView ? 'secondary' : 'ghost'" size="sm" class="h-6 gap-1 px-2 text-xs" :title="t('grid.formattedJson')" @click="toggleCellDetailJsonFormatted">
<Code2 class="h-3 w-3" />
{{ t("grid.formattedJson") }}
</Button>
+1 -1
View File
@@ -798,7 +798,7 @@ export default {
copyColumnTsv: "Copy Column (TSV)",
editValue: "Edit Value",
formatJson: "Format JSON",
formattedJsonEditWarning: "You are editing formatted JSON. Saving writes back formatted text and may change the original whitespace and layout",
formattedJsonEditWarning: "You are editing formatted JSON. Saving will write it as JSON, so the original formatting may change.",
setNull: "Set NULL",
restoreOriginalValue: "Restore Original",
copyColumnName: "Copy Column Name",
+1
View File
@@ -788,6 +788,7 @@ export default withEnglishFallback({
copyColumnTsv: "Copiar columna (TSV)",
editValue: "Editar valor",
formatJson: "Formatear JSON",
formattedJsonEditWarning: "Estás editando JSON formateado. Al guardar se escribirá como JSON, por lo que el formato original puede cambiar.",
setNull: "Establecer NULL",
restoreOriginalValue: "Restaurar original",
copyColumnName: "Copiar nombre de columna",
+1
View File
@@ -795,6 +795,7 @@ export default withEnglishFallback({
copyColumnTsv: "Copia Colonna (TSV)",
editValue: "Modifica Valore",
formatJson: "Formatta JSON",
formattedJsonEditWarning: "Stai modificando JSON formattato. Salvando verrà scritto come JSON, quindi la formattazione originale potrebbe cambiare.",
setNull: "Imposta NULL",
restoreOriginalValue: "Ripristina Originale",
copyColumnName: "Copia Nome Colonna",
+1
View File
@@ -786,6 +786,7 @@ export default withEnglishFallback({
copyColumnTsv: "列をコピー (TSV)",
editValue: "値を編集",
formatJson: "JSONをフォーマット",
formattedJsonEditWarning: "フォーマット済みJSONを編集中です。保存するとJSONとして書き込まれるため、元の書式が変わる場合があります。",
setNull: "NULLに設定",
restoreOriginalValue: "元の値に戻す",
copyColumnName: "列名をコピー",
+1
View File
@@ -800,6 +800,7 @@ export default withEnglishFallback({
copyColumnTsv: "Copiar Coluna (TSV)",
editValue: "Editar Valor",
formatJson: "Formatar JSON",
formattedJsonEditWarning: "Você está editando JSON formatado. Ao salvar, ele será gravado como JSON, então a formatação original pode mudar.",
setNull: "Definir NULL",
restoreOriginalValue: "Restaurar Original",
copyColumnName: "Copiar Nome da Coluna",
+1 -1
View File
@@ -801,7 +801,7 @@ export default withEnglishFallback({
copyColumnTsv: "复制列 (TSV)",
editValue: "编辑值",
formatJson: "格式化 JSON",
formattedJsonEditWarning: "正在编辑格式化后的 JSON。保存后会写回格式化文本,原始空白和排版可能变化",
formattedJsonEditWarning: "正在编辑格式化后的 JSON。保存后会以JSON格式写入,原始排版可能变化。",
setNull: "设为 NULL",
restoreOriginalValue: "恢复原值",
copyColumnName: "复制列名",
+1 -1
View File
@@ -789,7 +789,7 @@ export default withEnglishFallback({
copyColumnTsv: "複製欄 (TSV)",
editValue: "編輯值",
formatJson: "格式化 JSON",
formattedJsonEditWarning: "正在編輯格式化後的 JSON。儲存後會寫回格式化文字,原始空白和排版可能改變",
formattedJsonEditWarning: "正在編輯格式化後的 JSON。儲存後會以 JSON 格式寫入,原始排版可能改變。",
setNull: "設為 NULL",
restoreOriginalValue: "復原資料",
copyColumnName: "複製欄位名稱",
+4
View File
@@ -351,6 +351,7 @@ export interface EditorSettings {
tableInfoDrawerWidth: number;
cellDetailDrawerWidth: number;
cellDetailPanelLayout: CellDetailPanelLayout;
cellDetailJsonFormatted: boolean;
shortcuts: ShortcutSettings;
sqlFormatter: SqlFormatterSettings;
sidebarActivation: SidebarActivation;
@@ -459,6 +460,7 @@ export const DEFAULT_EDITOR_SETTINGS: EditorSettings = {
tableInfoDrawerWidth: 320,
cellDetailDrawerWidth: 380,
cellDetailPanelLayout: "bottom",
cellDetailJsonFormatted: false,
shortcuts: normalizeShortcutSettings(),
sqlFormatter: normalizeSqlFormatterSettings(DEFAULT_SQL_FORMATTER_SETTINGS),
sidebarActivation: "single",
@@ -656,6 +658,7 @@ export function normalizeEditorSettings(settings: Partial<EditorSettings>, exist
tableInfoDrawerWidth: normalizeDrawerWidth(settings.tableInfoDrawerWidth, 240, DEFAULT_EDITOR_SETTINGS.tableInfoDrawerWidth),
cellDetailDrawerWidth: normalizeDrawerWidth(settings.cellDetailDrawerWidth, 260, DEFAULT_EDITOR_SETTINGS.cellDetailDrawerWidth),
cellDetailPanelLayout: normalizeCellDetailPanelLayout(settings.cellDetailPanelLayout),
cellDetailJsonFormatted: typeof settings.cellDetailJsonFormatted === "boolean" ? settings.cellDetailJsonFormatted : DEFAULT_EDITOR_SETTINGS.cellDetailJsonFormatted,
shortcuts: normalizeShortcutSettings(settings.shortcuts),
sqlFormatter: normalizeSqlFormatterSettings(settings.sqlFormatter),
sidebarActivation: settings.sidebarActivation === "single" || settings.sidebarActivation === "double" ? settings.sidebarActivation : DEFAULT_EDITOR_SETTINGS.sidebarActivation,
@@ -835,6 +838,7 @@ export const useSettingsStore = defineStore("settings", () => {
if (partial.tableInfoDrawerWidth !== undefined) editorSettings.value.tableInfoDrawerWidth = normalizeDrawerWidth(partial.tableInfoDrawerWidth, 240, DEFAULT_EDITOR_SETTINGS.tableInfoDrawerWidth);
if (partial.cellDetailDrawerWidth !== undefined) editorSettings.value.cellDetailDrawerWidth = normalizeDrawerWidth(partial.cellDetailDrawerWidth, 260, DEFAULT_EDITOR_SETTINGS.cellDetailDrawerWidth);
if (partial.cellDetailPanelLayout !== undefined) editorSettings.value.cellDetailPanelLayout = normalizeCellDetailPanelLayout(partial.cellDetailPanelLayout);
if (partial.cellDetailJsonFormatted !== undefined) editorSettings.value.cellDetailJsonFormatted = partial.cellDetailJsonFormatted === true;
if (partial.shortcuts !== undefined) editorSettings.value.shortcuts = normalizeShortcutSettings(partial.shortcuts);
if (partial.sqlFormatter !== undefined) editorSettings.value.sqlFormatter = normalizeSqlFormatterSettings(partial.sqlFormatter);
if (partial.sidebarActivation !== undefined) editorSettings.value.sidebarActivation = partial.sidebarActivation;