refactor: remove unused javascript-time-ago types and enhance node sorting logic

This commit is contained in:
Marvin Zhang
2025-06-11 22:30:46 +08:00
parent 622dce51c3
commit 3552b7805b
9 changed files with 63 additions and 38 deletions

View File

@@ -75,7 +75,6 @@
"@popperjs/core": "^2.11.8",
"@types/getos": "^3.0.4",
"@types/humanize-duration": "^3.27.4",
"@types/javascript-time-ago": "^2.0.8",
"@types/lodash": "^4.17.6",
"@types/markdown-it": "^14.1.2",
"@types/md5": "^2.3.5",

View File

@@ -50,9 +50,6 @@ importers:
'@types/humanize-duration':
specifier: ^3.27.4
version: 3.27.4
'@types/javascript-time-ago':
specifier: ^2.0.8
version: 2.5.0
'@types/lodash':
specifier: ^4.17.6
version: 4.17.16
@@ -1205,10 +1202,6 @@ packages:
'@types/istanbul-reports@3.0.4':
resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==}
'@types/javascript-time-ago@2.5.0':
resolution: {integrity: sha512-c0GQ02qkkZx138VphjPqU4+PkVSNkWvQcpE3Yy03S6NpWlT9XTSXPUbJ1qv4KV0/eW7wSEAoU87e2YHz7ndHrA==}
deprecated: This is a stub types definition. javascript-time-ago provides its own type definitions, so you do not need this installed.
'@types/jest@29.5.14':
resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==}
@@ -4632,10 +4625,6 @@ snapshots:
dependencies:
'@types/istanbul-lib-report': 3.0.3
'@types/javascript-time-ago@2.5.0':
dependencies:
javascript-time-ago: 2.5.11
'@types/jest@29.5.14':
dependencies:
expect: 29.7.0

View File

@@ -17,19 +17,22 @@ const useNode = (store: Store<RootStoreState>) => {
// form rules
const formRules: FormRules = {};
const allNodesSorted = computed(() => {
return state.allNodes.sort((a, b) => {
if (a.is_master) return -1;
if (b.is_master) return 1;
return a.name!.localeCompare(b.name!);
});
});
const activeNodesSorted = computed(() => {
return state.allNodes
.filter(n => n.active)
.sort((a, b) => {
if (a.is_master) return -1;
if (b.is_master) return 1;
return a.name!.localeCompare(b.name!);
});
return allNodesSorted.value.filter(node => node.active);
});
return {
...useForm<Node>(ns, store, useNodeService(store), formComponentData),
formRules,
allNodesSorted,
activeNodesSorted,
};
};

View File

@@ -4,7 +4,7 @@ import { useStore } from 'vuex';
import { useSpider, useProject, useNode } from '@/components';
import { TASK_MODE_RANDOM, TASK_MODE_SELECTED_NODES } from '@/constants/task';
import pinyin, { STYLE_NORMAL } from 'pinyin';
import { isZeroObjectId } from '@/utils/mongo';
import { EMPTY_OBJECT_ID, isZeroObjectId } from '@/utils/mongo';
import { useSpiderDetail } from '@/views';
import { getToRunNodes, priorityOptions, translate } from '@/utils';
import { getSpiderTemplateGroups, getSpiderTemplates } from '@/utils/spider';
@@ -20,11 +20,11 @@ const { get } = useRequest();
const store = useStore();
// use node
const { activeNodesSorted: activeNodes } = useNode(store);
const { allNodesSorted: allNodes } = useNode(store);
const toRunNodes = computed(() => {
const { mode, node_ids } = form.value;
return getToRunNodes(mode, node_ids, activeNodes.value);
return getToRunNodes(mode, node_ids, allNodes.value);
});
// use spider
@@ -177,7 +177,15 @@ defineOptions({ name: 'ClSpiderForm' });
:label="t('components.spider.form.project')"
prop="project_id"
>
<cl-remote-select v-model="form.project_id" endpoint="/projects" />
<cl-remote-select
v-model="form.project_id"
endpoint="/projects"
filterable
:empty-option="{
label: t('common.status.unassigned'),
value: EMPTY_OBJECT_ID,
}"
/>
</cl-form-item>
<!-- ./Row -->
@@ -246,7 +254,7 @@ defineOptions({ name: 'ClSpiderForm' });
:placeholder="t('components.spider.form.selectedNodes')"
>
<el-option
v-for="n in activeNodes"
v-for="n in allNodes"
:key="n.key"
:value="n._id"
:label="n.name"
@@ -254,7 +262,14 @@ defineOptions({ name: 'ClSpiderForm' });
<span style="margin-right: 5px">
<cl-node-tag :node="n" icon-only />
</span>
<span>{{ n.name }}</span>
<span>
{{
n.name +
(n.active
? ''
: ` (${t('components.node.nodeStatus.label.offline')})`)
}}
</span>
</el-option>
</el-select>
</cl-form-item>

