fix(mysql): edit enum column values

This commit is contained in:
t8y2 committed 2026-07-10 16:10:54 +08:00
1 parent ea8b3f9800
commit 8c7e34a6de
14 files changed
+283 -54

No files matched your search

+29 -6
View File
@@ -90,7 +90,7 @@ import { createColumnDrafts } from "@/lib/table/tableStructureEditorState";
import type { BuildSingleColumnAlterSqlOptions } from "@/lib/table/tableStructureEditorSql";
import { buildTableSelectSql, quoteTableIdentifier } from "@/lib/table/tableSelectSql";
import { uuid } from "@/lib/common/utils";
import { resolveHeaderColumnType } from "@/lib/dataGrid/dataGridColumnType";
import { compactHeaderColumnType, resolveHeaderColumnType } from "@/lib/dataGrid/dataGridColumnType";
import { canEditExistingTableRows, canInsertTableRows, canUseKeylessRowPredicate, hiveTablePropertiesIndicateTransactional, isClickHouseExistingRowReadonlyColumn, isHiddenGridColumn, isTdengineExistingRowReadonlyColumn, usesSyntheticRowIdKey } from "@/lib/table/tableEditing";
import { buildDataGridColumnDistinctValuesSql, buildDataGridContextFilterCondition, buildDataGridCountSql, buildHiveTablePropertiesSql, type DataGridContextFilterMode } from "@/lib/dataGrid/dataGridSql";
import {
@@ -379,7 +379,7 @@ function headerColumnType(column: string, actualColIdx: number): string {
resultColumnTypes: props.result.column_types,
actualColIdx,
});
return resolved ? shortTypeName(resolved) : "";
return resolved ? shortTypeName(compactHeaderColumnType(resolved)) : "";
}
function shortTypeName(t: string): string {
@@ -4124,6 +4124,11 @@ function isEnumGridColumnNullable(columnIndex: number): boolean {
return tableColumnForGridColumn(columnIndex)?.is_nullable ?? false;
}
function isEnumEditorInitialNull(rowId: number | undefined, columnIndex: number): boolean {
if (rowId === undefined) return false;
return getRowItem(rowId)?.data[columnIndex] === null;
}
function cellEditInputModeForColumn(columnIndex: number): "decimal" | "numeric" | undefined {
const dataType = normalizedColumnDataType(tableColumnForGridColumn(columnIndex));
if (isIntegerColumnType(dataType)) return "numeric";
@@ -6752,8 +6757,8 @@ function deleteCurrentRow(): boolean {
return true;
}
function commitGridEdit() {
void commitEditAndMaybeAutoSave().finally(() => nextTick(() => gridRef.value?.focus({ preventScroll: true })));
function commitGridEdit(value?: string | null) {
void commitEditAndMaybeAutoSave(value === undefined ? undefined : { explicitValue: value }).finally(() => nextTick(() => gridRef.value?.focus({ preventScroll: true })));
}
async function commitEditFromCellBlur() {
@@ -9257,7 +9262,16 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
@cancel="cancelEdit"
@commit="commitGridEdit"
/>
<EnumCellEditor v-else-if="isEnumGridColumn(cell.valueIndex)" v-model="editValue" :values="enumValuesForGridColumn(cell.valueIndex)" :nullable="isEnumGridColumnNullable(cell.valueIndex)" cell-layout="transpose" @cancel="cancelEdit" @commit="commitGridEdit" />
<EnumCellEditor
v-else-if="isEnumGridColumn(cell.valueIndex)"
v-model="editValue"
:values="enumValuesForGridColumn(cell.valueIndex)"
:nullable="isEnumGridColumnNullable(cell.valueIndex)"
:initial-null="isEnumEditorInitialNull(displayItems[cell.recordIndex]?.id, cell.valueIndex)"
cell-layout="transpose"
@cancel="cancelEdit"
@commit="commitGridEdit"
/>
<textarea
v-else-if="cellUsesExpandedEditor(displayItems[cell.recordIndex]?.id, cell.valueIndex)"
v-model="editValue"
@@ -9744,6 +9758,7 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
v-model="editValue"
:values="enumValuesForGridColumn(canvasEditingCell.actualColIdx)"
:nullable="isEnumGridColumnNullable(canvasEditingCell.actualColIdx)"
:initial-null="isEnumEditorInitialNull(canvasEditingCell.rowId, canvasEditingCell.actualColIdx)"
@cancel="cancelEdit"
@commit="commitGridEdit"
/>
@@ -9889,7 +9904,15 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
@cancel="cancelEdit"
@commit="commitGridEdit"
/>
<EnumCellEditor v-else-if="isEnumGridColumn(col.actualColIdx)" v-model="editValue" :values="enumValuesForGridColumn(col.actualColIdx)" :nullable="isEnumGridColumnNullable(col.actualColIdx)" @cancel="cancelEdit" @commit="commitGridEdit" />
<EnumCellEditor
v-else-if="isEnumGridColumn(col.actualColIdx)"
v-model="editValue"
:values="enumValuesForGridColumn(col.actualColIdx)"
:nullable="isEnumGridColumnNullable(col.actualColIdx)"
:initial-null="isEnumEditorInitialNull(item.id, col.actualColIdx)"
@cancel="cancelEdit"
@commit="commitGridEdit"
/>
<textarea
v-else-if="cellUsesExpandedEditor(item.id, col.actualColIdx)"
v-model="editValue"
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { computed, nextTick, onMounted, ref } from "vue";
import { useI18n } from "vue-i18n";
import type { FocusOutsideEvent, PointerDownOutsideEvent } from "reka-ui";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
@@ -8,40 +9,47 @@ const props = withDefaults(
modelValue: string;
values: string[];
nullable?: boolean;
initialNull?: boolean;
cellLayout?: "grid" | "transpose";
}>(),
{
nullable: false,
initialNull: false,
cellLayout: "grid",
},
);
const emit = defineEmits<{
"update:modelValue": [value: string];
commit: [];
commit: [value?: string | null];
cancel: [];
}>();
const { t } = useI18n();
const open = ref(true);
const triggerRef = ref<HTMLButtonElement | null>(null);
let closeHandled = false;
const triggerClass = computed(() => ["cell-edit-input absolute inset-0 z-10 flex items-center gap-1 border-2 border-primary bg-background py-0 text-left text-xs outline-none", props.cellLayout === "transpose" ? "px-1.5" : "px-2.5"].join(" "));
const displayValue = computed(() => props.modelValue || "(NULL)");
const displayValue = computed(() => {
if (props.initialNull && props.modelValue === "") return t("grid.nullValue");
return props.modelValue === "" ? "''" : props.modelValue;
});
onMounted(() => {
nextTick(() => triggerRef.value?.focus());
});
function selectValue(value: string) {
emit("update:modelValue", value);
finishCommit();
function selectValue(value: string | null) {
if (value !== null) emit("update:modelValue", value);
finishCommit(value);
}
function finishCommit() {
function finishCommit(value?: string | null) {
closeHandled = true;
emit("commit");
emit("commit", value);
}
function finishCancel() {
@@ -87,9 +95,22 @@ function onPopoverInteractOutside(event: PointerDownOutsideEvent | FocusOutsideE
</PopoverTrigger>
<PopoverContent align="start" side="bottom" class="w-auto min-w-[120px] rounded-md p-1" @click.stop @keydown.stop="onKeydown" @interact-outside="onPopoverInteractOutside">
<div class="flex flex-col gap-0.5">
<button v-if="nullable" type="button" class="flex items-center rounded-sm px-2 py-1 text-xs text-muted-foreground hover:bg-accent hover:text-accent-foreground" :class="{ 'bg-accent text-accent-foreground': modelValue === '' }" @click="selectValue('')">(NULL)</button>
<button v-for="val in values" :key="val" type="button" class="flex items-center rounded-sm px-2 py-1 text-xs hover:bg-accent hover:text-accent-foreground" :class="{ 'bg-accent text-accent-foreground': modelValue === val }" @click="selectValue(val)">
{{ val }}
<button v-if="nullable" type="button" class="flex min-h-7 w-full items-center rounded-sm px-2 py-1 text-left text-xs italic text-muted-foreground hover:bg-accent hover:text-accent-foreground" :class="{ 'bg-accent text-accent-foreground': initialNull }" @click="selectValue(null)">
{{ t("grid.nullValue") }}
</button>
<button
v-for="val in values"
:key="val"
type="button"
class="flex min-h-7 w-full items-center rounded-sm px-2 py-1 text-left text-xs hover:bg-accent hover:text-accent-foreground"
:class="{ 'bg-accent text-accent-foreground': modelValue === val && !(initialNull && val === '') }"
@click="selectValue(val)"
>
<template v-if="val === ''">
<code>''</code>
<span class="ml-2 text-muted-foreground">{{ t("grid.emptyStringValue") }}</span>
</template>
<template v-else>{{ val }}</template>
</button>
</div>
</PopoverContent>