diff --git a/.changeset/approvals-zh-nav-action-views.md b/.changeset/approvals-zh-nav-action-views.md new file mode 100644 index 00000000..30bfbcf5 --- /dev/null +++ b/.changeset/approvals-zh-nav-action-views.md @@ -0,0 +1,4 @@ +--- +--- + +`revenue/approvals` (zh-Hans, zh-Hant): the sidebar entry and its group are now spelled as the app's zh-CN pack renders them (待我审批 / 我的工作, Traditional script on zh-Hant), the three `sys_approval_action` views take the approvals plugin's zh-CN labels (最近 / 按执行人 / 全部) without the English gloss, and the **Completed** view is described on all three pages as including cancelled requests, matching the installed plugin's filter. Docs only; nothing ships in the package (#1976). diff --git a/content/docs/revenue/approvals.mdx b/content/docs/revenue/approvals.mdx index ef2fa484..d9459caa 100644 --- a/content/docs/revenue/approvals.mdx +++ b/content/docs/revenue/approvals.mdx @@ -105,7 +105,7 @@ The approvals plugin also ships four built-in list views on the `sys_approval_re | --- | --- | | **My Pending** | Requests still pending where you are one of the approvers | | **I Submitted** | Everything you submitted, in any state | -| **Completed** | Requests that ended — approved, rejected or recalled | +| **Completed** | Requests that ended — approved, rejected, recalled or cancelled | | **All** | Every request, most recently updated first | Read those as a second screen, not as the tabs above. Two names sit on both sides unchanged, and one pair differs by a single word: diff --git a/content/docs/revenue/approvals.zh-Hans.mdx b/content/docs/revenue/approvals.zh-Hans.mdx index 9f3ffcf1..44f12c19 100644 --- a/content/docs/revenue/approvals.zh-Hans.mdx +++ b/content/docs/revenue/approvals.zh-Hans.mdx @@ -81,9 +81,9 @@ approval 节点使用**首次响应**(`first_response`)行为——在每个 ## 在哪里找到待处理的审批 -HotCRM 应用里审批只有一个入口,它挂在 **My Work**(我的工作)分组下——等着你审批的事情本身就是你的工作,所以它与你的任务、商机、工单并列,而不是单独占一个分组。**My Work** 在应用加载时就是展开的,不必先点开分组才能看见它。 +HotCRM 应用里审批只有一个入口,它挂在 **我的工作** 分组下——等着你审批的事情本身就是你的工作,所以它与你的任务、商机、工单并列,而不是单独占一个分组。**我的工作** 在应用加载时就是展开的,不必先点开分组才能看见它。 -- **Inbox**——点开后进入平台的**审批中心**,也就是真正能把待办审批批准或拒绝的那块界面。侧边栏上的 label 就是 **Inbox**,简体中文界面下这一项显示为**待我审批**;应用里没有任何导航条目叫 *Approval Requests*(审批请求)。这个名字不是凭空捏造:它是审批插件给**对象**起的名字(*Approval Request* / *Approval Requests*,简体界面为「审批请求」)——只是本页把它摆在了侧边栏条目的位置上。 +- **待我审批**——点开后进入平台的**审批中心**,也就是真正能把待办审批批准或拒绝的那块界面。侧边栏上这一项的 label 就是 **待我审批**;应用里没有任何导航条目叫 *Approval Requests*(审批请求)。这个名字不是凭空捏造:它是审批插件给**对象**起的名字(*Approval Request* / *Approval Requests*,简体界面为「审批请求」)——只是本页把它摆在了侧边栏条目的位置上。下面会看到,审批中心的第一个页签和对象内置的第一个视图也都叫 **待我审批**——三处同名,却是三样东西。 该条目没有绑定自己的视图。它过去落在 `sys_approval_request` 对象的列表页上,而那个列表是只读的——能看到请求,却动不了它——所以现在改为直接打开审批中心,也就是带**批准** / **拒绝**按钮的那块界面。对象名仍然留在条目上,作用是在没装审批插件的环境里把整个条目隐藏掉,但它已经不是这一项的落点了。 @@ -99,13 +99,13 @@ HotCRM 应用里审批只有一个入口,它挂在 **My Work**(我的工作 ### 对象自带的列表视图是另一块界面 -审批插件同时还在 `sys_approval_request` **对象**上内置了四个列表视图。它们是真实存在、也仍在发货的——只是点 **Inbox** 打不开它们,本应用侧边栏里也没有任何条目能打开: +审批插件同时还在 `sys_approval_request` **对象**上内置了四个列表视图。它们是真实存在、也仍在发货的——只是点侧边栏的 **待我审批** 条目打不开它们,本应用侧边栏里也没有任何条目能打开: | 对象内置视图 | 内容 | | --- | --- | | **待我审批** | 仍在待批、且你是审批人之一的请求 | | **我提交的** | 你提交过的全部请求,不分状态 | -| **已完成** | 已结束的请求——已批准、已拒绝或已撤回 | +| **已完成** | 已结束的请求——已批准、已拒绝、已撤回或已作废 | | **全部** | 全部请求,按最近更新排序 | 请把这四个当成第二块界面,不要和上面的页签混着读。有两个名字在两边一模一样,还有一对只差一个词: @@ -119,7 +119,7 @@ HotCRM 应用里审批只有一个入口,它挂在 **My Work**(我的工作 本页过去列出的三个名字——*Pending My Approval*、*Submitted by Me*、*Recently Approved*——**哪里都不存在**:`src/` 与已安装的审批插件双面零命中,换任何拼写都一样。它们想描述的其实就是 **待我审批**、**我提交的** 和 **已完成**。有一点是随这次改指向新出现的:审批中心的 **我发起的** 页签在英文界面上叫 *Submitted by me*,与幻影名字 *Submitted by Me* 只差一个字母的大小写。那个页签是审批中心里真实存在的一块界面,但它从来不是对象上的视图。 -**Action History**(操作历史)同样不在这个分组里,本应用侧边栏上也没有任何条目叫这个名字。审批的操作留痕本身是真实数据——审批插件把每一次操作存为 `sys_approval_action`,还为它内置了 **Recent**(最近)/ **By Actor**(按执行人)/ **All**(全部)三个视图,每条操作都通过 `request_id` 指回它所属的请求。缺的只是入口:本应用里没有任何导航条目能打开这个对象。 +**Action History**(操作历史)同样不在这个分组里,本应用侧边栏上也没有任何条目叫这个名字。审批的操作留痕本身是真实数据——审批插件把每一次操作存为 `sys_approval_action`,还为它内置了 **最近** / **按执行人** / **全部** 三个视图,每条操作都通过 `request_id` 指回它所属的请求。缺的只是入口:本应用里没有任何导航条目能打开这个对象。 ## 给销售代表的提示 diff --git a/content/docs/revenue/approvals.zh-Hant.mdx b/content/docs/revenue/approvals.zh-Hant.mdx index 29d5c737..2df6f17b 100644 --- a/content/docs/revenue/approvals.zh-Hant.mdx +++ b/content/docs/revenue/approvals.zh-Hant.mdx @@ -83,9 +83,9 @@ approval 節點使用**首次回應**(`first_response`)行為——在每個 ## 在哪裡找到待處理的審批 -HotCRM 應用裡審批只有一個入口,它掛在 **My Work**(我的工作)群組下——等著你審批的事情本身就是你的工作,所以它與你的任務、商機、工單並列,而不是單獨佔一個群組。**My Work** 在應用載入時就是展開的,不必先點開群組才能看見它。 +HotCRM 應用裡審批只有一個入口,它掛在 **我的工作** 群組下——等著你審批的事情本身就是你的工作,所以它與你的任務、商機、工單並列,而不是單獨佔一個群組。**我的工作** 在應用載入時就是展開的,不必先點開群組才能看見它。 -- **Inbox**——點開後進入平台的**審批中心**,也就是真正能把待辦審批批准或拒絕的那塊介面。側邊欄上的 label 就是 **Inbox**(本應用提供 en / zh-CN / ja-JP / es-ES 四種介面語言,簡體中文介面下這一項顯示為「待我审批」);應用裡沒有任何導覽條目叫 *Approval Requests*(審批請求)。這個名字不是憑空捏造:它是審批外掛給**物件**取的名字(*Approval Request* / *Approval Requests*)——只是本頁把它擺在了側邊欄條目的位置上。 +- **待我審批**——點開後進入平台的**審批中心**,也就是真正能把待辦審批批准或拒絕的那塊介面。側邊欄上這一項的 label 就是 **待我審批**(本應用提供 en / zh-CN / ja-JP / es-ES 四種介面語言,簡體中文介面下這一項顯示為「待我审批」);應用裡沒有任何導覽條目叫 *Approval Requests*(審批請求)。這個名字不是憑空捏造:它是審批外掛給**物件**取的名字(*Approval Request* / *Approval Requests*)——只是本頁把它擺在了側邊欄條目的位置上。下面會看到,審批中心的第一個頁籤和物件內建的第一個檢視也都叫 **待我審批**——三處同名,卻是三樣東西。 該條目沒有綁定自己的檢視。它過去落在 `sys_approval_request` 物件的列表頁上,而那個列表是唯讀的——看得到請求,卻動不了它——所以現在改成直接打開審批中心,也就是帶**批准** / **拒絕**按鈕的那塊介面。物件名仍然留在條目上,作用是在沒裝審批外掛的環境裡把整個條目隱藏掉,但它已經不是這一項的落點了。 @@ -101,13 +101,13 @@ HotCRM 應用裡審批只有一個入口,它掛在 **My Work**(我的工作 ### 物件自帶的列表檢視是另一塊介面 -審批外掛同時還在 `sys_approval_request` **物件**上內建了四個列表檢視。它們是真實存在、也仍在出貨的——只是點 **Inbox** 打不開它們,本應用側邊欄裡也沒有任何條目能打開: +審批外掛同時還在 `sys_approval_request` **物件**上內建了四個列表檢視。它們是真實存在、也仍在出貨的——只是點側邊欄的 **待我審批** 條目打不開它們,本應用側邊欄裡也沒有任何條目能打開: | 物件內建檢視 | 內容 | | --- | --- | | **待我審批** | 仍在待批、且你是審批人之一的請求 | | **我提交的** | 你提交過的全部請求,不分狀態 | -| **已完成** | 已結束的請求——已批准、已拒絕或已撤回 | +| **已完成** | 已結束的請求——已批准、已拒絕、已撤回或已作廢 | | **全部** | 全部請求,按最近更新排序 | 請把這四個當成第二塊介面,不要和上面的頁籤混著讀。有兩個名字在兩邊一模一樣,還有一對只差一個詞: @@ -121,7 +121,7 @@ HotCRM 應用裡審批只有一個入口,它掛在 **My Work**(我的工作 本頁過去列出的三個名字——*Pending My Approval*、*Submitted by Me*、*Recently Approved*——**哪裡都不存在**:`src/` 與已安裝的審批外掛雙面零命中,換任何拼寫都一樣。它們想描述的其實就是 **待我審批**、**我提交的** 和 **已完成**。有一點是隨這次改指向新出現的:審批中心的 **我發起的** 頁籤在英文介面上叫 *Submitted by me*,與幻影名字 *Submitted by Me* 只差一個字母的大小寫。那個頁籤是審批中心裡真實存在的一塊介面,但它從來不是物件上的檢視。 -**Action History**(操作歷史)同樣不在這個群組裡,本應用側邊欄上也沒有任何條目叫這個名字。審批的操作留痕本身是真實資料——審批外掛把每一次操作存為 `sys_approval_action`,還為它內建了 **Recent**(最近)/ **By Actor**(按執行人)/ **All**(全部)三個檢視,每條操作都透過 `request_id` 指回它所屬的請求。缺的只是入口:本應用裡沒有任何導覽條目能打開這個物件。 +**Action History**(操作歷史)同樣不在這個群組裡,本應用側邊欄上也沒有任何條目叫這個名字。審批的操作留痕本身是真實資料——審批外掛把每一次操作存為 `sys_approval_action`,還為它內建了 **最近** / **按執行人** / **全部** 三個檢視,每條操作都透過 `request_id` 指回它所屬的請求。缺的只是入口:本應用裡沒有任何導覽條目能打開這個物件。 ## 給銷售代表的提示 diff --git a/test/docs-revenue-approvals-navigation.test.ts b/test/docs-revenue-approvals-navigation.test.ts index 42a88075..d8312d34 100644 --- a/test/docs-revenue-approvals-navigation.test.ts +++ b/test/docs-revenue-approvals-navigation.test.ts @@ -122,7 +122,7 @@ const REQUEST_VIEWS = viewLabels(SysApprovalRequest as unknown as AnyRec); const ACTION_VIEWS = viewLabels(SysApprovalAction as unknown as AnyRec); /** - * The zh-CN labels of the request views, from the plugin's own pack — a Chinese + * The zh-CN labels of the plugin's views, from the plugin's own pack — a Chinese * page spells a view name as the zh-CN value of the pack that owns the object * (#1552). The package exports its schemas but not its locale packs, so the * labels are read off the built bundle with its `\uXXXX` escapes decoded, the @@ -142,22 +142,31 @@ const ZH_CN_PLUGIN_OBJECTS: string = (() => { return end < 0 ? raw.slice(start) : raw.slice(start, start + 1 + end); })(); -const ZH_HANS_REQUEST_VIEWS: string[] = Object.keys( - ((SysApprovalRequest as unknown as AnyRec).listViews ?? {}) as Record, -).map((key) => { - const m = ZH_CN_PLUGIN_OBJECTS.match(new RegExp(`\\b${key}:\\s*\\{\\s*label:\\s*"([^"]+)"`)); - if (!m) throw new Error(`the approvals plugin ships no zh-CN label for view '${key}'`); - return m[1]; -}); +/** The zh-CN labels of one plugin object's views, read from the plugin's pack. */ +const zhHansViews = (schema: AnyRec): string[] => + Object.keys((schema.listViews ?? {}) as Record).map((key) => { + const m = ZH_CN_PLUGIN_OBJECTS.match(new RegExp(`\\b${key}:\\s*\\{\\s*label:\\s*"([^"]+)"`)); + if (!m) throw new Error(`the approvals plugin ships no zh-CN label for view '${key}'`); + return m[1]; + }); + +const ZH_HANS_REQUEST_VIEWS = zhHansViews(SysApprovalRequest as unknown as AnyRec); +const ZH_HANS_ACTION_VIEWS = zhHansViews(SysApprovalAction as unknown as AnyRec); /** * No pack ships Traditional script, so the zh-Hant page spells the same labels * by character conversion only (no word swap) — the convention AGENTS.md sets * for zh-Hant view names. Only the characters these labels use are mapped. */ -const ZH_HANT_REQUEST_VIEWS = ZH_HANS_REQUEST_VIEWS.map((l) => - l.replace(/审/g, '審').replace(/发/g, '發'), -); +const toHant = (l: string): string => + l.replace(/审/g, '審').replace(/发/g, '發').replace(/执/g, '執'); + +const ZH_HANT_REQUEST_VIEWS = ZH_HANS_REQUEST_VIEWS.map(toHant); +const ZH_HANT_ACTION_VIEWS = ZH_HANS_ACTION_VIEWS.map(toHant); + +/** The Inbox entry's label as this app's own zh-CN pack renders it (#1976). */ +const ZH_HANS_INBOX: string = + (packFor('zh-CN') as AnyRec)?.apps?.[CrmApp.name]?.navigation?.nav_approval_requests?.label; /** * Which destination the Inbox entry actually carries, reduced to the @@ -233,8 +242,12 @@ const PAGES = [ file: 'content/docs/revenue/approvals.mdx', lang: 'en', heading: '## Where to find pending approvals', + /** The Inbox entry's label, in this page's language. */ + inboxLabel: 'Inbox', /** The request views' labels, in this page's language. */ requestViews: REQUEST_VIEWS, + /** The action views' labels, in this page's language. */ + actionViews: ACTION_VIEWS, /** The denials the section must actually make, not merely imply. */ denials: [ /\*Approval Requests\* is not a navigation entry anywhere in this app/, @@ -267,7 +280,9 @@ const PAGES = [ file: 'content/docs/revenue/approvals.zh-Hans.mdx', lang: 'zh-Hans', heading: '## 在哪里找到待处理的审批', + inboxLabel: ZH_HANS_INBOX, requestViews: ZH_HANS_REQUEST_VIEWS, + actionViews: ZH_HANS_ACTION_VIEWS, denials: [ /应用里没有任何导航条目叫 \*Approval Requests\*/, /哪里都不存在/, @@ -303,7 +318,9 @@ const PAGES = [ file: 'content/docs/revenue/approvals.zh-Hant.mdx', lang: 'zh-Hant', heading: '## 在哪裡找到待處理的審批', + inboxLabel: toHant(ZH_HANS_INBOX), requestViews: ZH_HANT_REQUEST_VIEWS, + actionViews: ZH_HANT_ACTION_VIEWS, denials: [ /應用裡沒有任何導覽條目叫 \*Approval Requests\*/, /哪裡都不存在/, @@ -527,7 +544,9 @@ describe('revenue/approvals names the navigation that exists (#963, #1162)', () ({ file, heading, + inboxLabel, requestViews, + actionViews, denials, attribution, destinationClaims, @@ -538,7 +557,7 @@ describe('revenue/approvals names the navigation that exists (#963, #1162)', () const section = () => sectionOf(file, heading); it('names the real sidebar item', () => { - expect(section()).toContain('Inbox'); + expect(section()).toContain(inboxLabel); }); /** @@ -613,7 +632,7 @@ describe('revenue/approvals names the navigation that exists (#963, #1162)', () it('lists the audit-trail views too, so "real data, no entry point" is concrete', () => { const text = section(); - expect(ACTION_VIEWS.filter((l) => !text.includes(l))).toEqual([]); + expect(actionViews.filter((l) => !text.includes(l))).toEqual([]); expect(text).toContain(SysApprovalAction.name); });