View File

@@ -8,11 +8,13 @@ const props = withDefaults(
placeholder?: string;
disabled?: boolean;
filterable?: boolean;
clearable?: boolean;
remoteShowSuffix?: boolean;
endpoint: string;
labelKey?: string;
valueKey?: string;
limit?: number;
emptyOption?: SelectOption;
}>(),
{
remoteShowSuffix: true,
@@ -62,12 +64,21 @@ const remoteMethod = async (query?: string) => {
loading.value = false;
}
};
const selectOptions = computed<SelectOption[]>(() =>
list.value.map(row => ({
label: row[props.labelKey],
value: row[props.valueKey],
}))
);
const selectOptions = computed<SelectOption[]>(() => {
const { emptyOption, labelKey, valueKey } = props;
const options: SelectOption[] = list.value.map(row => ({
label: row[labelKey],
value: row[valueKey],
}));
if (emptyOption) {
const { label, value } = emptyOption;
options.unshift({
label,
value,
});
}
return options;
});
onBeforeMount(remoteMethod);
defineOptions({ name: 'ClRemoteSelect' });
@@ -79,6 +90,7 @@ defineOptions({ name: 'ClRemoteSelect' });
:placeholder="placeholder"
:filterable="filterable"
:disabled="disabled"
:clearable="clearable"
remote
:remote-method="remoteMethod"
:remote-show-suffix="remoteShowSuffix"

View File

@@ -10,6 +10,7 @@ const props = withDefaults(
showBackButton?: boolean;
showSaveButton?: boolean;
allListSelectOptions?: SelectOption[];
navItemLabelFn?: (item: NavItem) => string;
}>(),
{
navItemNameKey: 'name',
@@ -77,7 +78,7 @@ defineOptions({ name: 'ClDetailLayout' });
<el-option
v-for="item in navItems"
:key="item.id"
:label="item.label"
:label="navItemLabelFn ? navItemLabelFn(item) : item.label"
:value="item.id"
/>
</el-select>

View File

@@ -41,6 +41,7 @@ const useDetail = <T extends BaseModel>(ns: ListStoreNamespace) => {
items.unshift({
id: activeId.value,
label: form.name || activeId.value,
data: form,
});
}
return items;

View File

@@ -1,9 +1,8 @@
import dayjs from 'dayjs';
import TimeAgo, { LocaleData } from 'javascript-time-ago';
import TimeAgo, { LocaleData, FormatStyleName } from 'javascript-time-ago';
import { getI18n } from '@/i18n';
import en from 'javascript-time-ago/locale/en';
import zh from 'javascript-time-ago/locale/zh';
import { FormatStyle } from 'javascript-time-ago/style';
TimeAgo.addLocale(en as LocaleData);
TimeAgo.addLocale(zh as LocaleData);
@@ -18,7 +17,7 @@ export const getTimeUnitParts = (timeUnit: string) => {
export const formatTimeAgo = (
value: string | Date,
formatStyle?: string | FormatStyle
formatStyle?: string | FormatStyleName
) => {
const time = dayjs(value);
const timeAgo = new TimeAgo(

View File

@@ -2,13 +2,20 @@
import { useStore } from 'vuex';
import { useTaskDetail } from '@/views';
import { useTask } from '@/components';
import { isPro } from '@/utils';
import { formatTimeAgo, isPro } from '@/utils';
const { activeTabName } = useTaskDetail();
const store = useStore();
const { allListSelectOptions } = useTask(store);
const navItemLabelFn = (item: NavItem<Task>) => {
if (!item.data) return item.label;
const spiderName = item.data.spider?.name;
const createdAt = formatTimeAgo(item.data.created_at!, 'mini-minute-now');
return `${spiderName} - ${createdAt}`;
};
defineOptions({ name: 'ClTaskDetail' });
</script>
@@ -16,6 +23,7 @@ defineOptions({ name: 'ClTaskDetail' });
<cl-detail-layout
store-namespace="task"
:all-list-select-options="allListSelectOptions"
:nav-item-label-fn="navItemLabelFn"
>
<template #actions>
<cl-task-detail-actions-common />
@@ -26,5 +34,3 @@ defineOptions({ name: 'ClTaskDetail' });
</template>
</cl-detail-layout>
</template>