feat(grid): support datetime formatter patterns
This commit is contained in:
15 files changed
+289
-78
No files matched your search
@@ -115,7 +115,7 @@ import { buildBinaryHexViewRows } from "@/lib/binaryHexViewer";
|
||||
import { canFormatCellDetailJson, cellDetailEditorText, defaultCellDetailTab, formatJsonText, isGeometryColumnType, linkedCellDetailTarget, valueEditorActions, visibleCellDetailTabs, type CellDetailTab } from "@/lib/cellDetailPresentation";
|
||||
import { renderWktOnCanvas, isHexGeometry } from "@/lib/geometryPreview";
|
||||
import { buildDataGridCellDetail, buildDataGridColumnDetail, buildDataGridRowDetail, dataGridColumnDetailJson, dataGridColumnDetailTsv, dataGridRowDetailJson, dataGridRowDetailTsv, filterDataGridDetailFields, type DataGridCellDetail } from "@/lib/dataGridDetail";
|
||||
import { applyColumnFormatter, buildColumnFormatterKey, normalizeColumnFormatter, resolveColumnFormatter, type ColumnFormatterConfig, type DateTimeFormatterUnit } from "@/lib/columnFormatter";
|
||||
import { applyColumnFormatter, buildColumnFormatterKey, normalizeColumnFormatter, resolveColumnFormatter, type ColumnFormatterConfig, type DateTimeFormatterUnit, DateTimePatterns } from "@/lib/columnFormatter";
|
||||
import { temporalCellEditorKind, type TemporalCellEditorKind } from "@/lib/dataGridTemporalEditor";
|
||||
import { isEnumColumn, enumValuesForColumn } from "@/lib/dataGridEnumEditor";
|
||||
import { isCancelSearchShortcut, isCopyCurrentRowShortcut, isDeleteCurrentRowShortcut, isFocusSearchShortcut, isModRShortcut, isSaveShortcut, isToggleTransposeShortcut } from "@/lib/keyboardShortcuts";
|
||||
@@ -155,6 +155,7 @@ import { caretPositionInsideInsertedSqlSingleQuotes, insertedSqlSingleQuoteAtCar
|
||||
import { effectiveDatabaseTypeForConnection } from "@/lib/jdbcDialect";
|
||||
import { isMacOS } from "@/lib/platform";
|
||||
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";
|
||||
@@ -600,6 +601,7 @@ type FormatterDraftKind = Exclude<ColumnFormatterConfig["kind"], "custom-ref">;
|
||||
const CUSTOM_FORMATTER_NEW = "__new";
|
||||
const formatterKind = ref<FormatterDraftKind>("datetime");
|
||||
const formatterDateUnit = ref<DateTimeFormatterUnit>("auto");
|
||||
const formatterDatetimePattern = ref<string>("YYYY-MM-DD HH:mm:ss");
|
||||
const formatterJsonPath = ref("$.user.name");
|
||||
const formatterMaskPrefix = ref(4);
|
||||
const formatterMaskSuffix = ref(4);
|
||||
@@ -960,14 +962,15 @@ function currentFormatterDraft(): ColumnFormatterConfig {
|
||||
if (formatterKind.value === "custom-template") {
|
||||
return { kind: "custom-template", template: formatterCustomTemplate.value.trim() || "${value}" };
|
||||
}
|
||||
return { kind: "datetime", unit: formatterDateUnit.value };
|
||||
return { kind: "datetime", unit: formatterDateUnit.value, pattern: formatterDatetimePattern.value };
|
||||
}
|
||||
|
||||
function loadFormatterDraft(formatter: ColumnFormatterConfig | undefined) {
|
||||
const draft = formatter ?? { kind: "datetime", unit: "auto" as const };
|
||||
const draft = formatter ?? { kind: "datetime", unit: "auto" as const, pattern: "YYYY-MM-DD HH:mm:ss" as const };
|
||||
formatterKind.value = draft.kind === "custom-ref" ? "custom-template" : draft.kind;
|
||||
if (draft.kind === "datetime") {
|
||||
formatterDateUnit.value = draft.unit;
|
||||
formatterDatetimePattern.value = draft.pattern;
|
||||
} else if (draft.kind === "json-path") {
|
||||
formatterJsonPath.value = draft.path;
|
||||
} else if (draft.kind === "mask") {
|
||||
@@ -8116,7 +8119,7 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
|
||||
<Code2 class="h-3.5 w-3.5" />
|
||||
</button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="start" side="bottom" class="w-[380px] max-w-[calc(100vw-2rem)] gap-0 overflow-hidden rounded-xl border bg-popover p-0 text-popover-foreground shadow-xl" @click.stop @keydown.stop>
|
||||
<PopoverContent align="start" side="bottom" class="w-[420px] max-w-[calc(100vw-2rem)] gap-0 overflow-hidden rounded-xl border bg-popover p-0 text-popover-foreground shadow-xl" @click.stop @keydown.stop>
|
||||
<div class="border-b bg-muted/40 px-3 py-2">
|
||||
<div class="text-sm font-semibold">
|
||||
{{ t("grid.columnFormatterFor", { column: col.name }) }}
|
||||
@@ -8143,20 +8146,40 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div v-if="formatterKind === 'datetime'" class="space-y-1.5">
|
||||
<div class="text-xs font-medium text-muted-foreground">
|
||||
{{ t("grid.formatterTimestampUnit") }}
|
||||
<div v-if="formatterKind === 'datetime'" class="flex gap-2">
|
||||
<div class="space-y-1.5">
|
||||
<div class="text-xs font-medium text-muted-foreground">
|
||||
{{ t("grid.formatterTimestampUnit") }}
|
||||
</div>
|
||||
<Select :model-value="formatterDateUnit" @update:model-value="(value: any) => (formatterDateUnit = value)">
|
||||
<SelectTrigger class="h-8 text-xs">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="auto">{{ t("grid.formatterUnitAuto") }}</SelectItem>
|
||||
<SelectItem value="seconds">{{ t("grid.formatterUnitSeconds") }}</SelectItem>
|
||||
<SelectItem value="milliseconds">{{ t("grid.formatterUnitMilliseconds") }}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div class="space-y-1.5 flex-1">
|
||||
<div class="text-xs font-medium text-muted-foreground">
|
||||
{{ t("grid.formatterDatetimePattern") }}
|
||||
</div>
|
||||
<SearchableSelect
|
||||
:model-value="formatterDatetimePattern"
|
||||
:options="DateTimePatterns"
|
||||
:placeholder="t('grid.formatterDatetimePatternPlaceholder')"
|
||||
:search-placeholder="t('grid.formatterDatetimePatternPlaceholder')"
|
||||
:empty-text="t('grid.formatterDatetimePatternEmpty')"
|
||||
:loading-text="t('common.loading')"
|
||||
:allow-custom="true"
|
||||
:trigger-class="['border border-input h-8 w-72 pl-2.5 text-xs']"
|
||||
content-class="w-72"
|
||||
item-class="h-auto min-h-8 px-2 py-1.5 text-xs"
|
||||
@update:model-value="(value: any) => (formatterDatetimePattern = value)"
|
||||
/>
|
||||
</div>
|
||||
<Select :model-value="formatterDateUnit" @update:model-value="(value: any) => (formatterDateUnit = value)">
|
||||
<SelectTrigger class="h-8 text-xs">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="auto">{{ t("grid.formatterUnitAuto") }}</SelectItem>
|
||||
<SelectItem value="seconds">{{ t("grid.formatterUnitSeconds") }}</SelectItem>
|
||||
<SelectItem value="milliseconds">{{ t("grid.formatterUnitMilliseconds") }}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div v-else-if="formatterKind === 'json-path'" class="space-y-1.5">
|
||||
|
||||
Reference in new issue
Block a user