Commit d88c812b authored by wuzekai's avatar wuzekai

feat: 汉化 /histories 与 /datasets 路由页面

- /histories 列表/查看/归档/导出页面汉化
- /datasets 列表/查看/复制/详情页面汉化
- 历史卡片操作、数据集操作、状态提示等界面文本中文化
parent 3932f929
...@@ -77,7 +77,7 @@ async function loadHistories() { ...@@ -77,7 +77,7 @@ async function loadHistories() {
await loadContents(); await loadContents();
} }
} else { } else {
errorMessage.value = "No Histories found."; errorMessage.value = "未找到历史记录。";
} }
loading.value = false; loading.value = false;
} }
...@@ -145,7 +145,7 @@ async function onCopy() { ...@@ -145,7 +145,7 @@ async function onCopy() {
} }
loading.value = false; loading.value = false;
} else { } else {
errorMessage.value = "Please select datasets and collections."; errorMessage.value = "请选择数据集和集合。";
} }
} }
...@@ -162,7 +162,7 @@ defineExpose({ ...@@ -162,7 +162,7 @@ defineExpose({
<div> <div>
<BAlert v-if="errorMessage" variant="danger" show>{{ errorMessage }}</BAlert> <BAlert v-if="errorMessage" variant="danger" show>{{ errorMessage }}</BAlert>
<BAlert v-else-if="successTargetIds.length > 0 && successTargetIds[0]" variant="success" show> <BAlert v-else-if="successTargetIds.length > 0 && successTargetIds[0]" variant="success" show>
{{ successItemCount }} item{{ successItemCount === 1 ? "" : "s" }} copied to: {{ successItemCount }} 个项目已复制到:
<span v-if="successHistoryName"> <span v-if="successHistoryName">
<RouterLink <RouterLink
:to="`/histories/view?id=${successTargetIds[0]}`" :to="`/histories/view?id=${successTargetIds[0]}`"
...@@ -214,9 +214,9 @@ defineExpose({ ...@@ -214,9 +214,9 @@ defineExpose({
</div> </div>
<div class="d-flex mt-2"> <div class="d-flex mt-2">
<BButton class="mr-2" size="sm" variant="outline-primary" @click="toggleAll(true)"> <BButton class="mr-2" size="sm" variant="outline-primary" @click="toggleAll(true)">
Select All 全选
</BButton> </BButton>
<BButton size="sm" variant="outline-primary" @click="toggleAll(false)"> Unselect All </BButton> <BButton size="sm" variant="outline-primary" @click="toggleAll(false)"> 取消全选 </BButton>
</div> </div>
</div> </div>
...@@ -239,7 +239,7 @@ defineExpose({ ...@@ -239,7 +239,7 @@ defineExpose({
newHistoryName = ''; newHistoryName = '';
targetMultiSelections = {}; targetMultiSelections = {};
" /> " />
<span class="text-sm mt-1"><b>OR</b> Select Multiple Target Histories:</span> <span class="text-sm mt-1"><b>或</b> 选择多个目标历史记录:</span>
<div class="dataset-copy-contents flex-grow-1 overflow-auto border rounded p-2"> <div class="dataset-copy-contents flex-grow-1 overflow-auto border rounded p-2">
<div v-if="histories.length === 0" class="text-muted">没有历史。</div> <div v-if="histories.length === 0" class="text-muted">没有历史。</div>
<div v-for="h in histories" :key="h.id" class="d-flex align-items-center mb-1"> <div v-for="h in histories" :key="h.id" class="d-flex align-items-center mb-1">
...@@ -253,7 +253,7 @@ defineExpose({ ...@@ -253,7 +253,7 @@ defineExpose({
</BFormCheckbox> </BFormCheckbox>
</div> </div>
</div> </div>
<span class="text-sm mt-1"><b>OR</b> Provide a New History Name:</span> <span class="text-sm mt-1"><b>或</b> 提供新的历史记录名称:</span>
<BFormInput <BFormInput
v-model="newHistoryName" v-model="newHistoryName"
data-description="copy history name" data-description="copy history name"
......
...@@ -77,14 +77,14 @@ watch( ...@@ -77,14 +77,14 @@ watch(
<BAlert v-if="errorMessage" variant="danger" show> <BAlert v-if="errorMessage" variant="danger" show>
{{ errorMessage }} {{ errorMessage }}
</BAlert> </BAlert>
<LoadingSpan v-else-if="isLoading || !dataset" message="Loading dataset content" /> <LoadingSpan v-else-if="isLoading || !dataset" message="正在加载数据集内容" />
<BAlert v-else-if="STATES.PENDING_STATES.includes(dataset.state)" show variant="warning"> <BAlert v-else-if="STATES.PENDING_STATES.includes(dataset.state)" show variant="warning">
<FontAwesomeIcon :icon="faSpinner" spin /> <FontAwesomeIcon :icon="faSpinner" spin />
<span>Waiting for dataset to become available. Please check the history panel for details.</span> <span>正在等待数据集变为可用。请查看历史记录面板以获取详细信息。</span>
</BAlert> </BAlert>
<BAlert v-else-if="!STATES.OK_STATES.includes(dataset.state)" show variant="danger"> <BAlert v-else-if="!STATES.OK_STATES.includes(dataset.state)" show variant="danger">
<FontAwesomeIcon :icon="faExclamationTriangle" /> <FontAwesomeIcon :icon="faExclamationTriangle" />
<span>Dataset is unavailable. Please check the history panel for details.</span> <span>数据集不可用。请查看历史记录面板以获取详细信息。</span>
</BAlert> </BAlert>
<div v-else class="dataset-display h-100"> <div v-else class="dataset-display h-100">
<Alert v-if="sanitizedMessage" :dismissible="true" variant="warning" data-description="sanitization warning"> <Alert v-if="sanitizedMessage" :dismissible="true" variant="warning" data-description="sanitization warning">
......
...@@ -24,32 +24,32 @@ import LoadingSpan from "@/components/LoadingSpan.vue"; ...@@ -24,32 +24,32 @@ import LoadingSpan from "@/components/LoadingSpan.vue";
import StatelessTags from "@/components/TagsMultiselect/StatelessTags.vue"; import StatelessTags from "@/components/TagsMultiselect/StatelessTags.vue";
import UtcDate from "@/components/UtcDate.vue"; import UtcDate from "@/components/UtcDate.vue";
const breadcrumbItems = [{ title: "Datasets", to: "/datasets/list" }]; const breadcrumbItems = [{ title: "数据集", to: "/datasets/list" }];
const allFields = [ const allFields = [
{ {
key: "name", key: "name",
label: "Name", label: "名称",
sortable: true, sortable: true,
}, },
{ {
key: "tags", key: "tags",
label: "Tags", label: "标签",
sortable: false, sortable: false,
}, },
{ {
key: "history_id", key: "history_id",
label: "History", label: "历史记录",
sortable: true, sortable: true,
}, },
{ {
key: "extension", key: "extension",
label: "Extension", label: "扩展名",
sortable: true, sortable: true,
}, },
{ {
key: "update_time", key: "update_time",
label: "Updated", label: "更新于",
sortable: true, sortable: true,
}, },
]; ];
...@@ -112,7 +112,7 @@ async function load(showOverlay = false) { ...@@ -112,7 +112,7 @@ async function load(showOverlay = false) {
rows.value = data; rows.value = data;
totalDatasets.value = totalMatches; totalDatasets.value = totalMatches;
} catch (e: any) { } catch (e: any) {
Toast.error(`Failed to load datasets: ${e}`); Toast.error(`无法加载数据集:${e}`);
} finally { } finally {
loading.value = false; loading.value = false;
overlay.value = false; overlay.value = false;
...@@ -129,7 +129,7 @@ async function onTags(tags: string[], index: number) { ...@@ -129,7 +129,7 @@ async function onTags(tags: string[], index: number) {
try { try {
await updateTags(item?.id as string, "HistoryDatasetAssociation", tags); await updateTags(item?.id as string, "HistoryDatasetAssociation", tags);
} catch (e: any) { } catch (e: any) {
Toast.error(`Failed to update tags: ${e}`); Toast.error(`无法更新标签:${e}`);
} }
} }
...@@ -189,10 +189,10 @@ function onToggleColumn(key: string) { ...@@ -189,10 +189,10 @@ function onToggleColumn(key: string) {
async function onBulkDelete() { async function onBulkDelete() {
const totalSelected = selectedItemIds.value.length; const totalSelected = selectedItemIds.value.length;
const confirmed = await confirm(`Are you sure you want to delete ${totalSelected} datasets?`, { const confirmed = await confirm(`确定要删除 ${totalSelected} 个数据集吗?`, {
id: "bulk-delete-datasets-confirmation", id: "bulk-delete-datasets-confirmation",
title: "Delete datasets", title: "删除数据集",
okTitle: "Delete datasets", okTitle: "删除数据集",
okVariant: "danger", okVariant: "danger",
cancelVariant: "outline-primary", cancelVariant: "outline-primary",
centered: true, centered: true,
...@@ -215,11 +215,11 @@ async function onBulkDelete() { ...@@ -215,11 +215,11 @@ async function onBulkDelete() {
); );
} }
Toast.success(`Deleted ${totalSelected} dataset${totalSelected > 1 ? "s" : ""}.`); Toast.success(`已删除 ${totalSelected} 个数据集。`);
selectedItemIds.value = []; selectedItemIds.value = [];
} catch (e: any) { } catch (e: any) {
Toast.error(`Failed to delete some datasets: ${e}`); Toast.error(`无法删除部分数据集:${e}`);
} finally { } finally {
overlay.value = false; overlay.value = false;
bulkDeleteOrRestoreLoading.value = false; bulkDeleteOrRestoreLoading.value = false;
...@@ -231,13 +231,13 @@ async function onBulkDelete() { ...@@ -231,13 +231,13 @@ async function onBulkDelete() {
function getDatasetStatusIcon(item: HDASummary): RowIcon | undefined { function getDatasetStatusIcon(item: HDASummary): RowIcon | undefined {
if (item.purged) { if (item.purged) {
return { icon: faBurn, class: "text-danger", title: "Purged" }; return { icon: faBurn, class: "text-danger", title: "已清除" };
} }
if (item.deleted) { if (item.deleted) {
return { icon: faTrash, class: "text-muted", title: "Deleted" }; return { icon: faTrash, class: "text-muted", title: "已删除" };
} }
if (item.state === "ok") { if (item.state === "ok") {
return { icon: faCheckCircle, class: "text-success", title: "Success" }; return { icon: faCheckCircle, class: "text-success", title: "成功" };
} }
const state = item.state && STATES[item.state]; const state = item.state && STATES[item.state];
if (state?.icon) { if (state?.icon) {
...@@ -260,7 +260,7 @@ onMounted(() => { ...@@ -260,7 +260,7 @@ onMounted(() => {
<div class="dataset-list-container h-100 d-flex flex-column"> <div class="dataset-list-container h-100 d-flex flex-column">
<BreadcrumbHeading :items="breadcrumbItems" /> <BreadcrumbHeading :items="breadcrumbItems" />
<div class="dataset-list-header"> <div class="dataset-list-header">
<DelayedInput class="m-2 mb-3" placeholder="Search Datasets" @change="onQuery" /> <DelayedInput class="m-2 mb-3" placeholder="搜索数据集" @change="onQuery" />
<ListHeader <ListHeader
list-id="datasets" list-id="datasets"
...@@ -276,17 +276,17 @@ onMounted(() => { ...@@ -276,17 +276,17 @@ onMounted(() => {
<div v-if="loading" class="dataset-list-content"> <div v-if="loading" class="dataset-list-content">
<BAlert variant="info" show> <BAlert variant="info" show>
<LoadingSpan message="Loading datasets" /> <LoadingSpan message="正在加载数据集" />
</BAlert> </BAlert>
</div> </div>
<div v-else-if="showNotAvailable" class="dataset-list-content"> <div v-else-if="showNotAvailable" class="dataset-list-content">
<BAlert id="dataset-list-empty" variant="info" show> <BAlert id="dataset-list-empty" variant="info" show>
No datasets found. You may upload new datasets using the button above. 未找到数据集。您可以使用上方按钮上传新的数据集。
</BAlert> </BAlert>
</div> </div>
<div v-else-if="showNotFound" class="dataset-list-content"> <div v-else-if="showNotFound" class="dataset-list-content">
<BAlert id="no-dataset-found" variant="info" show> <BAlert id="no-dataset-found" variant="info" show>
No matching entries found for: <span class="font-weight-bold">{{ query }}</span> 未找到匹配的条目:<span class="font-weight-bold">{{ query }}</span>
</BAlert> </BAlert>
</div> </div>
<div v-else class="dataset-list-content overflow-auto"> <div v-else class="dataset-list-content overflow-auto">
...@@ -342,7 +342,7 @@ onMounted(() => { ...@@ -342,7 +342,7 @@ onMounted(() => {
size="sm" size="sm"
variant="primary" variant="primary"
:disabled="bulkDeleteOrRestoreLoading" :disabled="bulkDeleteOrRestoreLoading"
:title="bulkDeleteOrRestoreLoading ? 'Deleting datasets' : 'Delete selected datasets'" :title="bulkDeleteOrRestoreLoading ? '正在删除数据集' : '删除选中的数据集'"
@click="onBulkDelete"> @click="onBulkDelete">
<FontAwesomeIcon :icon="faTrash" /> <FontAwesomeIcon :icon="faTrash" />
{{ localize("Delete Selected") }} ({{ selectedItemIds.length }}) {{ localize("Delete Selected") }} ({{ selectedItemIds.length }})
......
...@@ -37,7 +37,7 @@ watch(props, () => { ...@@ -37,7 +37,7 @@ watch(props, () => {
<template> <template>
<div> <div>
<LoadingSpan v-if="loading" message="Loading permission information" /> <LoadingSpan v-if="loading" message="正在加载权限信息" />
<div v-else-if="simplePermissions && !selectedAdvancedForm"> <div v-else-if="simplePermissions && !selectedAdvancedForm">
<PortletSection :icon="faUsers" :title="title"> <PortletSection :icon="faUsers" :title="title">
<div class="mb-3"> <div class="mb-3">
......
...@@ -73,7 +73,7 @@ watch(props, fetch, { immediate: true }); ...@@ -73,7 +73,7 @@ watch(props, fetch, { immediate: true });
<div v-if="errorMessage" class="error">{{ errorMessage }}</div> <div v-if="errorMessage" class="error">{{ errorMessage }}</div>
<LoadingSpan v-else-if="storageInfo == null"> </LoadingSpan> <LoadingSpan v-else-if="storageInfo == null"> </LoadingSpan>
<div v-else-if="discarded"> <div v-else-if="discarded">
<p>This dataset has been discarded and its files are not available to Galaxy.</p> <p>此数据集已被弃用,其文件对 Galaxy 不可用。</p>
</div> </div>
<div v-else-if="deferred"> <div v-else-if="deferred">
<p> <p>
......
...@@ -92,7 +92,7 @@ async function relocate(objectStoreId: string) { ...@@ -92,7 +92,7 @@ async function relocate(objectStoreId: string) {
<template> <template>
<span class="storage-relocate-link"> <span class="storage-relocate-link">
<SelectModal v-if="currentObjectStore" v-model="showModal" title="Relocate Dataset"> <SelectModal v-if="currentObjectStore" v-model="showModal" title="迁移数据集">
<RelocateDialog <RelocateDialog
:from-object-store="currentObjectStore" :from-object-store="currentObjectStore"
:target-object-stores="validTargets" :target-object-stores="validTargets"
......
...@@ -117,7 +117,7 @@ watch( ...@@ -117,7 +117,7 @@ watch(
}} }}
</p> </p>
</div> </div>
<LoadingSpan v-else-if="isLoading || !dataset" message="Loading dataset details" /> <LoadingSpan v-else-if="isLoading || !dataset" message="正在加载数据集详情" />
<div v-else class="dataset-view d-flex flex-column"> <div v-else class="dataset-view d-flex flex-column">
<header v-if="!displayOnly" :key="`dataset-header-${dataset.id}`" class="dataset-header flex-shrink-0"> <header v-if="!displayOnly" :key="`dataset-header-${dataset.id}`" class="dataset-header flex-shrink-0">
<div class="d-flex"> <div class="d-flex">
...@@ -168,43 +168,43 @@ watch( ...@@ -168,43 +168,43 @@ watch(
<BNav v-if="!displayOnly" pills class="my-2 p-2 bg-light border-bottom"> <BNav v-if="!displayOnly" pills class="my-2 p-2 bg-light border-bottom">
<BNavItem <BNavItem
v-if="showOk" v-if="showOk"
title="View a preview of the dataset contents" title="查看数据集内容的预览"
:active="tab === 'preview'" :active="tab === 'preview'"
:to="`/datasets/${datasetId}/preview`"> :to="`/datasets/${datasetId}/preview`">
<FontAwesomeIcon :icon="faEye" class="mr-1" /> Preview <FontAwesomeIcon :icon="faEye" class="mr-1" /> 预览
</BNavItem> </BNavItem>
<BNavItem <BNavItem
v-if="showOk && preferredVisualization" v-if="showOk && preferredVisualization"
title="View raw dataset contents" title="查看数据集原始内容"
:active="tab === 'raw'" :active="tab === 'raw'"
:to="`/datasets/${datasetId}/raw`"> :to="`/datasets/${datasetId}/raw`">
<FontAwesomeIcon :icon="faFileAlt" class="mr-1" /> Raw <FontAwesomeIcon :icon="faFileAlt" class="mr-1" /> 原始
</BNavItem> </BNavItem>
<BNavItem <BNavItem
v-if="showOk" v-if="showOk"
title="Explore available visualizations for this dataset" title="探索此数据集可用的可视化"
:active="tab === 'visualize'" :active="tab === 'visualize'"
:to="`/datasets/${datasetId}/visualize`"> :to="`/datasets/${datasetId}/visualize`">
<FontAwesomeIcon :icon="faChartBar" class="mr-1" /> Visualize <FontAwesomeIcon :icon="faChartBar" class="mr-1" /> 可视化
</BNavItem> </BNavItem>
<BNavItem <BNavItem
title="View detailed information about this dataset" title="查看此数据集的详细信息"
:active="tab === 'details'" :active="tab === 'details'"
:to="`/datasets/${datasetId}/details`"> :to="`/datasets/${datasetId}/details`">
<FontAwesomeIcon :icon="faInfoCircle" class="mr-1" /> Details <FontAwesomeIcon :icon="faInfoCircle" class="mr-1" /> 详情
</BNavItem> </BNavItem>
<BNavItem <BNavItem
title="Edit dataset attributes and metadata" title="编辑数据集属性和元数据"
:active="tab === 'edit'" :active="tab === 'edit'"
:to="`/datasets/${datasetId}/edit`"> :to="`/datasets/${datasetId}/edit`">
<FontAwesomeIcon :icon="faPen" class="mr-1" /> Edit <FontAwesomeIcon :icon="faPen" class="mr-1" /> 编辑
</BNavItem> </BNavItem>
<BNavItem <BNavItem
v-if="showError" v-if="showError"
title="View error information for this dataset" title="查看此数据集的错误信息"
:active="tab === 'error'" :active="tab === 'error'"
:to="`/datasets/${datasetId}/error`"> :to="`/datasets/${datasetId}/error`">
<FontAwesomeIcon :icon="faBug" class="mr-1" /> Error <FontAwesomeIcon :icon="faBug" class="mr-1" /> 错误
</BNavItem> </BNavItem>
</BNav> </BNav>
<div v-if="tab === 'preview'" class="tab-content-panel"> <div v-if="tab === 'preview'" class="tab-content-panel">
...@@ -216,7 +216,7 @@ watch( ...@@ -216,7 +216,7 @@ watch(
<div v-else-if="isAutoDownloadType && !isPdfDataset" class="auto-download-message p-4"> <div v-else-if="isAutoDownloadType && !isPdfDataset" class="auto-download-message p-4">
<div class="alert alert-info"> <div class="alert alert-info">
<h4>{{ localize("Download Required") }}</h4> <h4>{{ localize("Download Required") }}</h4>
<p>This file type ({{ dataset.file_ext }}) will download automatically when accessed directly.</p> <p>此文件类型({{ dataset.file_ext }})在直接访问时会自动下载。</p>
<p>{{ localize("File size:") }} <strong v-html="bytesToString(dataset.file_size || 0, false)" /></p> <p>{{ localize("File size:") }} <strong v-html="bytesToString(dataset.file_size || 0, false)" /></p>
<a :href="downloadUrl" class="btn btn-primary mt-2" download> <a :href="downloadUrl" class="btn btn-primary mt-2" download>
<FontAwesomeIcon :icon="faFileAlt" class="mr-1" /> {{ localize("Download File") }} <FontAwesomeIcon :icon="faFileAlt" class="mr-1" /> {{ localize("Download File") }}
...@@ -234,7 +234,7 @@ watch( ...@@ -234,7 +234,7 @@ watch(
<div v-if="isAutoDownloadType && !isPdfDataset" class="auto-download-message p-4"> <div v-if="isAutoDownloadType && !isPdfDataset" class="auto-download-message p-4">
<div class="alert alert-info"> <div class="alert alert-info">
<h4>{{ localize("Download Required") }}</h4> <h4>{{ localize("Download Required") }}</h4>
<p>This file type ({{ dataset.file_ext }}) will download automatically when accessed directly.</p> <p>此文件类型({{ dataset.file_ext }})在直接访问时会自动下载。</p>
<p>{{ localize("File size:") }} <strong v-html="bytesToString(dataset.file_size || 0, false)" /></p> <p>{{ localize("File size:") }} <strong v-html="bytesToString(dataset.file_size || 0, false)" /></p>
<a :href="downloadUrl" class="btn btn-primary mt-2" download> <a :href="downloadUrl" class="btn btn-primary mt-2" download>
<FontAwesomeIcon :icon="faFileAlt" class="mr-1" /> {{ localize("Download File") }} <FontAwesomeIcon :icon="faFileAlt" class="mr-1" /> {{ localize("Download File") }}
......
...@@ -25,7 +25,7 @@ export function useDatasetTableActions(refreshList: () => Promise<void>) { ...@@ -25,7 +25,7 @@ export function useDatasetTableActions(refreshList: () => Promise<void>) {
try { try {
await historyStore.applyFilters(history_id, filters); await historyStore.applyFilters(history_id, filters);
} catch (error) { } catch (error) {
Toast.error("Failed to show dataset in history"); Toast.error("无法在历史记录中显示数据集");
} }
} }
...@@ -34,25 +34,25 @@ export function useDatasetTableActions(refreshList: () => Promise<void>) { ...@@ -34,25 +34,25 @@ export function useDatasetTableActions(refreshList: () => Promise<void>) {
try { try {
if (!currentHistoryId.value) { if (!currentHistoryId.value) {
throw new Error("No current history found."); throw new Error("未找到当前历史记录。");
} }
await copyDataset(dataset_id, currentHistoryId.value); await copyDataset(dataset_id, currentHistoryId.value);
historyStore.loadCurrentHistory(); historyStore.loadCurrentHistory();
await refreshList(); await refreshList();
Toast.success(`Dataset "${item.name}" copied to current history.`); Toast.success(`数据集“${item.name}”已复制到当前历史记录。`);
} catch (error) { } catch (error) {
Toast.error("Failed to copy dataset"); Toast.error("无法复制数据集");
} }
} }
async function confirmDeleteDataset(item: HDASummary, purge: boolean) { async function confirmDeleteDataset(item: HDASummary, purge: boolean) {
const confirmed = await confirm( const confirmed = await confirm(
`Are you sure you want to ${purge ? "purge" : "delete"} the dataset "${item.name}"?`, `确定要${purge ? "永久删除" : "删除"}数据集“${item.name}”吗?`,
{ {
title: purge ? "Purge Dataset" : "Delete Dataset", title: purge ? "永久删除数据集" : "删除数据集",
okTitle: purge ? "Purge" : "Delete", okTitle: purge ? "永久删除" : "删除",
okVariant: "danger", okVariant: "danger",
}, },
); );
...@@ -61,11 +61,11 @@ export function useDatasetTableActions(refreshList: () => Promise<void>) { ...@@ -61,11 +61,11 @@ export function useDatasetTableActions(refreshList: () => Promise<void>) {
try { try {
await deleteDataset(item.id, purge); await deleteDataset(item.id, purge);
Toast.success(`Dataset "${item.name}" ${purge ? "purged" : "deleted"}.`); Toast.success(`数据集“${item.name}”已${purge ? "永久删除" : "删除"}。`);
historyStore.loadCurrentHistory(); historyStore.loadCurrentHistory();
await refreshList(); await refreshList();
} catch (error) { } catch (error) {
Toast.error(`Failed to ${purge ? "purge" : "delete"} dataset.`); Toast.error(`无法${purge ? "永久删除" : "删除"}数据集。`);
} }
} }
} }
...@@ -81,29 +81,29 @@ export function useDatasetTableActions(refreshList: () => Promise<void>) { ...@@ -81,29 +81,29 @@ export function useDatasetTableActions(refreshList: () => Promise<void>) {
const datasetTableActions: TableAction[] = [ const datasetTableActions: TableAction[] = [
{ {
id: "copy-dataset", id: "copy-dataset",
label: "Copy to current history", label: "复制到当前历史记录",
title: "Copy Dataset to current history", title: "将数据集复制到当前历史记录",
icon: faCopy, icon: faCopy,
handler: onCopyDataset, handler: onCopyDataset,
}, },
{ {
id: "show-dataset", id: "show-dataset",
label: "Show in history", label: "在历史记录中显示",
title: "Show dataset in history panel", title: "在历史记录面板中显示数据集",
icon: faEye, icon: faEye,
handler: onShowDataset, handler: onShowDataset,
}, },
{ {
id: "delete-dataset", id: "delete-dataset",
label: "Delete", label: "删除",
title: "Delete dataset", title: "删除数据集",
icon: faTrash, icon: faTrash,
handler: onDeleteDataset, handler: onDeleteDataset,
}, },
{ {
id: "purge-dataset", id: "purge-dataset",
label: "Purge", label: "永久删除",
title: "Purge dataset", title: "永久删除数据集",
icon: faFire, icon: faFire,
handler: onPurgeDataset, handler: onPurgeDataset,
}, },
......
...@@ -126,7 +126,7 @@ onUnmounted(() => { ...@@ -126,7 +126,7 @@ onUnmounted(() => {
</span> </span>
<div v-if="dataset.peek"> <div v-if="dataset.peek">
<Heading id="dataset-peek-heading" h2 separator inline size="md"> Dataset Peek </Heading> <Heading id="dataset-peek-heading" h2 separator inline size="md"> 数据集预览 </Heading>
<div class="dataset-peek" v-html="dataset.peek" /> <div class="dataset-peek" v-html="dataset.peek" />
</div> </div>
...@@ -141,8 +141,7 @@ onUnmounted(() => { ...@@ -141,8 +141,7 @@ onUnmounted(() => {
<h2 class="h-md">未找到作业</h2> <h2 class="h-md">未找到作业</h2>
<p> <p>
No job associated with this dataset is recorded in Galaxy. Galaxy cannot determine full dataset Galaxy 中没有记录与此数据集关联的作业。Galaxy 无法确定此数据集的完整来源和历史记录。
provenance and history for this dataset.
</p> </p>
</div> </div>
</div> </div>
......
...@@ -93,14 +93,14 @@ async function updateExports() { ...@@ -93,14 +93,14 @@ async function updateExports() {
waitForTask(mostUpToDateExport.value.taskUUID); waitForTask(mostUpToDateExport.value.taskUUID);
} }
if (taskMonitorRequestFailed.value) { if (taskMonitorRequestFailed.value) {
exportErrorMessage.value = "The request to get the export progress failed. Please check back later."; exportErrorMessage.value = "获取导出进度的请求失败,请稍后查看。";
} }
if (taskHasFailed.value) { if (taskHasFailed.value) {
exportErrorMessage.value = "The history export request failed. Please try again later."; exportErrorMessage.value = "历史记录导出请求失败,请稍后重试。";
} }
} }
} catch (e) { } catch (e) {
exportErrorMessage.value = "The request to get your history exports records failed. Please check back later."; exportErrorMessage.value = "获取您历史记录导出记录列表的请求失败,请稍后查看。";
} }
} }
...@@ -122,7 +122,7 @@ async function doExportToFileSource(exportDirectory: string, fileName: string) { ...@@ -122,7 +122,7 @@ async function doExportToFileSource(exportDirectory: string, fileName: string) {
try { try {
await exportHistoryToFileSource(props.history.id, exportDirectory, fileName, DEFAULT_EXPORT_PARAMS); await exportHistoryToFileSource(props.history.id, exportDirectory, fileName, DEFAULT_EXPORT_PARAMS);
} catch (error) { } catch (error) {
exportErrorMessage.value = "The history export request failed. Please try again later."; exportErrorMessage.value = "历史记录导出请求失败,请稍后重试。";
} }
updateExports(); updateExports();
} }
...@@ -137,15 +137,14 @@ function onArchiveHistoryWithExport() { ...@@ -137,15 +137,14 @@ function onArchiveHistoryWithExport() {
<template> <template>
<div> <div>
<p> <p>
If you are not planning to use this history in the near future, you can 如果您近期不打算使用此历史记录,可以
<b>archive and delete its contents to free up disk space</b>. <b>归档并删除其内容以释放磁盘空间</b>。
</p> </p>
<p> <p>
To be able to recreate your archived history later, you need to export it first to a permanent remote 为了日后能重建已归档的历史记录,您需要先将其导出到永久远程位置。之后您可以从远程来源将历史记录作为新副本重新导入 Galaxy。
location. Then you will be able to import it back to Galaxy from the remote source, as a new copy.
</p> </p>
<BAlert v-if="isLoading" show variant="info"> <BAlert v-if="isLoading" show variant="info">
<LoadingSpan message="Retrieving export records..." /> <LoadingSpan message="正在获取导出记录…" />
</BAlert> </BAlert>
<BAlert v-else-if="exportErrorMessage" show variant="danger"> <BAlert v-else-if="exportErrorMessage" show variant="danger">
<p> <p>
...@@ -159,44 +158,39 @@ function onArchiveHistoryWithExport() { ...@@ -159,44 +158,39 @@ function onArchiveHistoryWithExport() {
<b>此历史已有最新的导出记录可用。</b> <b>此历史已有最新的导出记录可用。</b>
</p> </p>
<p> <p>
This export record will be associated with your archived history so you can recreate it later by 此导出记录将与您的已归档历史记录关联,以便您之后通过导入来重建它。
importing it.
</p> </p>
<ExportRecordCard id="export-record-ready" class="mt-3" :export-record="mostUpToDateExport" /> <ExportRecordCard id="export-record-ready" class="mt-3" :export-record="mostUpToDateExport" />
</BAlert> </BAlert>
</div> </div>
<div v-else> <div v-else>
<BAlert v-if="isExportingRecord" id="generating-export-record-alert" show variant="info"> <BAlert v-if="isExportingRecord" id="generating-export-record-alert" show variant="info">
<LoadingSpan message="Generating export record. This may take a while..." /> <LoadingSpan message="正在生成导出记录,这可能需要一些时间…" />
</BAlert> </BAlert>
<BAlert v-else show variant="info"> <BAlert v-else show variant="info">
<p> <p>
<b> <b>
There is no up-to-date export record of this history. You need to create a new export record to 此历史记录没有最新的导出记录。您需要创建新的导出记录,以便之后能重建历史记录。
be able to recreate the history later.
</b> </b>
</p> </p>
<p>Use the button below to create a new export record before archiving the history.</p> <p>在归档历史记录之前,请使用下方按钮创建新的导出记录。</p>
<BButton <BButton
id="create-export-record-btn" id="create-export-record-btn"
:disabled="!canCreateExportRecord" :disabled="!canCreateExportRecord"
variant="primary" variant="primary"
@click="onCreateExportRecord"> @click="onCreateExportRecord">
Create export record 创建导出记录
</BButton> </BButton>
</BAlert> </BAlert>
</div> </div>
<p v-if="!isDeleteContentsConfirmed" class="mt-3 mb-0"> <p v-if="!isDeleteContentsConfirmed" class="mt-3 mb-0">
To continue, you need to confirm that you want to delete the contents of the original history before you can 要继续,您需要使用下方复选框确认您希望删除原始历史记录的内容,然后才能归档它。如果您在上方创建了导出记录,之后可以通过从导出记录导入来重建历史记录。
archive it using the checkbox below. If you created an export record above, you will be able to recreate the
history later by importing it from the export record.
</p> </p>
<BFormCheckbox id="confirm-delete-checkbox" v-model="isDeleteContentsConfirmed" class="my-3"> <BFormCheckbox id="confirm-delete-checkbox" v-model="isDeleteContentsConfirmed" class="my-3">
<b>I am aware that the contents of the original history will be permanently deleted.</b> <b>我已知晓原始历史记录的内容将被永久删除。</b>
</BFormCheckbox> </BFormCheckbox>
<BAlert show variant="warning"> <BAlert show variant="warning">
Remember that you cannot undo this action. Once you archive and delete the history, you can only recover it 请注意,您无法撤销此操作。一旦归档并删除历史记录,您只能通过从导出记录中导入新副本的方式来恢复它。
by importing it as a new copy from the export record.
</BAlert> </BAlert>
<BButton <BButton
id="archive-history-btn" id="archive-history-btn"
...@@ -204,37 +198,30 @@ function onArchiveHistoryWithExport() { ...@@ -204,37 +198,30 @@ function onArchiveHistoryWithExport() {
:disabled="!canArchiveHistory" :disabled="!canArchiveHistory"
variant="primary" variant="primary"
@click="onArchiveHistoryWithExport"> @click="onArchiveHistoryWithExport">
Archive (and purge) history 归档(并清除)历史记录
</BButton> </BButton>
<BModal v-model="isExportDialogOpen" title="Export history to permanent storage" size="lg" hide-footer> <BModal v-model="isExportDialogOpen" title="将历史记录导出到永久存储" size="lg" hide-footer>
<GTabs card vertical lazy class="export-option-tabs"> <GTabs card vertical lazy class="export-option-tabs">
<GTab id="to-remote-file-tab" title="To Repository" active> <GTab id="to-remote-file-tab" title="导出到仓库" active>
<p> <p>
<b>正在导出到仓库</b> will create a compressed archive of the history contents, copy <b>正在导出到仓库</b> 将创建历史记录内容的压缩归档,将其复制到远程位置(例如 FTP 服务器),并创建包含这些信息的导出记录,该记录将与已归档的历史记录关联。之后您可以通过从导出记录导入来重建历史记录。
it to a remote location (e.g. an FTP server) and create an export record with this information
that will be associated with the archived history. You will be able to recreate the history
later by importing it from the export record.
</p> </p>
<ExportToFileSourceForm what="history" @export="doExportToFileSourceWithPrefix" /> <ExportToFileSourceForm what="history" @export="doExportToFileSourceWithPrefix" />
</GTab> </GTab>
<GTab id="to-rdm-repository-tab" title="To RDM Repository"> <GTab id="to-rdm-repository-tab" title="导出到 RDM 仓库">
<p> <p>
<b>正在导出到 RDM 仓库</b> (e.g. any <b>正在导出到 RDM 仓库</b>(例如任何
<ExternalLink href="https://inveniosoftware.org/products/rdm/"> Invenio RDM </ExternalLink> <ExternalLink href="https://inveniosoftware.org/products/rdm/"> Invenio RDM </ExternalLink>
compatible repository) will require to create or select an existing record in the repository 兼容的仓库)将要求在仓库中创建或选择一个现有记录,用于上传历史归档。导出记录将与已归档的历史记录关联,之后您可以通过从导出记录导入来重建历史记录。
where the history archive will be uploaded. The export record will be associated with the
archived history and you will be able to recreate the history later by importing it from the
export record.
</p> </p>
<p> <p>
You may need to setup your credentials for the selected repository in your 您可能需要先在您的
<RouterLink to="/user/information" target="_blank">settings page</RouterLink> to be able to <RouterLink to="/user/information" target="_blank">设置页面</RouterLink> 中为所选仓库配置凭据,才能导出。
export.
</p> </p>
<ExportToRDMRepositoryForm <ExportToRDMRepositoryForm
what="history" what="history"
:default-filename="historyName + ' (Galaxy History)'" :default-filename="historyName + ' (Galaxy 历史记录)'"
:default-record-name="historyName" :default-record-name="historyName"
@export="doExportToFileSource" /> @export="doExportToFileSource" />
</GTab> </GTab>
......
...@@ -11,20 +11,18 @@ function onArchiveHistory() { ...@@ -11,20 +11,18 @@ function onArchiveHistory() {
<template> <template>
<div> <div>
<p> <p>
If you want to remove the history from your <i>active</i> histories but keep it around for reference, you 如果您想将历史记录从您的<i>活动</i>历史记录中移除但保留以便参考,可以点击下方按钮将其移动到
can move it to the <b>{{ localize("Archived Histories") }}</b> section, by clicking the button below. <b>{{ localize("Archived Histories") }}</b> 部分。
</p> </p>
<p> <p>
This is particularly useful if you have a lot of histories and want to keep the list of 如果您有很多历史记录、希望保持<i>活动</i>历史记录列表简洁,或者发布了一个历史记录并希望避免对其产生意外更改,此功能尤其有用。
<i>active</i> histories short or if you publish a history and want to avoid accidental changes to it.
</p> </p>
<p> <p>
You can undo this action at any time, and the history will be moved back to your 您可以随时撤销此操作,历史记录将被移回您的<i>活动</i>历史记录。
<i>active</i> histories.
</p> </p>
<BButton class="archive-history-btn mt-3" variant="primary" @click="onArchiveHistory"> <BButton class="archive-history-btn mt-3" variant="primary" @click="onArchiveHistory">
Archive history 归档历史记录
</BButton> </BButton>
</div> </div>
</template> </template>
...@@ -90,18 +90,18 @@ const breadcrumbItems = computed(() => [ ...@@ -90,18 +90,18 @@ const breadcrumbItems = computed(() => [
</BAlert> </BAlert>
<div v-else-if="history"> <div v-else-if="history">
<BAlert show variant="info"> <BAlert show variant="info">
Archiving a history will remove it from your <i>active histories</i>. You can still access it from the 归档历史记录会将其从您的<i>活动历史记录</i>中移除。您仍可从
<RouterLink :to="archivedHistoriesRoute">{{ localize("Archived Histories") }}</RouterLink> section. <RouterLink :to="archivedHistoriesRoute">{{ localize("Archived Histories") }}</RouterLink> 部分访问它。
</BAlert> </BAlert>
<div v-if="canFreeStorage"> <div v-if="canFreeStorage">
<h2 class="h-md">How do you want to archive this history?</h2> <h2 class="h-md">您希望如何归档此历史记录?</h2>
<BCard no-body class="mt-3"> <BCard no-body class="mt-3">
<GTabs pills card vertical lazy class="archival-option-tabs"> <GTabs pills card vertical lazy class="archival-option-tabs">
<GTab id="keep-storage-tab" title="Keep storage space" active> <GTab id="keep-storage-tab" title="保留存储空间" active>
<HistoryArchiveSimple :history="history" @onArchive="onArchiveHistory" /> <HistoryArchiveSimple :history="history" @onArchive="onArchiveHistory" />
</GTab> </GTab>
<GTab id="free-storage-tab" title="Free storage space"> <GTab id="free-storage-tab" title="释放存储空间">
<HistoryArchiveExportSelector :history="history" @onArchive="onArchiveHistory" /> <HistoryArchiveExportSelector :history="history" @onArchive="onArchiveHistory" />
</GTab> </GTab>
</GTabs> </GTabs>
......
...@@ -347,7 +347,7 @@ function unexpandedClick(event: Event) { ...@@ -347,7 +347,7 @@ function unexpandedClick(event: Event) {
v-b-tooltip.hover v-b-tooltip.hover
variant="link" variant="link"
class="p-0" class="p-0"
title="Input" title="输入"
@click.stop="toggleHighlights"> @click.stop="toggleHighlights">
<FontAwesomeIcon class="text-info" :icon="faArrowCircleUp" /> <FontAwesomeIcon class="text-info" :icon="faArrowCircleUp" />
</BButton> </BButton>
...@@ -356,7 +356,7 @@ function unexpandedClick(event: Event) { ...@@ -356,7 +356,7 @@ function unexpandedClick(event: Event) {
v-b-tooltip.hover v-b-tooltip.hover
variant="link" variant="link"
class="p-0" class="p-0"
title="Inputs/Outputs highlighted for this item" title="为此项目高亮显示输入/输出"
@click.stop="toggleHighlights" @click.stop="toggleHighlights"
@keypress="toggleHighlights"> @keypress="toggleHighlights">
<FontAwesomeIcon :icon="faCheckCircle" /> <FontAwesomeIcon :icon="faCheckCircle" />
...@@ -366,7 +366,7 @@ function unexpandedClick(event: Event) { ...@@ -366,7 +366,7 @@ function unexpandedClick(event: Event) {
v-b-tooltip.hover v-b-tooltip.hover
variant="link" variant="link"
class="p-0" class="p-0"
title="Output" title="输出"
@click.stop="toggleHighlights"> @click.stop="toggleHighlights">
<FontAwesomeIcon class="text-info" :icon="faArrowCircleDown" /> <FontAwesomeIcon class="text-info" :icon="faArrowCircleDown" />
</BButton> </BButton>
...@@ -381,15 +381,15 @@ function unexpandedClick(event: Event) { ...@@ -381,15 +381,15 @@ function unexpandedClick(event: Event) {
<span class="content-title name font-weight-bold">{{ name }}</span> <span class="content-title name font-weight-bold">{{ name }}</span>
</span> </span>
<span v-if="item.purged" class="ml-auto align-self-start btn-group p-1"> <span v-if="item.purged" class="ml-auto align-self-start btn-group p-1">
<BBadge variant="secondary" title="This dataset has been permanently deleted"> <BBadge variant="secondary" title="此数据集已被永久删除">
<FontAwesomeIcon :icon="faBurn" /> Purged <FontAwesomeIcon :icon="faBurn" /> 已清除
</BBadge> </BBadge>
</span> </span>
<span class="align-self-start btn-group"> <span class="align-self-start btn-group">
<BButton <BButton
v-if="item.sub_items?.length && !isSubItem" v-if="item.sub_items?.length && !isSubItem"
v-b-tooltip.hover v-b-tooltip.hover
title="Show converted items" title="显示已转换的项目"
tabindex="0" tabindex="0"
class="display-btn px-1 align-items-center" class="display-btn px-1 align-items-center"
size="sm" size="sm"
......
...@@ -170,13 +170,13 @@ function onDisplay($event: MouseEvent) { ...@@ -170,13 +170,13 @@ function onDisplay($event: MouseEvent) {
<template v-slot:button-content> <template v-slot:button-content>
<FontAwesomeIcon :icon="faTrash" /> <FontAwesomeIcon :icon="faTrash" />
</template> </template>
<b-dropdown-item title="Delete collection only" @click.prevent.stop="onDeleteItem"> <b-dropdown-item title="仅删除集合" @click.prevent.stop="onDeleteItem">
<FontAwesomeIcon :icon="faFile" /> <FontAwesomeIcon :icon="faFile" />
Collection only 仅集合
</b-dropdown-item> </b-dropdown-item>
<b-dropdown-item title="Delete collection and elements" @click.prevent.stop="onDeleteItemRecursively"> <b-dropdown-item title="删除集合及其元素" @click.prevent.stop="onDeleteItemRecursively">
<FontAwesomeIcon :icon="faCopy" /> <FontAwesomeIcon :icon="faCopy" />
Collection and elements 集合及其元素
</b-dropdown-item> </b-dropdown-item>
</BDropdown> </BDropdown>
</BButton> </BButton>
......
...@@ -99,7 +99,7 @@ function onRerun() { ...@@ -99,7 +99,7 @@ function onRerun() {
v-if="showError" v-if="showError"
v-b-tooltip.hover v-b-tooltip.hover
class="px-1" class="px-1"
title="Error" title="错误"
size="sm" size="sm"
variant="link" variant="link"
:href="reportErrorUrl" :href="reportErrorUrl"
...@@ -113,7 +113,7 @@ function onRerun() { ...@@ -113,7 +113,7 @@ function onRerun() {
v-if="showDownloads" v-if="showDownloads"
v-b-tooltip.hover v-b-tooltip.hover
class="px-1" class="px-1"
title="Copy Link" title="复制链接"
size="sm" size="sm"
variant="link" variant="link"
@click.stop="onCopyLink"> @click.stop="onCopyLink">
...@@ -124,7 +124,7 @@ function onRerun() { ...@@ -124,7 +124,7 @@ function onRerun() {
v-if="showInfo" v-if="showInfo"
v-b-tooltip.hover v-b-tooltip.hover
class="info-btn px-1" class="info-btn px-1"
title="Dataset Details" title="数据集详情"
size="sm" size="sm"
variant="link" variant="link"
:href="showDetailsUrl" :href="showDetailsUrl"
...@@ -136,7 +136,7 @@ function onRerun() { ...@@ -136,7 +136,7 @@ function onRerun() {
v-if="showVisualizations" v-if="showVisualizations"
v-b-tooltip.hover v-b-tooltip.hover
class="visualize-btn px-1" class="visualize-btn px-1"
title="Visualize" title="可视化"
size="sm" size="sm"
variant="link" variant="link"
:href="visualizeUrl" :href="visualizeUrl"
...@@ -148,7 +148,7 @@ function onRerun() { ...@@ -148,7 +148,7 @@ function onRerun() {
v-if="showHighlight" v-if="showHighlight"
v-b-tooltip.hover v-b-tooltip.hover
class="highlight-btn px-1" class="highlight-btn px-1"
title="Show Related Items" title="显示相关项目"
size="sm" size="sm"
variant="link" variant="link"
@click.stop="onHighlight"> @click.stop="onHighlight">
...@@ -159,7 +159,7 @@ function onRerun() { ...@@ -159,7 +159,7 @@ function onRerun() {
v-if="writable && showRerun" v-if="writable && showRerun"
v-b-tooltip.hover v-b-tooltip.hover
class="rerun-btn px-1" class="rerun-btn px-1"
title="Run Job Again" title="重新运行作业"
size="sm" size="sm"
variant="link" variant="link"
:href="rerunUrl" :href="rerunUrl"
......
...@@ -60,7 +60,7 @@ function onDownload(resource: string, extension = "") { ...@@ -60,7 +60,7 @@ function onDownload(resource: string, extension = "") {
:data-description="`download ${metaFile.file_type}`" :data-description="`download ${metaFile.file_type}`"
:href="metaDownloadUrl + metaFile.file_type" :href="metaDownloadUrl + metaFile.file_type"
@click.prevent.stop="onDownload(metaDownloadUrl, metaFile.file_type)"> @click.prevent.stop="onDownload(metaDownloadUrl, metaFile.file_type)">
Download {{ metaFile.file_type }} 下载 {{ metaFile.file_type }}
</BDropdownItem> </BDropdownItem>
</BDropdown> </BDropdown>
...@@ -68,7 +68,7 @@ function onDownload(resource: string, extension = "") { ...@@ -68,7 +68,7 @@ function onDownload(resource: string, extension = "") {
v-else v-else
v-b-tooltip.hover v-b-tooltip.hover
class="download-btn px-1" class="download-btn px-1"
title="Download" title="下载"
size="sm" size="sm"
variant="link" variant="link"
:href="downloadUrl" :href="downloadUrl"
......
...@@ -37,26 +37,20 @@ function showHelp() { ...@@ -37,26 +37,20 @@ function showHelp() {
<template> <template>
<div class="info"> <div class="info">
<b-modal v-if="sharingError" v-model="showErrorHelp" title="Dataset Sharing Misconfigured" ok-only> <b-modal v-if="sharingError" v-model="showErrorHelp" title="数据集共享配置错误" ok-only>
<p> <p>
This error message indicates that your history is setup to allow sharing but your job was run in a 此错误消息表示您的历史记录设置为允许共享,但您的作业运行在目标 Galaxy 存储显式禁用共享的配置下。
configuration to target a Galaxy storage that explicitly disables sharing.
</p> </p>
<p> <p>
To fix this configure your history so that new datasets are private or target a different storage 要修复此问题,请将历史记录配置为新数据集为私有,或指定不同的存储位置。
location.
</p> </p>
<p> <p>
To re-configure your history, click the history menu and go to the "Set Permissions" option in the 要重新配置历史记录,请点击历史记录菜单,在下拉菜单中选择“设置权限”选项。这应出现一个开关,允许您将历史记录配置为将新数据集创建为私有数据集。
dropdown. This should result in a toggle that allows you to configure the history so that new datasets
are created as private datasets.
</p> </p>
<p> <p>
There are many ways to instead target different storage for your job. This can be selected in the tool 有多种方式可以为您的作业指定不同的存储。您可以在执行作业前的工具或工作流表单中选择,或为历史记录或用户选择允许共享的不同默认值。
or workflow form right before you execute your job or a different default for your history or user can
be chosen that allows for sharing.
</p> </p>
</b-modal> </b-modal>
<span class="value">{{ miscInfo }} <a v-if="fixable" href="#" @click="showHelp">How do I fix this?</a></span> <span class="value">{{ miscInfo }} <a v-if="fixable" href="#" @click="showHelp">如何修复此问题?</a></span>
</div> </div>
</template> </template>
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
v-slot="{ result: item, loading }" v-slot="{ result: item, loading }"
:view="view" :view="view"
auto-refresh> auto-refresh>
<LoadingSpan v-if="loading" message="Loading dataset" /> <LoadingSpan v-if="loading" message="正在加载数据集" />
<div v-else> <div v-else>
<ContentItem <ContentItem
:id="item.hid ?? item.element_index + 1" :id="item.hid ?? item.element_index + 1"
......
...@@ -421,7 +421,7 @@ const { ...@@ -421,7 +421,7 @@ const {
:key="props.history.id" :key="props.history.id"
class="content-operations-filters mx-3" class="content-operations-filters mx-3"
name="History Items" name="History Items"
placeholder="search datasets" placeholder="搜索数据集"
:filter-class="filterClass" :filter-class="filterClass"
:filter-text.sync="filterText" :filter-text.sync="filterText"
:loading="isLoading" :loading="isLoading"
...@@ -489,22 +489,22 @@ const { ...@@ -489,22 +489,22 @@ const {
<div class="h-100"> <div class="h-100">
<div v-if="isLoading && historyItems && historyItems.length === 0"> <div v-if="isLoading && historyItems && historyItems.length === 0">
<BAlert class="m-2" variant="info" show> <BAlert class="m-2" variant="info" show>
<LoadingSpan message="Loading History" /> <LoadingSpan message="正在加载历史记录" />
</BAlert> </BAlert>
</div> </div>
<BAlert v-else-if="isProcessing" class="m-2" variant="info" show> <BAlert v-else-if="isProcessing" class="m-2" variant="info" show>
<LoadingSpan message="Processing operation" /> <LoadingSpan message="正在处理操作" />
</BAlert> </BAlert>
<div v-else-if="historyItems.length === 0"> <div v-else-if="historyItems.length === 0">
<HistoryEmpty v-if="queryDefault" :writable="canEditHistory" class="m-2" /> <HistoryEmpty v-if="queryDefault" :writable="canEditHistory" class="m-2" />
<BAlert v-else-if="formattedSearchError" class="m-2" variant="danger" show> <BAlert v-else-if="formattedSearchError" class="m-2" variant="danger" show>
Error in filter: 筛选出错:
<a href="javascript:void(0)" @click="showAdvanced = true"> <a href="javascript:void(0)" @click="showAdvanced = true">
{{ formattedSearchError.filter }}'{{ formattedSearchError.value }}' {{ formattedSearchError.filter }}'{{ formattedSearchError.value }}'
</a> </a>
</BAlert> </BAlert>
<BAlert v-else class="m-2" variant="info" show> No data found for selected filter. </BAlert> <BAlert v-else class="m-2" variant="info" show> 所选筛选条件下未找到数据。 </BAlert>
</div> </div>
<ListingLayout <ListingLayout
v-else v-else
......
...@@ -194,7 +194,7 @@ function downloadFromRecord(record: ExportRecord) { ...@@ -194,7 +194,7 @@ function downloadFromRecord(record: ExportRecord) {
function copyDownloadLinkFromRecord(record: ExportRecord) { function copyDownloadLinkFromRecord(record: ExportRecord) {
if (record.canDownload) { if (record.canDownload) {
const relativeLink = getDownloadObjectUrl(record.stsDownloadId!); const relativeLink = getDownloadObjectUrl(record.stsDownloadId!);
sendToClipboard(absPath(relativeLink), "Download link copied to your clipboard"); sendToClipboard(absPath(relativeLink), "下载链接已复制到剪贴板");
} }
} }
...@@ -206,8 +206,7 @@ async function reimportFromRecord(record: ExportRecord) { ...@@ -206,8 +206,7 @@ async function reimportFromRecord(record: ExportRecord) {
try { try {
await reimportHistoryFromRecord(record); await reimportHistoryFromRecord(record);
actionMessageVariant.value = "info"; actionMessageVariant.value = "info";
actionMessage.value = actionMessage.value = "历史记录正在后台导入。请稍后在您的历史记录中查找它。";
"The history is being imported in the background. Check your histories after a while to find it.";
} catch (error) { } catch (error) {
actionMessageVariant.value = "danger"; actionMessageVariant.value = "danger";
actionMessage.value = errorMessageAsString(error); actionMessage.value = errorMessageAsString(error);
...@@ -236,7 +235,7 @@ const breadcrumbItems = computed(() => [ ...@@ -236,7 +235,7 @@ const breadcrumbItems = computed(() => [
to: `/histories/view?id=${props.historyId}`, to: `/histories/view?id=${props.historyId}`,
superText: historyStore.currentHistoryId === props.historyId ? "current" : undefined, superText: historyStore.currentHistoryId === props.historyId ? "current" : undefined,
}, },
{ title: "Export", icon: faFileExport }, { title: "导出", icon: faFileExport },
]); ]);
</script> </script>
...@@ -287,7 +286,7 @@ const breadcrumbItems = computed(() => [ ...@@ -287,7 +286,7 @@ const breadcrumbItems = computed(() => [
<GModal <GModal
:show.sync="showOldRecords" :show.sync="showOldRecords"
:title="`Previous Export Records for ${historyName}`" :title="`${historyName} 的先前导出记录`"
size="medium" size="medium"
hide-header hide-header
fixed-height fixed-height
......
...@@ -81,20 +81,20 @@ const emit = defineEmits<{ ...@@ -81,20 +81,20 @@ const emit = defineEmits<{
const errorMessage = ref<string>(); const errorMessage = ref<string>();
const exportData: HistoryExportData = reactive(initializeExportData()); const exportData: HistoryExportData = reactive(initializeExportData());
const defaultFileName = computed(() => `(Galaxy History) ${props.historyName}`); const defaultFileName = computed(() => `(Galaxy 历史记录) ${props.historyName}`);
const exportButtonLabel = computed(() => { const exportButtonLabel = computed(() => {
switch (exportData.destination) { switch (exportData.destination) {
case "download": case "download":
return "Generate Download Link"; return "生成下载链接";
case "remote-source": case "remote-source":
return "Export to Remote Source"; return "导出到远程源";
case "rdm-repository": case "rdm-repository":
return "Export to RDM Repository"; return "导出到 RDM 仓库";
case "zenodo-repository": case "zenodo-repository":
return "Export to Zenodo"; return "导出到 Zenodo";
default: default:
return "Export"; return "导出";
} }
}); });
...@@ -126,42 +126,42 @@ const zenodoSource = computed(() => getZenodoSource()); ...@@ -126,42 +126,42 @@ const zenodoSource = computed(() => getZenodoSource());
const wizard = useWizard({ const wizard = useWizard({
"select-format": { "select-format": {
label: "Select output format", label: "选择输出格式",
instructions: computed(() => { instructions: computed(() => {
return `Select the format you would like to export the ${resource} to and click Next to continue.`; return `选择要将 ${resource} 导出成的格式,然后点击下一步继续。`;
}), }),
isValid: () => true, isValid: () => true,
isSkippable: () => false, isSkippable: () => false,
}, },
"select-destination": { "select-destination": {
label: "Select destination", label: "选择目的地",
instructions: computed(() => { instructions: computed(() => {
return `Select where you would like to export the ${resource} ${exportFormatName.value} to and click Next to continue.`; return `选择要将 ${resource} ${exportFormatName.value} 导出到的位置,然后点击下一步继续。`;
}), }),
isValid: () => true, isValid: () => true,
isSkippable: () => false, isSkippable: () => false,
}, },
"setup-remote": { "setup-remote": {
label: "Select remote source", label: "选择远程源",
instructions: "Select remote source directory", instructions: "选择远程源目录",
isValid: () => Boolean(exportData.remoteUri), isValid: () => Boolean(exportData.remoteUri),
isSkippable: () => exportData.destination !== "remote-source", isSkippable: () => exportData.destination !== "remote-source",
}, },
"setup-rdm": { "setup-rdm": {
label: "Select RDM repository", label: "选择 RDM 仓库",
instructions: "Select RDM repository and provide a draft record to export to", instructions: "选择 RDM 仓库并提供用于导出的草稿记录",
isValid: () => Boolean(exportData.remoteUri), isValid: () => Boolean(exportData.remoteUri),
isSkippable: () => exportData.destination !== "rdm-repository", isSkippable: () => exportData.destination !== "rdm-repository",
}, },
"setup-zenodo": { "setup-zenodo": {
label: "Select draft record", label: "选择草稿记录",
instructions: "Select or create a draft record to export to", instructions: "选择或创建一个用于导出的草稿记录",
isValid: () => Boolean(exportData.remoteUri), isValid: () => Boolean(exportData.remoteUri),
isSkippable: () => exportData.destination !== "zenodo-repository", isSkippable: () => exportData.destination !== "zenodo-repository",
}, },
"export-summary": { "export-summary": {
label: "Export", label: "导出",
instructions: "Summary", instructions: "摘要",
isValid: () => Boolean(exportData.outputFileName) || exportData.destination === "download", isValid: () => Boolean(exportData.outputFileName) || exportData.destination === "download",
isSkippable: () => false, isSkippable: () => false,
}, },
...@@ -201,31 +201,31 @@ function initializeExportDestinations(): ExportDestinationInfo[] { ...@@ -201,31 +201,31 @@ function initializeExportDestinations(): ExportDestinationInfo[] {
const destinations: ExportDestinationInfo[] = [ const destinations: ExportDestinationInfo[] = [
{ {
destination: "download", destination: "download",
label: "Temporary Direct Download", label: "临时直接下载",
markdownDescription: `Generate a link to the export file and download it directly to your computer. markdownDescription: `生成导出文件的链接并直接下载到您的计算机。
**Please note that the link will expire after 24 hours.**`, **请注意,链接将在 24 小时后过期。**`,
}, },
]; ];
if (hasWritableFileSources.value) { if (hasWritableFileSources.value) {
destinations.push({ destinations.push({
destination: "remote-source", destination: "remote-source",
label: "Repository", label: "仓库",
markdownDescription: `If you need a **more permanent** way of storing your ${resource} you can export it directly to one of the available repositories. You will be able to re-import it later as long as it remains available on the remote server. markdownDescription: `如果您需要**更持久**的方式来存储 ${resource},可以将其直接导出到可用的仓库之一。只要在远程服务器上仍可用,您之后就可以重新导入它。
Examples of remote sources include Amazon S3, Azure Storage, Google Drive... and other public or personal file sources that you have setup access to.`, 远程源的示例包括 Amazon S3、Azure 存储、Google Drive……以及您已配置访问权限的其他公共或个人文件源。`,
}); });
} }
if (hasWritableRDMFileSources.value) { if (hasWritableRDMFileSources.value) {
destinations.push({ destinations.push({
destination: "rdm-repository", destination: "rdm-repository",
label: "RDM Repository", label: "RDM 仓库",
markdownDescription: `You can upload your ${resource} to one of the available **Research Data Management repositories** here. markdownDescription: `您可以在此将 ${resource} 上传到可用的**研究数据管理仓库**之一。
This will allow you to easily associate your ${resource} with your research project or publication. 这样您可以轻松地将 ${resource} 与您的研究项目或出版物关联。
Examples of RDM repositories include [Invenio RDM](https://inveniosoftware.org/products/rdm/) instances, [RSpace](https://www.researchspace.com/), and other public or personal repositories that you have setup access to.`, RDM 仓库的示例包括 [Invenio RDM](https://inveniosoftware.org/products/rdm/) 实例、[RSpace](https://www.researchspace.com/),以及您已配置访问权限的其他公共或个人仓库。`,
}); });
} }
...@@ -235,7 +235,7 @@ Examples of RDM repositories include [Invenio RDM](https://inveniosoftware.org/p ...@@ -235,7 +235,7 @@ Examples of RDM repositories include [Invenio RDM](https://inveniosoftware.org/p
label: `${zenodoSource.value.label}`, label: `${zenodoSource.value.label}`,
markdownDescription: `![Zenodo Logo](https://raw.githubusercontent.com/zenodo/zenodo/master/zenodo/modules/theme/static/img/logos/zenodo-gradient-square.svg) markdownDescription: `![Zenodo Logo](https://raw.githubusercontent.com/zenodo/zenodo/master/zenodo/modules/theme/static/img/logos/zenodo-gradient-square.svg)
[Zenodo](https://zenodo.org/) is a general-purpose open repository developed under the [European OpenAIRE](https://www.openaire.eu/) program and operated by [CERN](https://home.cern/). It allows researchers to deposit research papers, data sets, research software, reports, and any other research related digital artefacts. For each submission, a persistent **digital object identifier (DOI)** is minted, which makes the stored items easily citeable.`, [Zenodo](https://zenodo.org/) 是在 [European OpenAIRE](https://www.openaire.eu/) 计划下开发、由 [CERN](https://home.cern/) 运营的通用开放仓库。它允许研究人员存放研究论文、数据集、研究软件、报告以及任何其他与研究相关的数字制品。每次提交都会生成持久的**数字对象标识符(DOI)**,使存储的项目易于引用。`,
}); });
} }
...@@ -332,7 +332,7 @@ function resetWizard() { ...@@ -332,7 +332,7 @@ function resetWizard() {
<BFormGroup <BFormGroup
v-if="needsFileName" v-if="needsFileName"
label-for="exported-file-name" label-for="exported-file-name"
:description="`Give the exported file a name.`" :description="`为导出的文件命名。`"
class="mt-3"> class="mt-3">
<BFormInput <BFormInput
id="exported-file-name" id="exported-file-name"
...@@ -352,11 +352,11 @@ function resetWizard() { ...@@ -352,11 +352,11 @@ function resetWizard() {
<br /> <br />
<div> <div>
Format <b>{{ exportFormatName }}</b> 格式 <b>{{ exportFormatName }}</b>
</div> </div>
<div> <div>
Destination 目的地
<b>{{ exportDestinationSummary }}</b> <b>{{ exportDestinationSummary }}</b>
<b v-if="exportData.destination !== 'download' && exportData.remoteUri"> <b v-if="exportData.destination !== 'download' && exportData.remoteUri">
<FileSourceNameSpan :uri="exportData.remoteUri" class="text-primary" /> <FileSourceNameSpan :uri="exportData.remoteUri" class="text-primary" />
...@@ -364,7 +364,7 @@ function resetWizard() { ...@@ -364,7 +364,7 @@ function resetWizard() {
</div> </div>
<div v-if="needsFileName && exportData.outputFileName"> <div v-if="needsFileName && exportData.outputFileName">
File Name <b>{{ exportData.outputFileName }}.{{ exportData.modelStoreFormat }}</b> 文件名 <b>{{ exportData.outputFileName }}.{{ exportData.modelStoreFormat }}</b>
</div> </div>
</div> </div>
</GenericWizard> </GenericWizard>
......
...@@ -70,7 +70,7 @@ async function getCounts() { ...@@ -70,7 +70,7 @@ async function getCounts() {
contentsActive.value = counts.contents_active; contentsActive.value = counts.contents_active;
contentsStates.value = counts.contents_states; contentsStates.value = counts.contents_states;
} catch (e) { } catch (e) {
Toast.error(`Failed to load history counts: ${errorMessageAsString(e)}`); Toast.error(`无法加载历史记录统计:${errorMessageAsString(e)}`);
} finally { } finally {
loading.value = false; loading.value = false;
} }
...@@ -86,14 +86,14 @@ onMounted(async () => { ...@@ -86,14 +86,14 @@ onMounted(async () => {
v-b-tooltip.hover.top.noninteractive v-b-tooltip.hover.top.noninteractive
class="history-datasets d-flex flex-gapx-1 flex-gapy-1 align-items-center outline-badge cursor-pointer font-size-small" class="history-datasets d-flex flex-gapx-1 flex-gapy-1 align-items-center outline-badge cursor-pointer font-size-small"
pill pill
:title="`View history storage overview`" :title="`查看历史记录存储概览`"
variant="light" variant="light"
:to="`/storage/history/${historyId}`"> :to="`/storage/history/${historyId}`">
<FontAwesomeIcon v-if="loading" :icon="faSpinner" fixed-width spin /> <FontAwesomeIcon v-if="loading" :icon="faSpinner" fixed-width spin />
<template v-else> <template v-else>
<small v-if="props.count"> <small v-if="props.count">
<FontAwesomeIcon :icon="faDatabase" fixed-width /> <FontAwesomeIcon :icon="faDatabase" fixed-width />
<template v-if="props.count"> {{ props.count }} <span class="items">items</span> </template> <template v-if="props.count"> {{ props.count }} <span class="items">项</span> </template>
</small> </small>
<template v-if="props.count && niceSize"> | </template> <template v-if="props.count && niceSize"> | </template>
......
...@@ -82,7 +82,7 @@ const props = withDefaults(defineProps<Props>(), { ...@@ -82,7 +82,7 @@ const props = withDefaults(defineProps<Props>(), {
activeList: "my", activeList: "my",
}); });
const breadcrumbItems = [{ title: "Histories", to: "/histories/list" }]; const breadcrumbItems = [{ title: "历史记录", to: "/histories/list" }];
const router = useRouter(); const router = useRouter();
const userStore = useUserStore(); const userStore = useUserStore();
...@@ -117,19 +117,19 @@ const archivedView = computed(() => props.activeList === "archived"); ...@@ -117,19 +117,19 @@ const archivedView = computed(() => props.activeList === "archived");
* @returns {string} Contextual placeholder text for the search input * @returns {string} Contextual placeholder text for the search input
*/ */
const searchPlaceHolder = computed(() => { const searchPlaceHolder = computed(() => {
let placeHolder = "Search my histories"; let placeHolder = "搜索我的历史记录";
if (sharedView.value) { if (sharedView.value) {
placeHolder = "Search shared histories"; placeHolder = "搜索与我共享的历史记录";
} }
if (publishedView.value) { if (publishedView.value) {
placeHolder = "Search published histories"; placeHolder = "搜索公开的历史记录";
} }
if (archivedView.value) { if (archivedView.value) {
placeHolder = "Search archived histories"; placeHolder = "搜索已归档的历史记录";
} }
placeHolder += " by query or use the advanced filtering options"; placeHolder += ",可按条件查询或使用高级筛选选项";
return placeHolder; return placeHolder;
}); });
...@@ -141,7 +141,7 @@ const sortDesc = computed(() => (listHeader.value && listHeader.value.sortDesc) ...@@ -141,7 +141,7 @@ const sortDesc = computed(() => (listHeader.value && listHeader.value.sortDesc)
const sortBy = computed(() => (listHeader.value && listHeader.value.sortBy) || "update_time"); const sortBy = computed(() => (listHeader.value && listHeader.value.sortBy) || "update_time");
const noItems = computed(() => !loading.value && historiesLoaded.value.length === 0 && !filterText.value); const noItems = computed(() => !loading.value && historiesLoaded.value.length === 0 && !filterText.value);
const noResults = computed(() => !loading.value && historiesLoaded.value.length === 0 && Boolean(filterText.value)); const noResults = computed(() => !loading.value && historiesLoaded.value.length === 0 && Boolean(filterText.value));
const deleteButtonTitle = computed(() => (showDeleted.value ? "Hide deleted histories" : "Show deleted histories")); const deleteButtonTitle = computed(() => (showDeleted.value ? "隐藏已删除的历史记录" : "显示已删除的历史记录"));
const showBulkPurge = computed(() => selectedHistories.value.some((h) => !h.purged)); const showBulkPurge = computed(() => selectedHistories.value.some((h) => !h.purged));
const showBulkMultiview = computed(() => selectedHistories.value.length > 1); const showBulkMultiview = computed(() => selectedHistories.value.length > 1);
...@@ -265,7 +265,7 @@ async function load(overlayLoading: boolean = false, silent: boolean = false) { ...@@ -265,7 +265,7 @@ async function load(overlayLoading: boolean = false, silent: boolean = false) {
totalHistories.value = total; totalHistories.value = total;
} }
} catch (error) { } catch (error) {
Toast.error(`Failed to load histories: ${errorMessageAsString(error)}`); Toast.error(`无法加载历史记录:${errorMessageAsString(error)}`);
} finally { } finally {
loading.value = false; loading.value = false;
overlay.value = false; overlay.value = false;
...@@ -327,12 +327,12 @@ async function onBulkDeleteOrPurge(purge: boolean = false) { ...@@ -327,12 +327,12 @@ async function onBulkDeleteOrPurge(purge: boolean = false) {
const hasPublished = selectedHistories.value.some((h) => h.published); const hasPublished = selectedHistories.value.some((h) => h.published);
const confirmed = await confirm( const confirmed = await confirm(
`${hasPublished ? "Some of the selected histories are published and will be removed from public view. " : ""} `${hasPublished ? "所选历史记录中部分已公开,将从公共视图移除。 " : ""}
Are you sure you want to ${purge ? "purge" : "delete"} ${totalSelected} histories?`, 确定要${purge ? "永久删除" : "删除"} ${totalSelected} 个历史记录吗?`,
{ {
id: "bulk-delete-histories", id: "bulk-delete-histories",
title: purge ? "Purge histories" : "Delete histories", title: purge ? "永久删除历史记录" : "删除历史记录",
okTitle: purge ? "Purge histories" : "Delete histories", okTitle: purge ? "永久删除历史记录" : "删除历史记录",
okVariant: "danger", okVariant: "danger",
cancelVariant: "outline-primary", cancelVariant: "outline-primary",
centered: true, centered: true,
...@@ -360,11 +360,11 @@ async function onBulkDeleteOrPurge(purge: boolean = false) { ...@@ -360,11 +360,11 @@ async function onBulkDeleteOrPurge(purge: boolean = false) {
); );
} }
Toast.success(`${purge ? "Purged" : "Deleted"} ${totalSelected} histories.`); Toast.success(`${purge ? "已永久删除" : "已删除"} ${totalSelected} 个历史记录。`);
resetSelection(); resetSelection();
} catch (e) { } catch (e) {
Toast.error(`Failed to ${purge ? "purge" : "delete"} some histories.`); Toast.error(`无法${purge ? "永久删除" : "删除"}部分历史记录。`);
} finally { } finally {
bulkPurgeLoading.value = false; bulkPurgeLoading.value = false;
bulkDeleteOrRestoreLoading.value = false; bulkDeleteOrRestoreLoading.value = false;
...@@ -381,10 +381,10 @@ async function onBulkDeleteOrPurge(purge: boolean = false) { ...@@ -381,10 +381,10 @@ async function onBulkDeleteOrPurge(purge: boolean = false) {
async function onBulkRestore() { async function onBulkRestore() {
const totalSelected = selectedHistories.value.length; const totalSelected = selectedHistories.value.length;
const confirmed = await confirm(`Are you sure you want to restore ${totalSelected} histories?`, { const confirmed = await confirm(`确定要恢复 ${totalSelected} 个历史记录吗?`, {
id: "bulk-restore-histories", id: "bulk-restore-histories",
title: "Restore histories", title: "恢复历史记录",
okTitle: "Restore histories", okTitle: "恢复历史记录",
okVariant: "primary", okVariant: "primary",
cancelVariant: "outline-primary", cancelVariant: "outline-primary",
centered: true, centered: true,
...@@ -449,9 +449,9 @@ async function onBulkTagsAdd(tags: string[]) { ...@@ -449,9 +449,9 @@ async function onBulkTagsAdd(tags: string[]) {
); );
} }
Toast.success(`Added tag(s) to ${totalSelected} histories.`); Toast.success(`已为 ${totalSelected} 个历史记录添加标签。`);
} catch (e) { } catch (e) {
Toast.error(`Failed to add tag(s) to some histories. ${e}`); Toast.error(`无法为部分历史记录添加标签。 ${e}`);
} finally { } finally {
bulkTagsLoading.value = false; bulkTagsLoading.value = false;
...@@ -474,13 +474,13 @@ async function onBulkOpenInMultiview() { ...@@ -474,13 +474,13 @@ async function onBulkOpenInMultiview() {
if (selectedHistoriesCount > MULTIVIEW_MAX_HISTORIES) { if (selectedHistoriesCount > MULTIVIEW_MAX_HISTORIES) {
const confirmed = await confirm( const confirmed = await confirm(
`You have selected ${selectedHistoriesCount} histories to open in multiview. `您已选择 ${selectedHistoriesCount} 个历史记录在多视图面板中打开。
However, the maximum number of histories allowed in multiview is ${MULTIVIEW_MAX_HISTORIES}. 但是,多视图面板最多允许 ${MULTIVIEW_MAX_HISTORIES} 个历史记录。
Do you want to proceed with opening the first ${MULTIVIEW_MAX_HISTORIES} histories?`, 是否继续打开前 ${MULTIVIEW_MAX_HISTORIES} 个历史记录?`,
{ {
id: "bulk-open-multiview-histories", id: "bulk-open-multiview-histories",
title: `You can only open ${MULTIVIEW_MAX_HISTORIES} histories in multiview`, title: `在多视图面板中最多只能打开 ${MULTIVIEW_MAX_HISTORIES} 个历史记录`,
okTitle: "Proceed", okTitle: "继续",
okVariant: "primary", okVariant: "primary",
cancelVariant: "outline-primary", cancelVariant: "outline-primary",
centered: true, centered: true,
...@@ -503,9 +503,7 @@ async function onBulkOpenInMultiview() { ...@@ -503,9 +503,7 @@ async function onBulkOpenInMultiview() {
resetSelection(); resetSelection();
Toast.success( Toast.success(`已${totalSelectedHistories === 1 ? "在" : "在"}多视图面板中打开 ${totalSelectedHistories} 个历史记录。`);
`Opened ${totalSelectedHistories} ${totalSelectedHistories === 1 ? "history" : "histories"} in multiview.`,
);
} }
/** /**
...@@ -541,50 +539,50 @@ onMounted(async () => { ...@@ -541,50 +539,50 @@ onMounted(async () => {
to="/histories/import" to="/histories/import"
data-description="header action import new history"> data-description="header action import new history">
<FontAwesomeIcon :icon="faPlus" /> <FontAwesomeIcon :icon="faPlus" />
Import History 导入历史记录
</GButton> </GButton>
</BreadcrumbHeading> </BreadcrumbHeading>
<BNav pills justified class="mb-2"> <BNav pills justified class="mb-2">
<BNavItem id="histories-my-tab" :active="myView" :disabled="userStore.isAnonymous" to="/histories/list"> <BNavItem id="histories-my-tab" :active="myView" :disabled="userStore.isAnonymous" to="/histories/list">
My Histories 我的历史记录
<LoginRequired <LoginRequired
v-if="userStore.isAnonymous" v-if="userStore.isAnonymous"
target="histories-my-tab" target="histories-my-tab"
title="Manage your Histories" /> title="管理您的历史记录" />
</BNavItem> </BNavItem>
<BNavItem <BNavItem
id="histories-shared-tab" id="histories-shared-tab"
:active="sharedView" :active="sharedView"
:disabled="userStore.isAnonymous" :disabled="userStore.isAnonymous"
to="/histories/list_shared"> to="/histories/list_shared">
Histories Shared with Me 与我共享的历史记录
<LoginRequired <LoginRequired
v-if="userStore.isAnonymous" v-if="userStore.isAnonymous"
target="histories-shared-tab" target="histories-shared-tab"
title="View Shared Histories" /> title="查看共享的历史记录" />
</BNavItem> </BNavItem>
<BNavItem <BNavItem
id="histories-published-tab" id="histories-published-tab"
:active="publishedView" :active="publishedView"
:disabled="userStore.isAnonymous" :disabled="userStore.isAnonymous"
to="/histories/list_published"> to="/histories/list_published">
Public Histories 公开历史记录
<LoginRequired <LoginRequired
v-if="userStore.isAnonymous" v-if="userStore.isAnonymous"
target="histories-published-tab" target="histories-published-tab"
title="View Published Histories" /> title="查看公开的历史记录" />
</BNavItem> </BNavItem>
<BNavItem <BNavItem
id="histories-archived-tab" id="histories-archived-tab"
:active="archivedView" :active="archivedView"
:disabled="userStore.isAnonymous" :disabled="userStore.isAnonymous"
to="/histories/archived"> to="/histories/archived">
Archived Histories 已归档历史记录
<LoginRequired <LoginRequired
v-if="userStore.isAnonymous" v-if="userStore.isAnonymous"
target="histories-archived-tab" target="histories-archived-tab"
title="View Archived Histories" /> title="查看已归档的历史记录" />
</BNavItem> </BNavItem>
</BNav> </BNav>
...@@ -612,7 +610,7 @@ onMounted(async () => { ...@@ -612,7 +610,7 @@ onMounted(async () => {
@select-all="onSelectAllHistories"> @select-all="onSelectAllHistories">
<template v-slot:extra-filter> <template v-slot:extra-filter>
<div v-if="activeList === 'my'"> <div v-if="activeList === 'my'">
Filter: 筛选:
<BButton <BButton
id="show-deleted" id="show-deleted"
v-b-tooltip.hover v-b-tooltip.hover
...@@ -622,7 +620,7 @@ onMounted(async () => { ...@@ -622,7 +620,7 @@ onMounted(async () => {
variant="outline-primary" variant="outline-primary"
@click="onToggleDeleted"> @click="onToggleDeleted">
<FontAwesomeIcon :icon="faTrash" fixed-width /> <FontAwesomeIcon :icon="faTrash" fixed-width />
Show deleted 显示已删除
</BButton> </BButton>
</div> </div>
</template> </template>
...@@ -631,17 +629,17 @@ onMounted(async () => { ...@@ -631,17 +629,17 @@ onMounted(async () => {
<div v-if="loading" class="h-100"> <div v-if="loading" class="h-100">
<BAlert variant="info" show> <BAlert variant="info" show>
<LoadingSpan message="Loading histories" /> <LoadingSpan message="正在加载历史记录" />
</BAlert> </BAlert>
</div> </div>
<div v-else-if="!loading && !overlay && noItems" class="h-100"> <div v-else-if="!loading && !overlay && noItems" class="h-100">
<BAlert id="history-list-empty" variant="info" show> <BAlert id="history-list-empty" variant="info" show>
No histories found. You may create or import new histories using the buttons above. 未找到历史记录。您可以使用上方按钮创建或导入新的历史记录。
</BAlert> </BAlert>
</div> </div>
<span v-else-if="!loading && !overlay && (noResults || hasInvalidFilters)" class="h-100"> <span v-else-if="!loading && !overlay && (noResults || hasInvalidFilters)" class="h-100">
<BAlert v-if="!hasInvalidFilters" id="no-history-found" variant="info" show> <BAlert v-if="!hasInvalidFilters" id="no-history-found" variant="info" show>
No histories found matching: <span class="font-weight-bold">{{ filterText }}</span> 未找到匹配的历史记录:<span class="font-weight-bold">{{ filterText }}</span>
</BAlert> </BAlert>
<BAlert v-else id="no-history-found-invalid" variant="danger" show> <BAlert v-else id="no-history-found-invalid" variant="danger" show>
...@@ -652,13 +650,13 @@ onMounted(async () => { ...@@ -652,13 +650,13 @@ onMounted(async () => {
: {{ value }} : {{ value }}
</li> </li>
</ul> </ul>
<GLink @click="filterText = validatedFilterText()"> Remove invalid filters from query </GLink> <GLink @click="filterText = validatedFilterText()"> 从查询中移除无效筛选 </GLink>
or 或
<GLink <GLink
title="Note that this might produce inaccurate results" title="请注意,这可能会产生不准确的结果"
tooltip tooltip
@click="filterText = `'${filterText}'`"> @click="filterText = `'${filterText}'`">
Match the exact query provided 精确匹配所提供的内容
</GLink> </GLink>
</BAlert> </BAlert>
</span> </span>
...@@ -692,75 +690,75 @@ onMounted(async () => { ...@@ -692,75 +690,75 @@ onMounted(async () => {
v-if="!showDeleted" v-if="!showDeleted"
id="history-list-footer-bulk-delete-button" id="history-list-footer-bulk-delete-button"
v-b-tooltip.hover v-b-tooltip.hover
:title="bulkDeleteOrRestoreLoading ? 'Deleting histories' : 'Delete selected histories'" :title="bulkDeleteOrRestoreLoading ? '正在删除历史记录' : '删除选中的历史记录'"
:disabled="bulkDeleteOrRestoreLoading" :disabled="bulkDeleteOrRestoreLoading"
size="sm" size="sm"
variant="primary" variant="primary"
@click="() => onBulkDeleteOrPurge()"> @click="() => onBulkDeleteOrPurge()">
<span v-if="!bulkDeleteOrRestoreLoading"> <span v-if="!bulkDeleteOrRestoreLoading">
<FontAwesomeIcon :icon="faTrash" fixed-width /> <FontAwesomeIcon :icon="faTrash" fixed-width />
Delete ({{ selectedHistories.length }}) 删除({{ selectedHistories.length }})
</span> </span>
<LoadingSpan v-else message="Deleting" /> <LoadingSpan v-else message="正在删除" />
</BButton> </BButton>
<BButton <BButton
v-else v-else
id="history-list-footer-bulk-restore-button" id="history-list-footer-bulk-restore-button"
v-b-tooltip.hover v-b-tooltip.hover
:title="bulkDeleteOrRestoreLoading ? 'Restoring histories' : 'Restore selected histories'" :title="bulkDeleteOrRestoreLoading ? '正在恢复历史记录' : '恢复选中的历史记录'"
:disabled="bulkDeleteOrRestoreLoading" :disabled="bulkDeleteOrRestoreLoading"
size="sm" size="sm"
variant="primary" variant="primary"
@click="onBulkRestore"> @click="onBulkRestore">
<span v-if="!bulkDeleteOrRestoreLoading"> <span v-if="!bulkDeleteOrRestoreLoading">
<FontAwesomeIcon :icon="faTrashRestore" fixed-width /> <FontAwesomeIcon :icon="faTrashRestore" fixed-width />
Restore ({{ selectedHistories.length }}) 恢复({{ selectedHistories.length }})
</span> </span>
<LoadingSpan v-else message="Restoring" /> <LoadingSpan v-else message="正在恢复" />
</BButton> </BButton>
<BButton <BButton
v-if="showBulkPurge" v-if="showBulkPurge"
id="history-list-footer-bulk-purge-button" id="history-list-footer-bulk-purge-button"
v-b-tooltip.hover v-b-tooltip.hover
:title="bulkPurgeLoading ? 'Purging histories' : 'Purge selected histories'" :title="bulkPurgeLoading ? '正在永久删除历史记录' : '永久删除选中的历史记录'"
:disabled="bulkPurgeLoading" :disabled="bulkPurgeLoading"
size="sm" size="sm"
variant="primary" variant="primary"
@click="() => onBulkDeleteOrPurge(true)"> @click="() => onBulkDeleteOrPurge(true)">
<span v-if="!bulkPurgeLoading"> <span v-if="!bulkPurgeLoading">
<FontAwesomeIcon :icon="faBurn" fixed-width /> <FontAwesomeIcon :icon="faBurn" fixed-width />
Purge ({{ selectedHistories.length }}) 永久删除({{ selectedHistories.length }})
</span> </span>
<LoadingSpan v-else message="Purging" /> <LoadingSpan v-else message="正在永久删除" />
</BButton> </BButton>
<BButton <BButton
v-if="!showDeleted" v-if="!showDeleted"
id="history-list-footer-bulk-add-tags-button" id="history-list-footer-bulk-add-tags-button"
v-b-tooltip.hover v-b-tooltip.hover
:title="bulkTagsLoading ? 'Adding tags' : 'Add tags to selected histories'" :title="bulkTagsLoading ? '正在添加标签' : '为选中的历史记录添加标签'"
:disabled="bulkTagsLoading" :disabled="bulkTagsLoading"
size="sm" size="sm"
variant="primary" variant="primary"
@click="onToggleBulkTags"> @click="onToggleBulkTags">
<span v-if="!bulkTagsLoading"> <span v-if="!bulkTagsLoading">
<FontAwesomeIcon :icon="faTags" fixed-width /> <FontAwesomeIcon :icon="faTags" fixed-width />
Add tags ({{ selectedHistories.length }}) 添加标签({{ selectedHistories.length }})
</span> </span>
<LoadingSpan v-else message="Adding tags" /> <LoadingSpan v-else message="正在添加标签" />
</BButton> </BButton>
<BButton <BButton
v-if="showBulkMultiview" v-if="showBulkMultiview"
id="history-list-footer-bulk-open-multiview-button" id="history-list-footer-bulk-open-multiview-button"
v-b-tooltip.hover v-b-tooltip.hover
title="Open selected histories in multiview" title="在多视图面板中打开选中的历史记录"
size="sm" size="sm"
variant="primary" variant="primary"
@click="onBulkOpenInMultiview"> @click="onBulkOpenInMultiview">
<FontAwesomeIcon :icon="faColumns" fixed-width /> <FontAwesomeIcon :icon="faColumns" fixed-width />
Open in Multiview ({{ selectedHistories.length }}) 在多视图面板中打开({{ selectedHistories.length }})
</BButton> </BButton>
</div> </div>
...@@ -778,9 +776,7 @@ onMounted(async () => { ...@@ -778,9 +776,7 @@ onMounted(async () => {
<TagsSelectionDialog <TagsSelectionDialog
:show="showBulkAddTagsModal" :show="showBulkAddTagsModal"
:title="`Add tags to ${selectedHistories.length} selected history${ :title="`为 ${selectedHistories.length} 个选中的历史记录添加标签`"
selectedHistories.length > 1 ? 's' : ''
}`"
@cancel="onToggleBulkTags" @cancel="onToggleBulkTags"
@ok="onBulkTagsAdd" /> @ok="onBulkTagsAdd" />
</div> </div>
......
...@@ -112,7 +112,7 @@ function onDelete() { ...@@ -112,7 +112,7 @@ function onDelete() {
:variant="props.minimal ? 'outline-info' : 'link'" :variant="props.minimal ? 'outline-info' : 'link'"
toggle-class="text-decoration-none" toggle-class="text-decoration-none"
menu-class="history-options-button-menu" menu-class="history-options-button-menu"
title="History options" title="历史选项"
right right
data-description="history options"> data-description="history options">
<template v-slot:button-content> <template v-slot:button-content>
...@@ -121,8 +121,8 @@ function onDelete() { ...@@ -121,8 +121,8 @@ function onDelete() {
</template> </template>
<BDropdownText> <BDropdownText>
<LoadingSpan v-if="historiesLoading" message="Fetching histories from server" /> <LoadingSpan v-if="historiesLoading" message="正在从服务器获取历史记录" />
<span v-else-if="!props.minimal">You have {{ totalHistoryCount }} histories.</span> <span v-else-if="!props.minimal">您共有 {{ totalHistoryCount }} 个历史记录。</span>
<span v-else>管理历史</span> <span v-else>管理历史</span>
</BDropdownText> </BDropdownText>
...@@ -139,8 +139,8 @@ function onDelete() { ...@@ -139,8 +139,8 @@ function onDelete() {
<BDropdownDivider v-if="!props.minimal" /> <BDropdownDivider v-if="!props.minimal" />
<BDropdownText v-if="!canEditHistory"> <BDropdownText v-if="!canEditHistory">
This history has been <span class="font-weight-bold">{{ historyState }}</span 该历史记录已被 <span class="font-weight-bold">{{ historyState }}</span
>. >。
<span v-localize>某些操作可能不可用。</span> <span v-localize>某些操作可能不可用。</span>
</BDropdownText> </BDropdownText>
...@@ -233,7 +233,7 @@ function onDelete() { ...@@ -233,7 +233,7 @@ function onDelete() {
:title="userTitle('Share, Publish, or Set Permissions for this History')" :title="userTitle('Share, Publish, or Set Permissions for this History')"
:to="`/histories/sharing?id=${history.id}`"> :to="`/histories/sharing?id=${history.id}`">
<FontAwesomeIcon fixed-width :icon="faUsersCog" /> <FontAwesomeIcon fixed-width :icon="faUsersCog" />
<span v-localize>Share & Manage Access</span> <span v-localize>共享并管理访问权限</span>
</BDropdownItem> </BDropdownItem>
</BDropdown> </BDropdown>
...@@ -242,15 +242,15 @@ function onDelete() { ...@@ -242,15 +242,15 @@ function onDelete() {
<BModal <BModal
v-model="showDeleteModal" v-model="showDeleteModal"
centered centered
:title="isDeletedNotPurged ? 'Permanently Delete History?' : 'Delete History?'" :title="isDeletedNotPurged ? '永久删除历史记录?' : '删除历史记录?'"
title-tag="h2" title-tag="h2"
:ok-title="isDeletedNotPurged ? 'Permanently Delete' : 'Delete'" :ok-title="isDeletedNotPurged ? '永久删除' : '删除'"
ok-variant="danger" ok-variant="danger"
cancel-variant="outline-primary" cancel-variant="outline-primary"
@ok="onDelete" @ok="onDelete"
@show="purgeHistory = isDeletedNotPurged"> @show="purgeHistory = isDeletedNotPurged">
<p v-localize> <p>
Do you also want to permanently delete the history <i class="ml-1">{{ history.name }}</i> 是否也要永久删除历史记录 <i class="ml-1">{{ history.name }}</i>
</p> </p>
<BFormCheckbox id="purge-history" v-model="purgeHistory" :disabled="isDeletedNotPurged"> <BFormCheckbox id="purge-history" v-model="purgeHistory" :disabled="isDeletedNotPurged">
......
...@@ -9,17 +9,17 @@ ...@@ -9,17 +9,17 @@
:disabled="isSetAsCurrentDisabled" :disabled="isSetAsCurrentDisabled"
data-description="switch to history button" data-description="switch to history button"
@click="setCurrentHistory(history.id)"> @click="setCurrentHistory(history.id)">
Switch to this history 切换到该历史记录
</GButton> </GButton>
<GButton <GButton
v-if="canImportHistory" v-if="canImportHistory"
v-b-modal:copy-history-modal v-b-modal:copy-history-modal
color="blue" color="blue"
title="Import this history" title="导入此历史记录"
data-description="import history button"> data-description="import history button">
<FontAwesomeIcon :icon="faFileImport" /> <FontAwesomeIcon :icon="faFileImport" />
Import this history 导入此历史记录
</GButton> </GButton>
<HistoryOptions :history="history" minimal /> <HistoryOptions :history="history" minimal />
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
</BreadcrumbHeading> </BreadcrumbHeading>
<b-alert :show="copySuccess"> <b-alert :show="copySuccess">
History imported and is now your active history. <b-link :to="importedHistoryLink">在此查看</b-link>. 历史记录已导入,现为您的活动历史。<b-link :to="importedHistoryLink">在此查看</b-link>。
</b-alert> </b-alert>
<CollectionPanel <CollectionPanel
...@@ -86,11 +86,11 @@ export default { ...@@ -86,11 +86,11 @@ export default {
...mapState(useHistoryStore, ["getHistoryById", "currentHistory"]), ...mapState(useHistoryStore, ["getHistoryById", "currentHistory"]),
breadcrumbItems() { breadcrumbItems() {
return [ return [
{ title: "Histories", to: "/histories/list" }, { title: "历史记录", to: "/histories/list" },
{ {
title: this.history.name, title: this.history.name,
to: `/histories/view?id=${this.history.id}`, to: `/histories/view?id=${this.history.id}`,
superText: this.isCurrentHistory ? "current" : undefined, superText: this.isCurrentHistory ? "当前" : undefined,
}, },
]; ];
}, },
...@@ -108,9 +108,9 @@ export default { ...@@ -108,9 +108,9 @@ export default {
}, },
setAsCurrentTitle() { setAsCurrentTitle() {
if (this.isCurrentHistory) { if (this.isCurrentHistory) {
return "This history is already your current history."; return "此历史记录已经是您的当前历史。";
} }
return "Switch to this history"; return "切换到该历史记录";
}, },
canImportHistory() { canImportHistory() {
return !this.userOwnsHistory && !this.history.purged; return !this.userOwnsHistory && !this.history.purged;
......
...@@ -91,9 +91,9 @@ export function useHistoryCardActions( ...@@ -91,9 +91,9 @@ export function useHistoryCardActions(
try { try {
await historyStore.restoreHistory(history.value.id); await historyStore.restoreHistory(history.value.id);
refreshCallBack(); refreshCallBack();
Toast.success("History restored"); Toast.success("历史记录已恢复");
} catch (e) { } catch (e) {
Toast.error(`Failed to restore history: ${errorMessageAsString(e)}`); Toast.error(`无法恢复历史记录:${errorMessageAsString(e)}`);
} }
} }
...@@ -287,9 +287,9 @@ export function useHistoryCardActions( ...@@ -287,9 +287,9 @@ export function useHistoryCardActions(
(isMyHistory(history.value) || archivedView) && historyStore.currentHistoryId !== history.value.id, (isMyHistory(history.value) || archivedView) && historyStore.currentHistoryId !== history.value.id,
}, },
{ {
title: "current history", title: "当前历史记录",
id: "current", id: "current",
label: "Current", label: "当前",
variant: "outline-primary", variant: "outline-primary",
disabled: true, disabled: true,
visible: visible:
......
...@@ -16,14 +16,14 @@ from typing import ( ...@@ -16,14 +16,14 @@ from typing import (
Optional, Optional,
) )
from pydantic import ValidationError from pydantic import ValidationError
from pydantic_ai import ( from pydantic_ai import (
Agent, Agent,
RunContext, RunContext,
) )
from galaxy.model import History as GalaxyHistory from galaxy.model import History as GalaxyHistory
from galaxy.schema.agents import ConfidenceLevel from galaxy.schema.agents import ConfidenceLevel
from .base import ( from .base import (
AgentResponse, AgentResponse,
AgentType, AgentType,
...@@ -241,7 +241,7 @@ class QueryRouterAgent(BaseGalaxyAgent): ...@@ -241,7 +241,7 @@ class QueryRouterAgent(BaseGalaxyAgent):
return "未提供当前历史 ID,无法列出数据集。请先选择一个历史。" return "未提供当前历史 ID,无法列出数据集。请先选择一个历史。"
try: try:
from galaxy.managers.base import decode_id from galaxy.managers.base import decode_id
app = deps.trans.app app = deps.trans.app
decoded_id = decode_id(app, history_id) decoded_id = decode_id(app, history_id)
...@@ -301,7 +301,7 @@ class QueryRouterAgent(BaseGalaxyAgent): ...@@ -301,7 +301,7 @@ class QueryRouterAgent(BaseGalaxyAgent):
return "未提供当前历史 ID,无法读取数据集。请先选择一个历史。" return "未提供当前历史 ID,无法读取数据集。请先选择一个历史。"
try: try:
from galaxy.managers.base import decode_id from galaxy.managers.base import decode_id
app = deps.trans.app app = deps.trans.app
decoded_hid = decode_id(app, history_id) decoded_hid = decode_id(app, history_id)
...@@ -327,7 +327,7 @@ class QueryRouterAgent(BaseGalaxyAgent): ...@@ -327,7 +327,7 @@ class QueryRouterAgent(BaseGalaxyAgent):
try: try:
dataset = target.dataset dataset = target.dataset
object_store = app.object_store object_store = app.object_store
max_lines = int(self._get_agent_config("max_dataset_preview_lines", 200)) max_lines = int(self._get_agent_config("max_dataset_preview_lines", 1000))
raw = object_store.get_data(dataset, start=0, count=max_lines) raw = object_store.get_data(dataset, start=0, count=max_lines)
text = raw if isinstance(raw, str) else (raw.decode("utf-8", errors="replace") if raw else "") text = raw if isinstance(raw, str) else (raw.decode("utf-8", errors="replace") if raw else "")
return text.strip() or "(数据集为空)" return text.strip() or "(数据集为空)"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment