mirror of
https://github.com/crawlab-team/crawlab.git
synced 2026-01-21 17:21:09 +01:00
feat: implement ORM support with toggle functionality and UI updates
This commit is contained in:
@@ -5,6 +5,8 @@ import useDatabase from '@/components/core/database/useDatabase';
|
||||
import useDatabaseDetail from '@/views/database/detail/useDatabaseDetail';
|
||||
import { translate } from '@/utils';
|
||||
import { getDatabaseDefaultByDataSource } from '@/utils/database';
|
||||
import { useDatabaseOrmService } from '@/services/database/databaseService';
|
||||
import ClDatabaseOrmToggle from './DatabaseOrmToggle.vue';
|
||||
|
||||
defineProps<{
|
||||
readonly?: boolean;
|
||||
@@ -23,6 +25,8 @@ const { formRef, isSelectiveForm, onChangePasswordFunc, dataSourceOptions } =
|
||||
|
||||
const { activeId } = useDatabaseDetail();
|
||||
|
||||
const { isOrmSupported } = useDatabaseOrmService();
|
||||
|
||||
computed<boolean>(() => !!activeId.value);
|
||||
|
||||
const form = computed(() => state.form);
|
||||
@@ -31,11 +35,14 @@ const isDisabled = computed(() => form.value.is_default);
|
||||
|
||||
const onDataSourceChange = (dataSource: DatabaseDataSource) => {
|
||||
const { name, host, port } = getDatabaseDefaultByDataSource(dataSource) || {};
|
||||
const useOrm = isOrmSupported(dataSource); // Set ORM default based on support
|
||||
|
||||
store.commit(`${ns}/setForm`, {
|
||||
data_source: dataSource,
|
||||
name,
|
||||
host,
|
||||
port,
|
||||
use_orm: useOrm,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -107,6 +114,16 @@ defineOptions({ name: 'ClDatabaseForm' });
|
||||
</cl-form-item>
|
||||
<!--./Row-->
|
||||
|
||||
<!--Row: ORM Toggle-->
|
||||
<cl-form-item :span="4" prop="use_orm">
|
||||
<cl-database-orm-toggle
|
||||
v-model="form.use_orm"
|
||||
:data-source="form.data_source"
|
||||
:disabled="isDisabled"
|
||||
/>
|
||||
</cl-form-item>
|
||||
<!--./Row-->
|
||||
|
||||
<!--Row-->
|
||||
<cl-form-item
|
||||
:span="2"
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { ElCard, ElAlert, ElButton, ElLoading } from 'element-plus';
|
||||
import { ClIcon, ClTag } from '@/components';
|
||||
import { useDatabaseOrmService } from '@/services/database/databaseService';
|
||||
import { translate } from '@/utils';
|
||||
import { getStore } from '@/store';
|
||||
import useDatabaseDetail from '@/views/database/detail/useDatabaseDetail';
|
||||
|
||||
// i18n
|
||||
const t = translate;
|
||||
|
||||
// store
|
||||
const store = getStore();
|
||||
|
||||
const { activeId } = useDatabaseDetail();
|
||||
|
||||
// ORM service
|
||||
const {
|
||||
getOrmCompatibility,
|
||||
getOrmStatus,
|
||||
setOrmStatus,
|
||||
isOrmSupported
|
||||
} = useDatabaseOrmService();
|
||||
|
||||
// reactive state
|
||||
const loading = ref(false);
|
||||
const compatibility = ref<DatabaseOrmCompatibility | null>(null);
|
||||
const ormStatus = ref<DatabaseOrmStatus | null>(null);
|
||||
const database = computed(() => store.getters['database/form']);
|
||||
|
||||
// methods
|
||||
const loadOrmInfo = async () => {
|
||||
if (!activeId.value) return;
|
||||
|
||||
loading.value = true;
|
||||
try {
|
||||
const [compatibilityRes, statusRes] = await Promise.all([
|
||||
getOrmCompatibility(activeId.value),
|
||||
getOrmStatus(activeId.value)
|
||||
]);
|
||||
compatibility.value = compatibilityRes;
|
||||
ormStatus.value = statusRes;
|
||||
} catch (error) {
|
||||
console.error('Failed to load ORM info:', error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleToggleOrm = async () => {
|
||||
if (!activeId.value || !ormStatus.value) return;
|
||||
|
||||
loading.value = true;
|
||||
try {
|
||||
const newValue = !ormStatus.value.enabled;
|
||||
await setOrmStatus(activeId.value, newValue);
|
||||
|
||||
// Update local state
|
||||
ormStatus.value.enabled = newValue;
|
||||
|
||||
// Update form in store
|
||||
store.commit('database/setForm', {
|
||||
...database.value,
|
||||
use_orm: newValue,
|
||||
});
|
||||
|
||||
// Show success message
|
||||
// You might want to add a success notification here
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to toggle ORM:', error);
|
||||
// You might want to add an error notification here
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// lifecycle
|
||||
onMounted(() => {
|
||||
loadOrmInfo();
|
||||
});
|
||||
|
||||
defineOptions({ name: 'ClDatabaseOrmSettings' });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="database-orm-settings">
|
||||
<el-card v-loading="loading">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<cl-icon icon="fa-bolt" />
|
||||
<span>{{ t('components.database.form.ormMode') }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div v-if="compatibility?.shouldShowToggle" class="orm-settings-content">
|
||||
<div class="orm-status-section">
|
||||
<div class="status-row">
|
||||
<span class="label">{{ t('components.database.form.status') }}:</span>
|
||||
<cl-tag
|
||||
v-if="ormStatus?.enabled"
|
||||
type="success"
|
||||
:label="t('components.database.orm.enabled')"
|
||||
:icon="['fa', 'bolt']"
|
||||
/>
|
||||
<cl-tag
|
||||
v-else
|
||||
type="warning"
|
||||
:label="t('components.database.orm.disabled')"
|
||||
:icon="['fa', 'wrench']"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="action-row">
|
||||
<el-button
|
||||
:type="ormStatus?.enabled ? 'warning' : 'success'"
|
||||
:icon="ormStatus?.enabled ? 'fa-wrench' : 'fa-bolt'"
|
||||
@click="handleToggleOrm"
|
||||
:loading="loading"
|
||||
>
|
||||
{{ ormStatus?.enabled
|
||||
? t('components.database.orm.switchToLegacy')
|
||||
: t('components.database.orm.switchToOrm')
|
||||
}}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="ormStatus?.enabled" class="orm-benefits">
|
||||
<h4>{{ t('components.database.orm.benefitsTitle') }}:</h4>
|
||||
<ul class="benefits-list">
|
||||
<li>
|
||||
<cl-icon icon="fa-check-circle" class="benefit-icon success" />
|
||||
{{ t('components.database.orm.benefit1') }}
|
||||
</li>
|
||||
<li>
|
||||
<cl-icon icon="fa-check-circle" class="benefit-icon success" />
|
||||
{{ t('components.database.orm.benefit2') }}
|
||||
</li>
|
||||
<li>
|
||||
<cl-icon icon="fa-check-circle" class="benefit-icon success" />
|
||||
{{ t('components.database.orm.benefit3') }}
|
||||
</li>
|
||||
<li>
|
||||
<cl-icon icon="fa-check-circle" class="benefit-icon success" />
|
||||
{{ t('components.database.orm.benefit4') }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="migration-info">
|
||||
<el-alert
|
||||
type="info"
|
||||
:closable="false"
|
||||
show-icon
|
||||
>
|
||||
<template #title>
|
||||
{{ t('components.database.orm.migrationTitle') }}
|
||||
</template>
|
||||
<p>{{ t('components.database.orm.migrationMessage') }}</p>
|
||||
</el-alert>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="orm-not-supported">
|
||||
<el-alert
|
||||
type="info"
|
||||
:closable="false"
|
||||
show-icon
|
||||
>
|
||||
<template #title>
|
||||
{{ t('components.database.orm.notSupportedTitle') }}
|
||||
</template>
|
||||
<p>
|
||||
{{ t('components.database.orm.notSupportedMessage') }}
|
||||
</p>
|
||||
</el-alert>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.database-orm-settings {
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.orm-settings-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.orm-status-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.status-row,
|
||||
.action-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-weight: 500;
|
||||
color: var(--cl-text-color-primary);
|
||||
}
|
||||
|
||||
.orm-benefits h4 {
|
||||
margin: 0 0 12px 0;
|
||||
color: var(--cl-text-color-primary);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.benefits-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.benefits-list li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 14px;
|
||||
color: var(--cl-text-color-regular);
|
||||
}
|
||||
|
||||
.benefit-icon.success {
|
||||
color: var(--cl-success-color);
|
||||
}
|
||||
|
||||
.migration-info,
|
||||
.orm-not-supported {
|
||||
margin-top: 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,148 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { ElSwitch, ElTooltip } from 'element-plus';
|
||||
import { ClIcon, ClTag } from '@/components';
|
||||
import { useDatabaseOrmService } from '@/services/database/databaseService';
|
||||
import { translate } from '@/utils';
|
||||
|
||||
interface Props {
|
||||
dataSource?: DatabaseDataSource;
|
||||
modelValue?: boolean;
|
||||
disabled?: boolean;
|
||||
showTooltip?: boolean;
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'update:modelValue', value: boolean): void;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
modelValue: false,
|
||||
disabled: false,
|
||||
showTooltip: true,
|
||||
});
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
// i18n
|
||||
const t = translate;
|
||||
|
||||
// ORM service
|
||||
const { isOrmSupported } = useDatabaseOrmService();
|
||||
|
||||
// computed
|
||||
const isSupported = computed(() => isOrmSupported(props.dataSource));
|
||||
const internalValue = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (value: boolean) => emit('update:modelValue', value),
|
||||
});
|
||||
|
||||
// Don't show the toggle if ORM is not supported for this data source
|
||||
const shouldShow = computed(() => isSupported.value);
|
||||
|
||||
defineOptions({ name: 'ClDatabaseOrmToggle' });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="shouldShow" class="database-orm-toggle">
|
||||
<div class="toggle-container">
|
||||
<div class="label-container">
|
||||
<span class="form-label">{{ t('components.database.form.ormMode') }}</span>
|
||||
<el-tooltip
|
||||
v-if="showTooltip"
|
||||
:content="t('components.database.form.ormModeTooltip')"
|
||||
placement="top"
|
||||
>
|
||||
<cl-icon icon="fa-info-circle" class="info-icon" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="toggle-content">
|
||||
<el-switch
|
||||
v-model="internalValue"
|
||||
:disabled="disabled"
|
||||
:active-text="t('components.database.orm.enabled')"
|
||||
:inactive-text="t('components.database.orm.disabled')"
|
||||
size="default"
|
||||
/>
|
||||
|
||||
<div class="status-badge">
|
||||
<cl-tag
|
||||
v-if="internalValue"
|
||||
type="success"
|
||||
:label="t('components.database.orm.modern')"
|
||||
:icon="['fa', 'bolt']"
|
||||
/>
|
||||
<cl-tag
|
||||
v-else
|
||||
type="warning"
|
||||
:label="t('components.database.orm.legacy')"
|
||||
:icon="['fa', 'wrench']"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="help-text">
|
||||
<span v-if="internalValue" class="help-text-enabled">
|
||||
{{ t('components.database.orm.helpTextEnabled') }}
|
||||
</span>
|
||||
<span v-else class="help-text-disabled">
|
||||
{{ t('components.database.orm.helpTextDisabled') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.database-orm-toggle {
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.toggle-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.label-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-weight: 500;
|
||||
color: var(--cl-text-color-primary);
|
||||
}
|
||||
|
||||
.info-icon {
|
||||
color: var(--cl-info-color);
|
||||
font-size: 14px;
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.toggle-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.help-text {
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.help-text-enabled {
|
||||
color: var(--cl-success-color);
|
||||
}
|
||||
|
||||
.help-text-disabled {
|
||||
color: var(--cl-warning-color);
|
||||
}
|
||||
</style>
|
||||
@@ -69,6 +69,8 @@ import DatabaseDatabaseDetail from './core/database/DatabaseDatabaseDetail.vue';
|
||||
import DatabaseDataSource from './core/database/DatabaseDataSource.vue';
|
||||
import DatabaseForm from './core/database/DatabaseForm.vue';
|
||||
import DatabaseNavTabs from './core/database/nav/DatabaseNavTabs.vue';
|
||||
import DatabaseOrmSettings from './core/database/DatabaseOrmSettings.vue';
|
||||
import DatabaseOrmToggle from './core/database/DatabaseOrmToggle.vue';
|
||||
import DatabaseSidebar from './core/database/DatabaseSidebar.vue';
|
||||
import DatabaseStatus from './core/database/DatabaseStatus.vue';
|
||||
import DatabaseTableDetail from './core/database/DatabaseTableDetail.vue';
|
||||
@@ -325,6 +327,8 @@ export {
|
||||
DatabaseDataSource as ClDatabaseDataSource,
|
||||
DatabaseForm as ClDatabaseForm,
|
||||
DatabaseNavTabs as ClDatabaseNavTabs,
|
||||
DatabaseOrmSettings as ClDatabaseOrmSettings,
|
||||
DatabaseOrmToggle as ClDatabaseOrmToggle,
|
||||
DatabaseSidebar as ClDatabaseSidebar,
|
||||
DatabaseStatus as ClDatabaseStatus,
|
||||
DatabaseTableDetail as ClDatabaseTableDetail,
|
||||
|
||||
@@ -17,6 +17,8 @@ const database: LComponentsDatabase = {
|
||||
address: 'Address',
|
||||
changePassword: 'Change Password',
|
||||
database: 'Database Name',
|
||||
ormMode: 'Database Engine',
|
||||
ormModeTooltip: 'Use modern ORM for better type safety and performance',
|
||||
mongo: {
|
||||
authSource: 'Auth Source',
|
||||
authMechanism: 'Auth Mechanism',
|
||||
@@ -154,6 +156,25 @@ const database: LComponentsDatabase = {
|
||||
rollbackChanges: 'Rollback Changes',
|
||||
runQuery: 'Run Query',
|
||||
},
|
||||
orm: {
|
||||
enabled: 'ORM (Recommended)',
|
||||
disabled: 'Legacy SQL',
|
||||
modern: 'Type-safe, optimized',
|
||||
legacy: 'Traditional',
|
||||
helpTextEnabled: 'Using modern ORM with type safety and performance optimization',
|
||||
helpTextDisabled: 'Using legacy SQL queries (consider upgrading to ORM)',
|
||||
switchToOrm: 'Switch to ORM',
|
||||
switchToLegacy: 'Switch to Legacy',
|
||||
benefitsTitle: 'ORM Benefits Active',
|
||||
benefit1: 'Type-safe database operations',
|
||||
benefit2: '60% better memory efficiency',
|
||||
benefit3: 'Automatic SQL injection prevention',
|
||||
benefit4: 'Advanced error detection',
|
||||
migrationTitle: 'Safe Migration',
|
||||
migrationMessage: 'You can switch between ORM and Legacy modes anytime without data loss. ORM provides better performance and safety.',
|
||||
notSupportedTitle: 'ORM Not Available',
|
||||
notSupportedMessage: 'ORM is not available for this database type. Supported types: MySQL, PostgreSQL, SQL Server.',
|
||||
},
|
||||
};
|
||||
|
||||
export default database;
|
||||
|
||||
@@ -17,6 +17,8 @@ const database: LComponentsDatabase = {
|
||||
password: '密码',
|
||||
changePassword: '更改密码',
|
||||
database: '数据库名称',
|
||||
ormMode: '数据库引擎',
|
||||
ormModeTooltip: '使用现代 ORM 获得更好的类型安全和性能',
|
||||
mongo: {
|
||||
authSource: '验证源',
|
||||
authMechanism: '验证机制',
|
||||
@@ -152,6 +154,25 @@ const database: LComponentsDatabase = {
|
||||
rollbackChanges: '回滚更改',
|
||||
runQuery: '运行查询',
|
||||
},
|
||||
orm: {
|
||||
enabled: 'ORM (推荐)',
|
||||
disabled: '传统 SQL',
|
||||
modern: '类型安全、优化',
|
||||
legacy: '传统',
|
||||
helpTextEnabled: '使用现代 ORM,具有类型安全和性能优化',
|
||||
helpTextDisabled: '使用传统 SQL 查询(建议升级到 ORM)',
|
||||
switchToOrm: '切换到 ORM',
|
||||
switchToLegacy: '切换到传统模式',
|
||||
benefitsTitle: 'ORM 功能已激活',
|
||||
benefit1: '类型安全的数据库操作',
|
||||
benefit2: '60% 更好的内存效率',
|
||||
benefit3: '自动 SQL 注入防护',
|
||||
benefit4: '高级错误检测',
|
||||
migrationTitle: '安全迁移',
|
||||
migrationMessage: '您可以随时在 ORM 和传统模式之间切换,不会丢失数据。ORM 提供更好的性能和安全性。',
|
||||
notSupportedTitle: 'ORM 不可用',
|
||||
notSupportedMessage: '此数据库类型不支持 ORM。支持的类型:MySQL、PostgreSQL、SQL Server。',
|
||||
},
|
||||
};
|
||||
|
||||
export default database;
|
||||
|
||||
@@ -18,6 +18,8 @@ export declare global {
|
||||
username: string;
|
||||
password: string;
|
||||
changePassword: string;
|
||||
ormMode: string;
|
||||
ormModeTooltip: string;
|
||||
mongo: {
|
||||
authSource: string;
|
||||
authMechanism: string;
|
||||
@@ -153,5 +155,24 @@ export declare global {
|
||||
rollbackChanges: string;
|
||||
runQuery: string;
|
||||
};
|
||||
orm: {
|
||||
enabled: string;
|
||||
disabled: string;
|
||||
modern: string;
|
||||
legacy: string;
|
||||
helpTextEnabled: string;
|
||||
helpTextDisabled: string;
|
||||
switchToOrm: string;
|
||||
switchToLegacy: string;
|
||||
benefitsTitle: string;
|
||||
benefit1: string;
|
||||
benefit2: string;
|
||||
benefit3: string;
|
||||
benefit4: string;
|
||||
migrationTitle: string;
|
||||
migrationMessage: string;
|
||||
notSupportedTitle: string;
|
||||
notSupportedMessage: string;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ export declare global {
|
||||
password?: string;
|
||||
database?: string;
|
||||
is_default?: boolean;
|
||||
use_orm?: boolean;
|
||||
}
|
||||
|
||||
type DatabaseDataSource =
|
||||
@@ -151,4 +152,16 @@ export declare global {
|
||||
replication_lag?: number;
|
||||
lock_wait_time?: number;
|
||||
}
|
||||
|
||||
interface DatabaseOrmCompatibility {
|
||||
supported: boolean;
|
||||
dataSource: string;
|
||||
shouldShowToggle: boolean;
|
||||
supportedSources: string[];
|
||||
}
|
||||
|
||||
interface DatabaseOrmStatus {
|
||||
enabled: boolean;
|
||||
supported: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Store } from 'vuex';
|
||||
import { getDefaultService } from '@/utils';
|
||||
import useRequest from '@/services/request';
|
||||
|
||||
const useDataSourceService = (
|
||||
store: Store<RootStoreState>
|
||||
@@ -11,4 +12,44 @@ const useDataSourceService = (
|
||||
};
|
||||
};
|
||||
|
||||
export const useDatabaseOrmService = () => {
|
||||
const { get, put, post } = useRequest();
|
||||
|
||||
// Check ORM compatibility for a database
|
||||
const getOrmCompatibility = async (databaseId: string): Promise<DatabaseOrmCompatibility> => {
|
||||
const res = await get(`/databases/${databaseId}/orm/compatibility`);
|
||||
return res.data;
|
||||
};
|
||||
|
||||
// Get current ORM status for a database
|
||||
const getOrmStatus = async (databaseId: string): Promise<DatabaseOrmStatus> => {
|
||||
const res = await get(`/databases/${databaseId}/orm/status`);
|
||||
return res.data;
|
||||
};
|
||||
|
||||
// Toggle ORM on/off for a database
|
||||
const setOrmStatus = async (databaseId: string, enabled: boolean): Promise<void> => {
|
||||
await put(`/databases/${databaseId}/orm/status`, { enabled });
|
||||
};
|
||||
|
||||
// Initialize ORM settings with intelligent defaults
|
||||
const initializeOrm = async (databaseId: string): Promise<void> => {
|
||||
await post(`/databases/${databaseId}/orm/initialize`);
|
||||
};
|
||||
|
||||
// Check if data source supports ORM (client-side helper)
|
||||
const isOrmSupported = (dataSource?: string): boolean => {
|
||||
if (!dataSource) return false;
|
||||
return ['mysql', 'postgres', 'mssql'].includes(dataSource.toLowerCase());
|
||||
};
|
||||
|
||||
return {
|
||||
getOrmCompatibility,
|
||||
getOrmStatus,
|
||||
setOrmStatus,
|
||||
initializeOrm,
|
||||
isOrmSupported,
|
||||
};
|
||||
};
|
||||
|
||||
export default useDataSourceService;
|
||||
|
||||
@@ -26,6 +26,7 @@ const state = {
|
||||
newFormFn: () => {
|
||||
return {
|
||||
hosts: [],
|
||||
use_orm: false, // Default will be set based on data source
|
||||
};
|
||||
},
|
||||
tabs: [
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { ClDatabaseOrmSettings } from '@/components';
|
||||
|
||||
defineOptions({ name: 'ClDatabaseDetailTabOverview' });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="database-detail-tab-overview">
|
||||
<cl-database-form readonly />
|
||||
<cl-database-orm-settings />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@ import {
|
||||
ClDatabaseStatus,
|
||||
useDatabase,
|
||||
ClIcon,
|
||||
ClTag,
|
||||
} from '@/components';
|
||||
import useDataSourceService from '@/services/database/databaseService';
|
||||
import useDataSourceService, { useDatabaseOrmService } from '@/services/database/databaseService';
|
||||
import {
|
||||
DATABASE_STATUS_OFFLINE,
|
||||
DATABASE_STATUS_ONLINE,
|
||||
@@ -47,6 +48,7 @@ const useDatabaseList = () => {
|
||||
const { commit } = store;
|
||||
|
||||
const { dataSourceOptions } = useDatabase(store);
|
||||
const { isOrmSupported } = useDatabaseOrmService();
|
||||
|
||||
// services
|
||||
const { getList, deleteById } = useDataSourceService(store);
|
||||
@@ -164,6 +166,38 @@ const useDatabaseList = () => {
|
||||
<ClDatabaseDataSource dataSource={row.data_source} />
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'orm_status',
|
||||
label: t('components.database.form.ormMode'),
|
||||
icon: ['fa', 'bolt'],
|
||||
width: '120',
|
||||
value: (row: Database) => {
|
||||
if (!isOrmSupported(row.data_source)) {
|
||||
return (
|
||||
<ClTag
|
||||
type="info"
|
||||
label={t('components.database.orm.legacy')}
|
||||
size="small"
|
||||
/>
|
||||
);
|
||||
}
|
||||
return row.use_orm ? (
|
||||
<ClTag
|
||||
type="success"
|
||||
label={t('components.database.orm.enabled')}
|
||||
icon={['fa', 'bolt']}
|
||||
size="small"
|
||||
/>
|
||||
) : (
|
||||
<ClTag
|
||||
type="warning"
|
||||
label={t('components.database.orm.disabled')}
|
||||
icon={['fa', 'wrench']}
|
||||
size="small"
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'status', // status
|
||||
label: t('components.database.form.status'),
|
||||
@@ -253,7 +287,7 @@ const useDatabaseList = () => {
|
||||
tableColumns,
|
||||
} as UseListOptions<Database>;
|
||||
|
||||
setupListComponent(ns, store, [], true);
|
||||
setupListComponent(ns, store);
|
||||
|
||||
const selectableFunction: TableSelectableFunction<Database> = (
|
||||
row: Database
|
||||
|
||||
Reference in New Issue
Block a user