Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions app/shared/src/i18n/workbench.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,20 @@ export const sharedWorkbenchResources = {
stateComponents: { title: '状态组件预览', description: '预览不同 Agent 运行状态的卡片样式' },
},
moreButton: { label: '设置更多' },
section: {
interface: '界面',
layout: '布局',
runNotifications: '运行提醒',
collaborationNotifications: '协作提醒',
defaultRunConfig: '默认运行配置',
permissionPolicy: '权限策略',
singleAgentConfig: '单个 Agent 配置',
localPreview: '本地预览',
debug: '调试',
localSessionImport: '本地会话导入',
statePolicy: '状态策略',
},
loadFailed: '设置加载失败',
},
projects: {
nav: { all: '全部项目', running: '运行中', completed: '已完成', archived: '已归档' },
Expand All @@ -142,6 +156,20 @@ export const sharedWorkbenchResources = {
loading: '正在加载项目…',
loadMoreError: '加载更多项目失败:{{message}}',
retryLoadMore: '重试加载更多',
section: {
members: '成员',
projectRuns: '项目运行',
runSummary: '运行摘要',
artifacts: '产物',
artifactIndex: '产物索引',
recentActivity: '最近动态',
runRecords: '运行记录',
deliveryActivity: '交付动态',
archiveCheck: '归档检查',
archivePackage: '归档包',
projectSettings: '项目设置',
memberPolicy: '成员策略',
},
empty: {
title: '暂无项目',
description: '创建第一个项目以开始协作。',
Expand All @@ -163,6 +191,13 @@ export const sharedWorkbenchResources = {
contacts: {
nav: { internal: '组织内联系人', external: '外部联系人', newFriend: '新的朋友' },
search: { placeholder: '搜索联系人' },
section: {
external: { title: '外部联系人', subtitle: '客户、合作方和临时项目协作者,不进入 TokenDance 组织架构。' },
starred: { title: '星标联系人', subtitle: '常用联系人会固定在这里,便于快速发起对话和项目协作。' },
internal: { title: '组织内联系人' },
myGroups: { title: '我的群组', subtitle: '项目群、评审群和协作群统一管理,按最新消息排序。' },
helpDesk: { title: '服务台', subtitle: '把账号、Agent 运行和云文档问题转给对应支持入口。' },
},
empty: { title: '暂无联系人', description: '添加联系人开始协作' },
emptySearch: {
title: '没有匹配的联系人',
Expand Down Expand Up @@ -410,6 +445,20 @@ export const sharedWorkbenchResources = {
stateComponents: { title: 'State component preview', description: 'Preview card styles for different agent run states' },
},
moreButton: { label: 'More settings' },
section: {
interface: 'Interface',
layout: 'Layout',
runNotifications: 'Run notifications',
collaborationNotifications: 'Collaboration notifications',
defaultRunConfig: 'Default run config',
permissionPolicy: 'Permission policy',
singleAgentConfig: 'Single agent config',
localPreview: 'Local preview',
debug: 'Debug',
localSessionImport: 'Local session import',
statePolicy: 'State policy',
},
loadFailed: 'Settings load failed',
},
projects: {
nav: { all: 'All projects', running: 'Running', completed: 'Completed', archived: 'Archived' },
Expand All @@ -420,6 +469,20 @@ export const sharedWorkbenchResources = {
loading: 'Loading projects…',
loadMoreError: 'Failed to load more projects: {{message}}',
retryLoadMore: 'Retry loading more',
section: {
members: 'Members',
projectRuns: 'Project runs',
runSummary: 'Run summary',
artifacts: 'Artifacts',
artifactIndex: 'Artifact index',
recentActivity: 'Recent activity',
runRecords: 'Run records',
deliveryActivity: 'Delivery activity',
archiveCheck: 'Archive check',
archivePackage: 'Archive package',
projectSettings: 'Project settings',
memberPolicy: 'Member policy',
},
empty: {
title: 'No projects yet',
description: 'Create your first project to start collaborating.',
Expand All @@ -441,6 +504,13 @@ export const sharedWorkbenchResources = {
contacts: {
nav: { internal: 'Internal contacts', external: 'External contacts', newFriend: 'New friends' },
search: { placeholder: 'Search contacts' },
section: {
external: { title: 'External contacts', subtitle: 'Clients, partners and temporary collaborators, not part of the TokenDance organization.' },
starred: { title: 'Starred contacts', subtitle: 'Frequent contacts are pinned here for quick access to conversations and projects.' },
internal: { title: 'Internal contacts' },
myGroups: { title: 'My groups', subtitle: 'Project, review and collaboration groups managed together, sorted by latest message.' },
helpDesk: { title: 'Help desk', subtitle: 'Route account, agent run and document issues to the appropriate support channel.' },
},
empty: { title: 'No contacts yet', description: 'Add contacts to start collaborating' },
emptySearch: {
title: 'No matching contacts',
Expand Down
10 changes: 6 additions & 4 deletions app/shared/src/workbench/pages/contacts/ContactMainParts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,12 @@ export function ContactGroupsPane({
onGroupClick?: ((group: ContactGroup) => void) | undefined;
onAvatarClick?: ((group: ContactGroup, anchor: HTMLElement) => void) | undefined;
}): React.ReactElement {
const { t } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE);
return (
<main className={`${styles.main} workbench-main`}>
<ContactMainHead
title="我的群组"
subtitle="项目群、评审群和协作群统一管理,按最新消息排序。"
title={t("contacts.section.myGroups.title")}
subtitle={t("contacts.section.myGroups.subtitle")}
actionLabel="创建群组"
onAction={onCreateGroup}
/>
Expand Down Expand Up @@ -241,11 +242,12 @@ export function ContactServicePane({
onServiceClick?: ((desk: ServiceDesk) => void) | undefined;
onAvatarClick?: ((desk: ServiceDesk, anchor: HTMLElement) => void) | undefined;
}): React.ReactElement {
const { t } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE);
return (
<main className={`${styles.main} workbench-main`}>
<ContactMainHead
title="服务台"
subtitle="把账号、Agent 运行和云文档问题转给对应支持入口。"
title={t("contacts.section.helpDesk.title")}
subtitle={t("contacts.section.helpDesk.subtitle")}
actionLabel="新建工单"
onAction={onNewTicket}
/>
Expand Down
13 changes: 8 additions & 5 deletions app/shared/src/workbench/pages/contacts/ContactMainViews.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import React, { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { SHARED_WORKBENCH_I18N_NAMESPACE } from '../../../i18n';
import {
ContactGroupsPane,
ContactListPage,
Expand Down Expand Up @@ -76,6 +78,7 @@ export function ContactMain({
onAcceptRequest,
onRejectRequest,
}: ContactMainProps): React.ReactElement {
const { t } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE);
const resolvedPending = pendingContacts ?? [];
const [activeProfile, setActiveProfile] = useState<ContactProfile | null>(null);
const [actionLoading, setActionLoading] = useState(false);
Expand Down Expand Up @@ -158,8 +161,8 @@ export function ContactMain({
case 'external':
return (
<ContactListPage
title="外部联系人"
subtitle="客户、合作方和临时项目协作者,不进入 TokenDance 组织架构。"
title={t("contacts.section.external.title")}
subtitle={t("contacts.section.external.subtitle")}
actionLabel="添加外部联系人"
rows={externalContacts ?? []}
sectionTitle="外部联系人"
Expand Down Expand Up @@ -196,8 +199,8 @@ export function ContactMain({
case 'starred':
return (
<ContactListPage
title="星标联系人"
subtitle="常用联系人会固定在这里,便于快速发起对话和项目协作。"
title={t("contacts.section.starred.title")}
subtitle={t("contacts.section.starred.subtitle")}
actionLabel="管理星标"
rows={starredContacts ?? []}
sectionTitle="TokenDance"
Expand Down Expand Up @@ -237,7 +240,7 @@ export function ContactMain({
default:
return (
<ContactListPage
title="组织内联系人"
title={t("contacts.section.internal.title")}
subtitle="TokenDance 成员和外部联系人统一从这里添加、确认和发起对话。"
actionLabel="添加联系人"
rows={members}
Expand Down
5 changes: 4 additions & 1 deletion app/shared/src/workbench/pages/projects/ProjectFeedPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@
═══════════════════════════════════════════════════════════════════════ */

import React from 'react';
import { useTranslation } from 'react-i18next';
import { SHARED_WORKBENCH_I18N_NAMESPACE } from '../../../i18n';
import styles from '../ProjectsPage.module.css';
import { ProjectSectionHead } from './ProjectPanelHelpers';
import type { ProjectFeedItem } from './types';

export function ProjectFeedPanel({ feed }: { feed: ProjectFeedItem[] }) {
const { t } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE);
return (
<section className={`${styles.detailPanel} ${styles.feedPanel} project-detail-panel`} data-card-surface>
<ProjectSectionHead icon="notes" title="最近动态" meta="Today" />
<ProjectSectionHead icon="notes" title={t("projects.section.recentActivity")} meta="Today" />
{feed.map((item) => (
<div key={item.id} className={styles.feedRow}>
<time className={styles.feedTime}>{item.time}</time>
Expand Down
17 changes: 12 additions & 5 deletions app/shared/src/workbench/pages/projects/ProjectPanelParts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
═══════════════════════════════════════════════════════════════════════ */

import React from 'react';
import { useTranslation } from 'react-i18next';
import { SHARED_WORKBENCH_I18N_NAMESPACE } from '../../../i18n';
import { DesignFileIcon } from '../../designIcons';
import type { WorkbenchDocumentPreview } from '../../documentPreview';
import { FilePreview } from '../../inspector';
Expand Down Expand Up @@ -35,9 +37,10 @@ export function MembersCard({
members: string[];
profiles?: WorkbenchProfileSource[] | undefined;
}) {
const { t } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE);
return (
<section className={`${styles.membersCard} project-members-card`} data-card-surface>
<ProjectSectionHead icon="users" title="成员" meta={`${members.length} people`} />
<ProjectSectionHead icon="users" title={t("projects.section.members")} meta={`${members.length} people`} />
<div className={`${styles.memberChips} project-members`}>
{members.map((name) => (
<ProjectMemberChip key={name} name={name} profiles={profiles} />
Expand Down Expand Up @@ -79,9 +82,10 @@ export function RunsPanel({
onRunClick?: ((run: ProjectRun) => void) | undefined;
profiles?: WorkbenchProfileSource[] | undefined;
}) {
const { t } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE);
return (
<section className={`${styles.detailPanel} ${styles.runsPanel} project-detail-panel project-runs-panel`} data-card-surface>
<ProjectSectionHead icon="running" title="项目运行" meta={meta} />
<ProjectSectionHead icon="running" title={t("projects.section.projectRuns")} meta={meta} />
{runs.map((run) => (
<button
key={run.id}
Expand All @@ -101,13 +105,14 @@ export function RunsPanel({
}

export function RunSummaryPanel({ project }: { project: ProjectInfo }) {
const { t } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE);
const running = runCount(project.runs, ['running', 'thinking']);
const completed = runCount(project.runs, ['completed']);
const waiting = runCount(project.runs, ['waiting']);

return (
<section className={`${styles.detailPanel} project-detail-panel`} data-card-surface>
<ProjectSectionHead icon="grid" title="运行摘要" meta={`${project.runs.length} total`} />
<ProjectSectionHead icon="grid" title={t("projects.section.runSummary")} meta={`${project.runs.length} total`} />
<div className={styles.summaryRows}>
<div className={styles.summaryRow}>
<span className={`${styles.stateDot} ${styles.stateRunning}`} />
Expand Down Expand Up @@ -136,9 +141,10 @@ export function ArtifactsPanel({
artifacts: ProjectArtifact[];
onArtifactClick?: ((artifact: ProjectArtifact) => void) | undefined;
}) {
const { t } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE);
return (
<section className={`${styles.detailPanel} project-detail-panel`} data-card-surface>
<ProjectSectionHead icon="package" title="产物" meta={`${artifacts.length} files`} />
<ProjectSectionHead icon="package" title={t("projects.section.artifacts")} meta={`${artifacts.length} files`} />
{artifacts.map((a) => (
<button
key={a.id}
Expand All @@ -156,9 +162,10 @@ export function ArtifactsPanel({
}

export function ArtifactIndexPanel({ artifacts }: { artifacts: ProjectArtifact[] }) {
const { t } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE);
return (
<section className={`${styles.detailPanel} project-detail-panel`} data-card-surface>
<ProjectSectionHead icon="notes" title="产物索引" meta={`${artifacts.length} entries`} />
<ProjectSectionHead icon="notes" title={t("projects.section.artifactIndex")} meta={`${artifacts.length} entries`} />
{artifacts.map((artifact, index) => (
<div key={artifact.id} className={styles.metaRow}>
<span>{String(index + 1).padStart(2, '0')}</span>
Expand Down
18 changes: 12 additions & 6 deletions app/shared/src/workbench/pages/projects/ProjectTabViews.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
═══════════════════════════════════════════════════════════════════════ */

import React from 'react';
import { useTranslation } from 'react-i18next';
import { SHARED_WORKBENCH_I18N_NAMESPACE } from '../../../i18n';
import {
DesignFileIcon,
} from '../../designIcons';
Expand Down Expand Up @@ -44,6 +46,7 @@ export function RunsTab({
onRunClick?: ((projectId: string, run: ProjectRun) => void) | undefined;
profiles?: WorkbenchProfileSource[] | undefined;
}) {
const { t } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE);
return (
<div className={styles.detailLayout}>
<RunsPanel
Expand All @@ -54,7 +57,7 @@ export function RunsTab({
/>
<RunSummaryPanel project={project} />
<section className={`${styles.detailPanel} ${styles.feedPanel} project-detail-panel project-feed`} data-card-surface>
<ProjectSectionHead icon="notes" title="运行记录" meta="Recent" />
<ProjectSectionHead icon="notes" title={t("projects.section.runRecords")} meta="Recent" />
{project.runs.map((run) => (
<div key={run.id} className={styles.feedRow}>
<time className={styles.feedTime}>{runStatusLabel(run.status)}</time>
Expand All @@ -79,6 +82,7 @@ export function ArtifactsTab({
activePreview?: WorkbenchDocumentPreview | null | undefined;
onClosePreview?: (() => void) | undefined;
}) {
const { t } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE);
return (
<div className={styles.detailLayout}>
<ArtifactsPanel
Expand All @@ -87,7 +91,7 @@ export function ArtifactsTab({
/>
<ArtifactIndexPanel artifacts={project.artifacts} />
<section className={`${styles.detailPanel} ${styles.feedPanel} project-detail-panel project-feed`} data-card-surface>
<ProjectSectionHead icon="package" title="交付动态" meta={`${project.artifacts.length} files`} />
<ProjectSectionHead icon="package" title={t("projects.section.deliveryActivity")} meta={`${project.artifacts.length} files`} />
{project.artifacts.map((artifact) => (
<div key={artifact.id} className={styles.feedRow}>
<time className={styles.feedTime}>{artifact.type}</time>
Expand All @@ -101,6 +105,7 @@ export function ArtifactsTab({
}

export function ArchiveTab({ project }: { project: ProjectInfo }) {
const { t } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE);
const completed = runCount(project.runs, ['completed']);
const active = runCount(project.runs, ['running', 'thinking', 'waiting']);
const archiveItems = [
Expand All @@ -112,7 +117,7 @@ export function ArchiveTab({ project }: { project: ProjectInfo }) {
return (
<div className={styles.detailLayout}>
<section className={`${styles.detailPanel} project-detail-panel`} data-card-surface>
<ProjectSectionHead icon="archive" title="归档检查" meta={`${archiveItems.length} checks`} />
<ProjectSectionHead icon="archive" title={t("projects.section.archiveCheck")} meta={`${archiveItems.length} checks`} />
{archiveItems.map((item) => (
<div key={item.id} className={styles.archiveRow}>
<span className={`${styles.stateDot} ${item.status === '可归档' || item.status === '已整理' ? styles.stateCompleted : styles.stateWaiting}`} />
Expand All @@ -123,7 +128,7 @@ export function ArchiveTab({ project }: { project: ProjectInfo }) {
))}
</section>
<section className={`${styles.detailPanel} project-detail-panel`} data-card-surface>
<ProjectSectionHead icon="package" title="归档包" meta="Draft" />
<ProjectSectionHead icon="package" title={t("projects.section.archivePackage")} meta="Draft" />
<button type="button" className={`${styles.artifactRow} project-artifact`} data-card-surface>
<DesignFileIcon className={styles.fileIcon} name={`${project.id}-handoff.md`} type="md" />
<span className={styles.artifactName}>{project.id}-handoff.md</span>
Expand All @@ -145,6 +150,7 @@ export function SettingsTab({
project: ProjectInfo;
profiles?: WorkbenchProfileSource[] | undefined;
}) {
const { t } = useTranslation(SHARED_WORKBENCH_I18N_NAMESPACE);
const settings = [
{ label: '项目名称', value: project.name, meta: project.id },
{ label: '当前状态', value: project.status, meta: project.meta },
Expand All @@ -160,7 +166,7 @@ export function SettingsTab({
onEdit={undefined}
/>
<section className={`${styles.detailPanel} ${styles.settingsPanel} project-detail-panel`} data-card-surface>
<ProjectSectionHead icon="tools" title="项目设置" meta={`${settings.length} 项`} />
<ProjectSectionHead icon="tools" title={t("projects.section.projectSettings")} meta={`${settings.length} 项`} />
{settings.map((item) => (
<div key={item.label} className={styles.settingRow}>
<div>
Expand All @@ -172,7 +178,7 @@ export function SettingsTab({
))}
</section>
<section className={`${styles.detailPanel} ${styles.settingsSidePanel} project-detail-panel`} data-card-surface>
<ProjectSectionHead icon="users" title="成员策略" meta={`${project.members.length} people`} />
<ProjectSectionHead icon="users" title={t("projects.section.memberPolicy")} meta={`${project.members.length} people`} />
<ProjectMembers members={project.members} profiles={profiles} />
</section>
</div>
Expand Down
Loading
Loading