fix: only refresh sidebar tree when table comment actually changed
Previously the sidebar tree refresh was skipped entirely in EDIT mode because the check was gated on activeTab.mode === 'data', which is never true when the structure editor is open. Now we pass a commentChanged flag through the event chain and only refresh the tree when the comment was modified.
This commit is contained in:
parent
29462937d3
commit
551339cd22
|
|
@ -925,13 +925,19 @@ onUnmounted(() => {
|
|||
"
|
||||
@object-schema-change="(schema) => activeTab && queryStore.updateSchema(activeTab.id, schema)"
|
||||
@structure-editor-saved="
|
||||
activeTab &&
|
||||
onStructureEditorSaved(onReloadData, toast, {
|
||||
connectionId: activeTab.connectionId,
|
||||
database: activeTab.database,
|
||||
schema: activeTab.schema,
|
||||
tableName: activeTab.structureTableName || '',
|
||||
})
|
||||
(commentChanged) =>
|
||||
activeTab &&
|
||||
onStructureEditorSaved(
|
||||
onReloadData,
|
||||
toast,
|
||||
{
|
||||
connectionId: activeTab.connectionId,
|
||||
database: activeTab.database,
|
||||
schema: activeTab.schema,
|
||||
tableName: activeTab.structureTableName || '',
|
||||
},
|
||||
commentChanged,
|
||||
)
|
||||
"
|
||||
@structure-editor-close="activeTab && queryStore.closeTab(activeTab.id)"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ const emit = defineEmits<{
|
|||
clickTable: [tableName: string];
|
||||
openObjectTable: [target: { tableName: string; schema?: string }];
|
||||
objectSchemaChange: [schema: string | undefined];
|
||||
structureEditorSaved: [];
|
||||
structureEditorSaved: [commentChanged: boolean];
|
||||
structureEditorClose: [];
|
||||
}>();
|
||||
|
||||
|
|
@ -690,7 +690,7 @@ defineExpose({ focusSearch, refreshData });
|
|||
:database="activeTab.database"
|
||||
:schema="activeTab.schema"
|
||||
:table-name="activeTab.structureTableName || ''"
|
||||
@saved="emit('structureEditorSaved')"
|
||||
@saved="(commentChanged) => emit('structureEditorSaved', commentChanged)"
|
||||
@close="emit('structureEditorClose')"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ const props = defineProps<{
|
|||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
saved: [];
|
||||
saved: [commentChanged: boolean];
|
||||
close: [];
|
||||
}>();
|
||||
|
||||
|
|
@ -140,6 +140,8 @@ const indexColLabels = computed(() => [
|
|||
const targetSchema = computed(() => props.schema || props.database || "");
|
||||
const isCreateMode = computed(() => !props.tableName);
|
||||
const newTableName = ref("");
|
||||
const tableComment = ref("");
|
||||
const originalTableComment = ref("");
|
||||
const targetLabel = computed(() =>
|
||||
buildStructureTargetLabel(
|
||||
connection.value?.name,
|
||||
|
|
@ -160,6 +162,8 @@ async function refreshSqlPreview() {
|
|||
tableName: isCreateMode.value ? newTableName.value : props.tableName || "",
|
||||
columns: columns.value,
|
||||
indexes: indexes.value,
|
||||
tableComment: tableComment.value,
|
||||
originalTableComment: isCreateMode.value ? undefined : originalTableComment.value,
|
||||
};
|
||||
try {
|
||||
const result = isCreateMode.value
|
||||
|
|
@ -201,6 +205,8 @@ function resetState() {
|
|||
foreignKeys.value = [];
|
||||
triggers.value = [];
|
||||
newTableName.value = "";
|
||||
tableComment.value = "";
|
||||
originalTableComment.value = "";
|
||||
}
|
||||
|
||||
async function loadStructure(silent = false) {
|
||||
|
|
@ -219,6 +225,16 @@ async function loadStructure(silent = false) {
|
|||
indexes.value = createIndexDrafts(nextIndexes);
|
||||
foreignKeys.value = nextForeignKeys;
|
||||
triggers.value = nextTriggers;
|
||||
try {
|
||||
const tables = await api.listTables(props.connectionId, props.database, targetSchema.value);
|
||||
const table = tables.find(
|
||||
(t) => t.name.toLowerCase() === props.tableName!.toLowerCase() && t.table_type !== "VIEW",
|
||||
);
|
||||
originalTableComment.value = table?.comment || "";
|
||||
tableComment.value = table?.comment || "";
|
||||
} catch {
|
||||
/* ignore — table comment is optional */
|
||||
}
|
||||
} catch (e: any) {
|
||||
errorMessage.value = e?.message || String(e);
|
||||
} finally {
|
||||
|
|
@ -385,7 +401,7 @@ async function applyChanges() {
|
|||
try {
|
||||
await api.executeBatch(props.connectionId, props.database, pendingStatements.value);
|
||||
toast(t("structureEditor.saved"), 2500);
|
||||
emit("saved");
|
||||
emit("saved", tableComment.value !== originalTableComment.value);
|
||||
if (isCreateMode.value) {
|
||||
emit("close");
|
||||
} else {
|
||||
|
|
@ -404,7 +420,7 @@ onMounted(() => {
|
|||
});
|
||||
|
||||
watch(
|
||||
[isCreateMode, databaseType, () => props.schema, () => props.tableName, newTableName, columns, indexes],
|
||||
[isCreateMode, databaseType, () => props.schema, () => props.tableName, newTableName, tableComment, columns, indexes],
|
||||
() => {
|
||||
void refreshSqlPreview();
|
||||
},
|
||||
|
|
@ -444,6 +460,15 @@ watch(
|
|||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex shrink-0 items-center gap-2">
|
||||
<label class="shrink-0 text-[11px] font-medium text-muted-foreground">{{ t("structureEditor.comment") }}</label>
|
||||
<Input
|
||||
v-model="tableComment"
|
||||
:placeholder="t('structureEditor.commentPlaceholder')"
|
||||
class="h-6 max-w-[320px] text-[11px]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="loading" class="flex min-h-0 flex-1 items-center justify-center gap-2 text-sm text-muted-foreground">
|
||||
<Loader2 class="h-4 w-4 animate-spin" />
|
||||
{{ t("common.loading") }}
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ export function useNavigationTargets(dialogs: {
|
|||
reloadData: () => Promise<void>,
|
||||
toast: (msg: string, duration?: number) => void,
|
||||
context: { connectionId: string; database: string; schema?: string; tableName: string },
|
||||
commentChanged?: boolean,
|
||||
) {
|
||||
if (!context.tableName) {
|
||||
try {
|
||||
|
|
@ -134,6 +135,15 @@ export function useNavigationTargets(dialogs: {
|
|||
} catch {}
|
||||
return;
|
||||
}
|
||||
if (commentChanged) {
|
||||
try {
|
||||
await connectionStore.refreshObjectListTreeNode(
|
||||
context.connectionId,
|
||||
context.database,
|
||||
context.schema || undefined,
|
||||
);
|
||||
} catch {}
|
||||
}
|
||||
const activeTab = queryStore.tabs.find((t) => t.id === queryStore.activeTabId);
|
||||
if (activeTab?.mode === "data" && activeTab.tableMeta?.tableName === context.tableName) {
|
||||
try {
|
||||
|
|
@ -148,11 +158,6 @@ export function useNavigationTargets(dialogs: {
|
|||
columns,
|
||||
primaryKeys: editablePrimaryKeys(connectionStore.getConfig(activeTab.connectionId)?.db_type, columns),
|
||||
});
|
||||
await connectionStore.refreshObjectListTreeNode(
|
||||
activeTab.connectionId,
|
||||
activeTab.database,
|
||||
activeTab.tableMeta.schema,
|
||||
);
|
||||
await reloadData();
|
||||
} catch (e: any) {
|
||||
toast(e?.message || String(e), 5000);
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ export interface BuildTableStructureChangeSqlOptions {
|
|||
tableName: string;
|
||||
columns: EditableStructureColumn[];
|
||||
indexes: EditableStructureIndex[];
|
||||
tableComment?: string;
|
||||
originalTableComment?: string;
|
||||
}
|
||||
|
||||
export interface TableStructureChangeSql {
|
||||
|
|
|
|||
|
|
@ -93,6 +93,10 @@ pub struct TableStructureSqlOptions {
|
|||
pub columns: Vec<EditableStructureColumn>,
|
||||
#[serde(default)]
|
||||
pub indexes: Vec<EditableStructureIndex>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub table_comment: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub original_table_comment: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
|
|
@ -291,9 +295,43 @@ pub fn build_table_structure_change_sql(options: TableStructureSqlOptions) -> Ta
|
|||
let mut warnings = validate_draft(&options);
|
||||
let mut statements = build_column_sql(&options, &mut warnings);
|
||||
statements.extend(build_index_sql(&options, &mut warnings));
|
||||
statements.extend(build_table_comment_sql(&options, &mut warnings));
|
||||
TableStructureSqlResult { statements, warnings }
|
||||
}
|
||||
|
||||
fn build_table_comment_sql(options: &TableStructureSqlOptions, warnings: &mut Vec<String>) -> Vec<String> {
|
||||
let capabilities = capabilities_for(options.database_type);
|
||||
if !capabilities.comment {
|
||||
return Vec::new();
|
||||
}
|
||||
let new_comment = options.table_comment.as_deref().unwrap_or("");
|
||||
let original_comment = options.original_table_comment.as_deref().unwrap_or("");
|
||||
if clean(new_comment) == clean(original_comment) {
|
||||
return Vec::new();
|
||||
}
|
||||
let dialect = capabilities.dialect;
|
||||
let table = qualified_table(dialect, options.schema.as_deref(), &options.table_name);
|
||||
let quoted = quote_string(&clean(new_comment));
|
||||
match dialect {
|
||||
StructureDialect::Mysql => {
|
||||
vec![format!("ALTER TABLE {table} COMMENT = {quoted};")]
|
||||
}
|
||||
StructureDialect::Postgres | StructureDialect::Oracle | StructureDialect::H2 => {
|
||||
vec![format!("COMMENT ON TABLE {table} IS {quoted};")]
|
||||
}
|
||||
StructureDialect::ClickHouse => {
|
||||
vec![format!("ALTER TABLE {table} MODIFY COMMENT {quoted};")]
|
||||
}
|
||||
StructureDialect::SqlServer | StructureDialect::Sqlite | StructureDialect::DuckDb | _ => {
|
||||
if !clean(new_comment).is_empty() {
|
||||
warnings
|
||||
.push(format!("Table comments are not supported for {} from this editor.", dialect_label(dialect)));
|
||||
}
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_create_table_sql(options: TableStructureSqlOptions) -> TableStructureSqlResult {
|
||||
let mut warnings = Vec::new();
|
||||
if clean(&options.table_name).is_empty() {
|
||||
|
|
@ -338,6 +376,21 @@ pub fn build_create_table_sql(options: TableStructureSqlOptions) -> TableStructu
|
|||
|
||||
statements.push(format!("CREATE TABLE {table} (\n {}\n);", column_definitions.join(",\n ")));
|
||||
|
||||
if capabilities.comment {
|
||||
let table_comment = clean(options.table_comment.as_deref().unwrap_or(""));
|
||||
if !table_comment.is_empty() {
|
||||
if dialect == StructureDialect::Mysql {
|
||||
if let Some(last) = statements.last_mut() {
|
||||
*last = last.replace(");", &format!(") COMMENT = {};", quote_string(&table_comment)));
|
||||
}
|
||||
} else if matches!(dialect, StructureDialect::Postgres | StructureDialect::Oracle | StructureDialect::H2) {
|
||||
statements.push(format!("COMMENT ON TABLE {table} IS {};", quote_string(&table_comment)));
|
||||
} else if dialect == StructureDialect::ClickHouse {
|
||||
statements.push(format!("ALTER TABLE {table} MODIFY COMMENT {};", quote_string(&table_comment)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if capabilities.comment
|
||||
&& matches!(dialect, StructureDialect::Postgres | StructureDialect::Oracle | StructureDialect::H2)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue