update web

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens Langhammer 2024-01-13 21:07:46 +01:00
parent 7ed2babd22
commit 39b574a47d
No known key found for this signature in database
17 changed files with 10381 additions and 10391 deletions

View File

@ -6,7 +6,7 @@ import { ChartData, ChartOptions } from "chart.js";
import { msg } from "@lit/localize";
import { customElement } from "lit/decorators.js";
import { ProvidersApi, SourcesApi, TaskStatusEnum } from "@goauthentik/api";
import { ProvidersApi, SourcesApi, SystemTaskStatusEnum } from "@goauthentik/api";
export interface SyncStatus {
healthy: number;
@ -49,12 +49,12 @@ export class LDAPSyncStatusChart extends AKChart<SyncStatus[]> {
});
health.tasks.forEach((task) => {
if (task.status !== TaskStatusEnum.Successful) {
if (task.status !== SystemTaskStatusEnum.Successful) {
metrics.failed += 1;
}
const now = new Date().getTime();
const maxDelta = 3600000; // 1 hour
if (!health || now - task.taskFinishTimestamp.getTime() > maxDelta) {
if (!health || now - task.finishTimestamp.getTime() > maxDelta) {
metrics.unsynced += 1;
} else {
metrics.healthy += 1;
@ -94,12 +94,12 @@ export class LDAPSyncStatusChart extends AKChart<SyncStatus[]> {
id: element.pk,
});
health.tasks.forEach((task) => {
if (task.status !== TaskStatusEnum.Successful) {
if (task.status !== SystemTaskStatusEnum.Successful) {
sourceKey = "failed";
}
const now = new Date().getTime();
const maxDelta = 3600000; // 1 hour
if (!health || now - task.taskFinishTimestamp.getTime() > maxDelta) {
if (!health || now - task.finishTimestamp.getTime() > maxDelta) {
sourceKey = "unsynced";
}
});

View File

@ -32,7 +32,7 @@ import {
RbacPermissionsAssignedByUsersListModelEnum,
SCIMProvider,
SCIMSyncStatus,
TaskStatusEnum,
SystemTaskStatusEnum,
} from "@goauthentik/api";
@customElement("ak-provider-scim-view")
@ -143,15 +143,15 @@ export class SCIMProviderViewPage extends AKElement {
<ul class="pf-c-list">
${this.syncState.tasks.map((task) => {
let header = "";
if (task.status === TaskStatusEnum.Warning) {
if (task.status === SystemTaskStatusEnum.Warning) {
header = msg("Task finished with warnings");
} else if (task.status === TaskStatusEnum.Error) {
} else if (task.status === SystemTaskStatusEnum.Error) {
header = msg("Task finished with errors");
} else {
header = msg(str`Last sync: ${task.taskFinishTimestamp.toLocaleString()}`);
header = msg(str`Last sync: ${task.finishTimestamp.toLocaleString()}`);
}
return html`<li>
<p>${task.taskName}</p>
<p>${task.name}</p>
<ul class="pf-c-list">
<li>${header}</li>
${task.messages.map((m) => {

View File

@ -29,7 +29,7 @@ import {
LDAPSyncStatus,
RbacPermissionsAssignedByUsersListModelEnum,
SourcesApi,
TaskStatusEnum,
SystemTaskStatusEnum,
} from "@goauthentik/api";
@customElement("ak-source-ldap-view")
@ -77,15 +77,15 @@ export class LDAPSourceViewPage extends AKElement {
<ul class="pf-c-list">
${this.syncState.tasks.map((task) => {
let header = "";
if (task.status === TaskStatusEnum.Warning) {
if (task.status === SystemTaskStatusEnum.Warning) {
header = msg("Task finished with warnings");
} else if (task.status === TaskStatusEnum.Error) {
} else if (task.status === SystemTaskStatusEnum.Error) {
header = msg("Task finished with errors");
} else {
header = msg(str`Last sync: ${task.taskFinishTimestamp.toLocaleString()}`);
header = msg(str`Last sync: ${task.finishTimestamp.toLocaleString()}`);
}
return html`<li>
<p>${task.taskName}</p>
<p>${task.name}</p>
<ul class="pf-c-list">
<li>${header}</li>
${task.messages.map((m) => {

View File

@ -1,3 +1,4 @@
import { uiConfig } from "@goauthentik/app/common/ui/config";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { EVENT_REFRESH } from "@goauthentik/common/constants";
import { PFColor } from "@goauthentik/elements/Label";
@ -14,13 +15,10 @@ import { customElement, property } from "lit/decorators.js";
import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css";
import { AdminApi, Task, TaskStatusEnum } from "@goauthentik/api";
import { EventsApi, SystemTask, SystemTaskStatusEnum } from "@goauthentik/api";
@customElement("ak-system-task-list")
export class SystemTaskListPage extends TablePage<Task> {
searchEnabled(): boolean {
return false;
}
export class SystemTaskListPage extends TablePage<SystemTask> {
pageTitle(): string {
return msg("System Tasks");
}
@ -34,53 +32,45 @@ export class SystemTaskListPage extends TablePage<Task> {
expandable = true;
@property()
order = "slug";
order = "name";
static get styles(): CSSResult[] {
return super.styles.concat(PFDescriptionList);
}
async apiEndpoint(page: number): Promise<PaginatedResponse<Task>> {
return new AdminApi(DEFAULT_CONFIG).adminSystemTasksList().then((tasks) => {
return {
pagination: {
count: tasks.length,
totalPages: 1,
startIndex: 1,
endIndex: tasks.length,
current: page,
next: 0,
previous: 0,
},
results: tasks,
};
async apiEndpoint(page: number): Promise<PaginatedResponse<SystemTask>> {
return new EventsApi(DEFAULT_CONFIG).eventsSystemTasksList({
ordering: this.order,
page: page,
pageSize: (await uiConfig()).pagination.perPage,
search: this.search || "",
});
}
columns(): TableColumn[] {
return [
new TableColumn(msg("Identifier")),
new TableColumn(msg("Identifier"), "name"),
new TableColumn(msg("Description")),
new TableColumn(msg("Last run")),
new TableColumn(msg("Status")),
new TableColumn(msg("Status"), "status"),
new TableColumn(msg("Actions")),
];
}
taskStatus(task: Task): TemplateResult {
taskStatus(task: SystemTask): TemplateResult {
switch (task.status) {
case TaskStatusEnum.Successful:
case SystemTaskStatusEnum.Successful:
return html`<ak-label color=${PFColor.Green}>${msg("Successful")}</ak-label>`;
case TaskStatusEnum.Warning:
case SystemTaskStatusEnum.Warning:
return html`<ak-label color=${PFColor.Orange}>${msg("Warning")}</ak-label>`;
case TaskStatusEnum.Error:
case SystemTaskStatusEnum.Error:
return html`<ak-label color=${PFColor.Red}>${msg("Error")}</ak-label>`;
default:
return html`<ak-label color=${PFColor.Grey}>${msg("Unknown")}</ak-label>`;
}
}
renderExpanded(item: Task): TemplateResult {
renderExpanded(item: SystemTask): TemplateResult {
return html` <td role="cell" colspan="3">
<div class="pf-c-table__expandable-row-content">
<dl class="pf-c-description-list pf-m-horizontal">
@ -90,7 +80,7 @@ export class SystemTaskListPage extends TablePage<Task> {
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
${msg(str`${item.taskDuration.toFixed(2)} seconds`)}
${msg(str`${item.duration.toFixed(2)} seconds`)}
</div>
</dd>
</div>
@ -113,18 +103,18 @@ export class SystemTaskListPage extends TablePage<Task> {
<td></td>`;
}
row(item: Task): TemplateResult[] {
row(item: SystemTask): TemplateResult[] {
return [
html`${item.taskName}`,
html`${item.taskDescription}`,
html`${item.taskFinishTimestamp.toLocaleString()}`,
html`${item.name}${item.uid ? `:${item.uid}` : ""}`,
html`${item.description}`,
html`${item.finishTimestamp.toLocaleString()}`,
this.taskStatus(item),
html`<ak-action-button
class="pf-m-plain"
.apiRequest=${() => {
return new AdminApi(DEFAULT_CONFIG)
.adminSystemTasksRetryCreate({
id: item.taskName,
return new EventsApi(DEFAULT_CONFIG)
.eventsSystemTasksRetryCreate({
uuid: item.uuid,
})
.then(() => {
this.dispatchEvent(

View File

@ -602,7 +602,7 @@
<source>Duration</source>
</trans-unit>
<trans-unit id="se7e1ababbc4868b8">
<source><x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/> seconds</source>
<source><x id="0" equiv-text="${item.duration.toFixed(2)}"/> seconds</source>
</trans-unit>
<trans-unit id="sc25edca57df81461">
<source>Authentication</source>
@ -2557,9 +2557,9 @@ doesn't pass when either or both of the selected options are equal or above the
<target>Aufgabe mit Fehlern beendet</target>
</trans-unit>
<trans-unit id="sbedb77365a066648">
<source>Last sync: <x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></source>
<source>Last sync: <x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></source>
<target>Letzte Synchronisierung:
<x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></target>
<x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></target>
</trans-unit>
<trans-unit id="sf3fec8353106ac2f">
<source>OAuth Source <x id="0" equiv-text="${this.source.name}"/></source>

View File

@ -617,9 +617,9 @@
<target>Duration</target>
</trans-unit>
<trans-unit id="se7e1ababbc4868b8">
<source><x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/> seconds</source>
<source><x id="0" equiv-text="${item.duration.toFixed(2)}"/> seconds</source>
<target>
<x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/>seconds</target>
<x id="0" equiv-text="${item.duration.toFixed(2)}"/>seconds</target>
</trans-unit>
<trans-unit id="sc25edca57df81461">
<source>Authentication</source>
@ -2679,9 +2679,9 @@ doesn't pass when either or both of the selected options are equal or above the
<target>Task finished with errors</target>
</trans-unit>
<trans-unit id="sbedb77365a066648">
<source>Last sync: <x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></source>
<source>Last sync: <x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></source>
<target>Last sync:
<x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></target>
<x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></target>
</trans-unit>
<trans-unit id="sf3fec8353106ac2f">
<source>OAuth Source <x id="0" equiv-text="${this.source.name}"/></source>

View File

@ -594,7 +594,7 @@
<source>Duration</source>
</trans-unit>
<trans-unit id="se7e1ababbc4868b8">
<source><x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/> seconds</source>
<source><x id="0" equiv-text="${item.duration.toFixed(2)}"/> seconds</source>
</trans-unit>
<trans-unit id="sc25edca57df81461">
<source>Authentication</source>
@ -2517,9 +2517,9 @@ doesn't pass when either or both of the selected options are equal or above the
<target>La tarea ha finalizado con errores</target>
</trans-unit>
<trans-unit id="sbedb77365a066648">
<source>Last sync: <x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></source>
<source>Last sync: <x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></source>
<target>Última sincronización:
<x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></target>
<x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></target>
</trans-unit>
<trans-unit id="sf3fec8353106ac2f">
<source>OAuth Source <x id="0" equiv-text="${this.source.name}"/></source>

View File

@ -766,9 +766,9 @@ Il y a <x id="0" equiv-text="${ago}"/> jour(s)</target>
</trans-unit>
<trans-unit id="se7e1ababbc4868b8">
<source><x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/> seconds</source>
<source><x id="0" equiv-text="${item.duration.toFixed(2)}"/> seconds</source>
<target>
<x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/>secondes</target>
<x id="0" equiv-text="${item.duration.toFixed(2)}"/>secondes</target>
</trans-unit>
<trans-unit id="sc25edca57df81461">
@ -3341,9 +3341,9 @@ doesn't pass when either or both of the selected options are equal or above the
</trans-unit>
<trans-unit id="sbedb77365a066648">
<source>Last sync: <x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></source>
<source>Last sync: <x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></source>
<target>Dernière synchro :
<x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></target>
<x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></target>
</trans-unit>
<trans-unit id="sf3fec8353106ac2f">

View File

@ -763,9 +763,9 @@
</trans-unit>
<trans-unit id="se7e1ababbc4868b8">
<source><x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/> seconds</source>
<source><x id="0" equiv-text="${item.duration.toFixed(2)}"/> seconds</source>
<target>
<x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/> 초</target>
<x id="0" equiv-text="${item.duration.toFixed(2)}"/> 초</target>
</trans-unit>
<trans-unit id="sc25edca57df81461">
@ -3332,8 +3332,8 @@ doesn't pass when either or both of the selected options are equal or above the
</trans-unit>
<trans-unit id="sbedb77365a066648">
<source>Last sync: <x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></source>
<target><x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/>에 마지막으로 동기화 됨</target>
<source>Last sync: <x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></source>
<target><x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/>에 마지막으로 동기화 됨</target>
</trans-unit>
<trans-unit id="sf3fec8353106ac2f">

View File

@ -767,8 +767,8 @@
</trans-unit>
<trans-unit id="se7e1ababbc4868b8">
<source><x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/> seconds</source>
<target><x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/> seconden</target>
<source><x id="0" equiv-text="${item.duration.toFixed(2)}"/> seconds</source>
<target><x id="0" equiv-text="${item.duration.toFixed(2)}"/> seconden</target>
</trans-unit>
<trans-unit id="sc25edca57df81461">
@ -3580,8 +3580,8 @@ slaagt niet wanneer een of beide geselecteerde opties gelijk zijn aan of boven d
</trans-unit>
<trans-unit id="sbedb77365a066648">
<source>Last sync: <x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></source>
<target>Laatste synchronisatie: <x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></target>
<source>Last sync: <x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></source>
<target>Laatste synchronisatie: <x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></target>
</trans-unit>
<trans-unit id="sf3fec8353106ac2f">

View File

@ -604,7 +604,7 @@
<source>Duration</source>
</trans-unit>
<trans-unit id="se7e1ababbc4868b8">
<source><x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/> seconds</source>
<source><x id="0" equiv-text="${item.duration.toFixed(2)}"/> seconds</source>
</trans-unit>
<trans-unit id="sc25edca57df81461">
<source>Authentication</source>
@ -2601,9 +2601,9 @@ doesn't pass when either or both of the selected options are equal or above the
<target>Zadanie zakończone z błędami</target>
</trans-unit>
<trans-unit id="sbedb77365a066648">
<source>Last sync: <x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></source>
<source>Last sync: <x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></source>
<target>Ostatnia synchronizacja:
<x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></target>
<x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></target>
</trans-unit>
<trans-unit id="sf3fec8353106ac2f">
<source>OAuth Source <x id="0" equiv-text="${this.source.name}"/></source>

View File

@ -753,8 +753,8 @@
</trans-unit>
<trans-unit id="se7e1ababbc4868b8">
<source><x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/> seconds</source>
<target><x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/> śēćōńďś</target>
<source><x id="0" equiv-text="${item.duration.toFixed(2)}"/> seconds</source>
<target><x id="0" equiv-text="${item.duration.toFixed(2)}"/> śēćōńďś</target>
</trans-unit>
<trans-unit id="sc25edca57df81461">
@ -3320,8 +3320,8 @@ doesn't pass when either or both of the selected options are equal or above the
</trans-unit>
<trans-unit id="sbedb77365a066648">
<source>Last sync: <x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></source>
<target>Ĺàśţ śŷńć: <x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></target>
<source>Last sync: <x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></source>
<target>Ĺàśţ śŷńć: <x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></target>
</trans-unit>
<trans-unit id="sf3fec8353106ac2f">

View File

@ -594,7 +594,7 @@
<source>Duration</source>
</trans-unit>
<trans-unit id="se7e1ababbc4868b8">
<source><x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/> seconds</source>
<source><x id="0" equiv-text="${item.duration.toFixed(2)}"/> seconds</source>
</trans-unit>
<trans-unit id="sc25edca57df81461">
<source>Authentication</source>
@ -2516,9 +2516,9 @@ doesn't pass when either or both of the selected options are equal or above the
<target>Görev hatalarla tamamlandı</target>
</trans-unit>
<trans-unit id="sbedb77365a066648">
<source>Last sync: <x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></source>
<source>Last sync: <x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></source>
<target>Son senkronizasyon:
<x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></target>
<x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></target>
</trans-unit>
<trans-unit id="sf3fec8353106ac2f">
<source>OAuth Source <x id="0" equiv-text="${this.source.name}"/></source>

View File

@ -766,9 +766,9 @@
</trans-unit>
<trans-unit id="se7e1ababbc4868b8">
<source><x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/> seconds</source>
<source><x id="0" equiv-text="${item.duration.toFixed(2)}"/> seconds</source>
<target>
<x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/>秒</target>
<x id="0" equiv-text="${item.duration.toFixed(2)}"/>秒</target>
</trans-unit>
<trans-unit id="sc25edca57df81461">
@ -3343,9 +3343,9 @@ doesn't pass when either or both of the selected options are equal or above the
</trans-unit>
<trans-unit id="sbedb77365a066648">
<source>Last sync: <x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></source>
<source>Last sync: <x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></source>
<target>上次同步:
<x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></target>
<x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></target>
</trans-unit>
<trans-unit id="sf3fec8353106ac2f">

View File

@ -601,7 +601,7 @@
<source>Duration</source>
</trans-unit>
<trans-unit id="se7e1ababbc4868b8">
<source><x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/> seconds</source>
<source><x id="0" equiv-text="${item.duration.toFixed(2)}"/> seconds</source>
</trans-unit>
<trans-unit id="sc25edca57df81461">
<source>Authentication</source>
@ -2538,9 +2538,9 @@ doesn't pass when either or both of the selected options are equal or above the
<target>任务已完成,但出现错误</target>
</trans-unit>
<trans-unit id="sbedb77365a066648">
<source>Last sync: <x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></source>
<source>Last sync: <x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></source>
<target>上次同步:
<x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></target>
<x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></target>
</trans-unit>
<trans-unit id="sf3fec8353106ac2f">
<source>OAuth Source <x id="0" equiv-text="${this.source.name}"/></source>

View File

@ -766,9 +766,9 @@
</trans-unit>
<trans-unit id="se7e1ababbc4868b8">
<source><x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/> seconds</source>
<source><x id="0" equiv-text="${item.duration.toFixed(2)}"/> seconds</source>
<target>
<x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/>秒</target>
<x id="0" equiv-text="${item.duration.toFixed(2)}"/>秒</target>
</trans-unit>
<trans-unit id="sc25edca57df81461">
@ -3343,9 +3343,9 @@ doesn't pass when either or both of the selected options are equal or above the
</trans-unit>
<trans-unit id="sbedb77365a066648">
<source>Last sync: <x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></source>
<source>Last sync: <x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></source>
<target>上次同步:
<x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></target>
<x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></target>
</trans-unit>
<trans-unit id="sf3fec8353106ac2f">

View File

@ -754,8 +754,8 @@
</trans-unit>
<trans-unit id="se7e1ababbc4868b8">
<source><x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/> seconds</source>
<target><x id="0" equiv-text="${item.taskDuration.toFixed(2)}"/> 秒</target>
<source><x id="0" equiv-text="${item.duration.toFixed(2)}"/> seconds</source>
<target><x id="0" equiv-text="${item.duration.toFixed(2)}"/> 秒</target>
</trans-unit>
<trans-unit id="sc25edca57df81461">
@ -3320,8 +3320,8 @@ doesn't pass when either or both of the selected options are equal or above the
</trans-unit>
<trans-unit id="sbedb77365a066648">
<source>Last sync: <x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></source>
<target>上次同步: <x id="0" equiv-text="${task.taskFinishTimestamp.toLocaleString()}"/></target>
<source>Last sync: <x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></source>
<target>上次同步: <x id="0" equiv-text="${task.finishTimestamp.toLocaleString()}"/></target>
</trans-unit>
<trans-unit id="sf3fec8353106ac2f">