mirror of
https://github.com/crawlab-team/crawlab.git
synced 2026-01-21 17:21:09 +01:00
feat: enhance AutoProbeResultsContainer with dynamic cell styling and active field management
This commit is contained in:
@@ -3,6 +3,7 @@ import { computed, ref } from 'vue';
|
||||
import { ClTag } from '@/components';
|
||||
import { translate, getIconByItemType } from '@/utils';
|
||||
import { TAB_NAME_RESULTS, TAB_NAME_PREVIEW } from '@/constants';
|
||||
import { CellStyle } from 'element-plus';
|
||||
|
||||
const t = translate;
|
||||
|
||||
@@ -10,6 +11,7 @@ const t = translate;
|
||||
const props = defineProps<{
|
||||
data?: PageData | PageData[];
|
||||
fields?: AutoProbeNavItem[];
|
||||
activeFieldName?: string;
|
||||
}>();
|
||||
|
||||
// Refs
|
||||
@@ -39,6 +41,7 @@ const tableColumns = computed<TableColumns<PageData>>(() => {
|
||||
return {
|
||||
key: field.name,
|
||||
label: field.name,
|
||||
minWidth: '200',
|
||||
value: (row: PageData) => {
|
||||
switch (field.type) {
|
||||
case 'list':
|
||||
@@ -65,6 +68,16 @@ const tableData = computed<TableData<PageData | PageData[]>>(() => {
|
||||
return [data];
|
||||
});
|
||||
|
||||
const tableCellStyle: CellStyle<PageData> = ({ column }) => {
|
||||
const { activeFieldName } = props;
|
||||
if (column.columnKey === activeFieldName) {
|
||||
return {
|
||||
backgroundColor: 'var(--el-color-primary-light-9)',
|
||||
};
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
// Methods
|
||||
const onTabSelect = (id: string) => {
|
||||
if (activeTabName.value === id) {
|
||||
@@ -125,8 +138,11 @@ defineOptions({ name: 'ClAutoProbeResultsContainer' });
|
||||
</cl-nav-tabs>
|
||||
<div class="results" v-if="activeTabName === TAB_NAME_RESULTS">
|
||||
<cl-table
|
||||
:key="JSON.stringify(tableColumns)"
|
||||
:columns="tableColumns"
|
||||
:data="tableData"
|
||||
:header-cell-style="tableCellStyle"
|
||||
:cell-style="tableCellStyle"
|
||||
embedded
|
||||
hide-footer
|
||||
/>
|
||||
|
||||
@@ -80,4 +80,10 @@ export declare global {
|
||||
parent?: AutoProbeNavItem;
|
||||
fieldCount?: number;
|
||||
}
|
||||
|
||||
interface AutoProbeResults {
|
||||
data?: PageData | PageData[];
|
||||
fields?: AutoProbeNavItem[];
|
||||
activeField?: AutoProbeNavItem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,5 @@ interface TreeNode<T = any> {
|
||||
value?: any;
|
||||
children?: T[];
|
||||
path?: string;
|
||||
level?: number;
|
||||
}
|
||||
|
||||
@@ -125,7 +125,8 @@ defineOptions({ name: 'ClDetailLayout' });
|
||||
overflow: hidden;
|
||||
|
||||
.nav-actions {
|
||||
height: fit-content;
|
||||
height: 53px;
|
||||
flex: 0 0 53px;
|
||||
}
|
||||
|
||||
.nav-select {
|
||||
@@ -143,7 +144,7 @@ defineOptions({ name: 'ClDetailLayout' });
|
||||
|
||||
.content-container {
|
||||
flex: 1;
|
||||
height: calc(100% - 41px - 50px);
|
||||
height: calc(100% - 41px - 53px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,7 +316,6 @@ export const getDefaultStoreActions = <T = any>(
|
||||
state,
|
||||
commit,
|
||||
}: StoreActionContext<BaseStoreState<T>>) => {
|
||||
console.debug('getList');
|
||||
const { page, size } = state.tablePagination;
|
||||
try {
|
||||
commit('setTableLoading', true);
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
import { getIconByExtractType, getIconByItemType, translate } from '@/utils';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { getIconByExtractType, getIconByItemType, translate } from '@/utils';
|
||||
import { useAutoProbeDetail } from '@/views';
|
||||
|
||||
// i18n
|
||||
const t = translate;
|
||||
@@ -11,6 +12,8 @@ const t = translate;
|
||||
const store = useStore();
|
||||
const { autoprobe: state } = store.state as RootStoreState;
|
||||
|
||||
const { activeId } = useAutoProbeDetail();
|
||||
|
||||
// form data
|
||||
const form = computed<AutoProbe>(() => state.form);
|
||||
const pageFields = computed(() => form.value?.page_pattern?.fields);
|
||||
@@ -19,6 +22,54 @@ const pagePagination = computed(() => form.value?.page_pattern?.pagination);
|
||||
const pageData = computed<PageData>(() => form.value?.page_data || {});
|
||||
const pageNavItemId = 'page';
|
||||
|
||||
// results data and fields based on active item
|
||||
const resultsDataFields = computed<AutoProbeResults>(() => {
|
||||
const rootDataFields: AutoProbeResults = {
|
||||
data: pageData.value,
|
||||
fields: computedTreeItems.value[0].children?.filter(
|
||||
item => item.type !== 'pagination'
|
||||
),
|
||||
};
|
||||
|
||||
if (!activeNavItem.value || !pageData.value) {
|
||||
return rootDataFields;
|
||||
}
|
||||
|
||||
const item = activeNavItem.value;
|
||||
|
||||
if (item.level === 0) {
|
||||
return rootDataFields;
|
||||
} else if (item.level === 1) {
|
||||
if (item.type === 'list') {
|
||||
return {
|
||||
data: pageData.value[item.name!],
|
||||
fields: item.children,
|
||||
} as AutoProbeResults;
|
||||
}
|
||||
return {
|
||||
...rootDataFields,
|
||||
activeField: item,
|
||||
};
|
||||
} else {
|
||||
let currentItem = item;
|
||||
while (currentItem.parent) {
|
||||
const parent = currentItem.parent;
|
||||
if (parent.level === 1 && parent.type === 'list') {
|
||||
return {
|
||||
data: pageData.value[parent.name!],
|
||||
fields: parent.children,
|
||||
activeField: currentItem,
|
||||
} as AutoProbeResults;
|
||||
}
|
||||
currentItem = currentItem.parent;
|
||||
}
|
||||
return rootDataFields;
|
||||
}
|
||||
});
|
||||
const resultsData = computed(() => resultsDataFields.value.data);
|
||||
const resultsFields = computed(() => resultsDataFields.value.fields);
|
||||
const resultsActiveField = computed(() => resultsDataFields.value.activeField);
|
||||
|
||||
const normalizeItem = (item: AutoProbeNavItem) => {
|
||||
const label = item.label ?? `${item.name} (${item.children?.length || 0})`;
|
||||
let icon: Icon;
|
||||
@@ -38,7 +89,8 @@ const normalizeItem = (item: AutoProbeNavItem) => {
|
||||
// Helper function to recursively process list items
|
||||
const processListItem = (
|
||||
list: ListRule,
|
||||
parent?: AutoProbeNavItem
|
||||
parent?: AutoProbeNavItem,
|
||||
level: number = 1
|
||||
): AutoProbeNavItem => {
|
||||
const listItem: AutoProbeNavItem = {
|
||||
id: list.name,
|
||||
@@ -47,6 +99,7 @@ const processListItem = (
|
||||
rule: list,
|
||||
children: [],
|
||||
parent,
|
||||
level,
|
||||
};
|
||||
|
||||
// Add fields directly if they exist
|
||||
@@ -60,6 +113,7 @@ const processListItem = (
|
||||
type: 'field',
|
||||
rule: field,
|
||||
parent: listItem,
|
||||
level: level + 1,
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -68,7 +122,7 @@ const processListItem = (
|
||||
// Recursively process nested lists if they exist
|
||||
if (list.item_pattern?.lists && list.item_pattern.lists.length > 0) {
|
||||
list.item_pattern.lists.forEach((nestedList: ListRule) => {
|
||||
listItem.children!.push(processListItem(nestedList, listItem));
|
||||
listItem.children!.push(processListItem(nestedList, listItem, level + 1));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -96,6 +150,7 @@ const computedTreeItems = computed<AutoProbeNavItem[]>(() => {
|
||||
name: form.value.page_pattern.name,
|
||||
type: 'page_pattern',
|
||||
children: [],
|
||||
level: 0,
|
||||
};
|
||||
|
||||
// Add fields directly if they exist
|
||||
@@ -109,6 +164,7 @@ const computedTreeItems = computed<AutoProbeNavItem[]>(() => {
|
||||
type: 'field',
|
||||
rule: field,
|
||||
parent: rootItem,
|
||||
level: 1,
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -117,7 +173,7 @@ const computedTreeItems = computed<AutoProbeNavItem[]>(() => {
|
||||
// Add lists directly if they exist
|
||||
if (pageLists.value) {
|
||||
pageLists.value.forEach(list => {
|
||||
rootItem.children!.push(processListItem(list, rootItem));
|
||||
rootItem.children!.push(processListItem(list, rootItem, 1));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -131,6 +187,7 @@ const computedTreeItems = computed<AutoProbeNavItem[]>(() => {
|
||||
type: 'pagination',
|
||||
rule: pagePagination.value,
|
||||
parent: rootItem,
|
||||
level: 1,
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -146,6 +203,11 @@ watch(
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
watch(activeId, () => {
|
||||
// Reset active item when the page changes
|
||||
activeNavItem.value = undefined;
|
||||
});
|
||||
|
||||
// ref
|
||||
const sidebarRef = ref();
|
||||
const detailContainerRef = ref<HTMLElement | null>(null);
|
||||
@@ -193,11 +255,11 @@ defineOptions({ name: 'ClAutoProbeDetailTabPatterns' });
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--TODO: implement the data for activeNavItem-->
|
||||
<cl-auto-probe-results-container
|
||||
v-if="detailNavItem"
|
||||
:data="pageData"
|
||||
:fields="activeNavItem?.children"
|
||||
:data="resultsData"
|
||||
:fields="resultsFields"
|
||||
:active-field-name="resultsActiveField?.name"
|
||||
@size-change="onSizeChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { useDetail } from '@/layouts/content';
|
||||
|
||||
const useAutoProbeDetail = () => {
|
||||
return {
|
||||
...useDetail<AutoProbe>('autoprobe'),
|
||||
};
|
||||
};
|
||||
|
||||
export default useAutoProbeDetail;
|
||||
@@ -92,6 +92,7 @@ import TaskDetailTabLogs from './task/detail/tabs/TaskDetailTabLogs.vue';
|
||||
import TaskDetailTabOverview from './task/detail/tabs/TaskDetailTabOverview.vue';
|
||||
import TaskList from './task/list/TaskList.vue';
|
||||
import TokenList from './token/list/TokenList.vue';
|
||||
import useAutoProbeDetail from './autoprobe/detail/useAutoProbeDetail';
|
||||
import useAutoProbeList from './autoprobe/list/useAutoProbeList';
|
||||
import useDatabaseDetail from './database/detail/useDatabaseDetail';
|
||||
import useDatabaseList from './database/list/useDatabaseList';
|
||||
@@ -218,6 +219,7 @@ export {
|
||||
TaskDetailTabOverview as ClTaskDetailTabOverview,
|
||||
TaskList as ClTaskList,
|
||||
TokenList as ClTokenList,
|
||||
useAutoProbeDetail as useAutoProbeDetail,
|
||||
useAutoProbeList as useAutoProbeList,
|
||||
useDatabaseDetail as useDatabaseDetail,
|
||||
useDatabaseList as useDatabaseList,
|
||||
|
||||
Reference in New Issue
Block a user