@yadsh/dsh-qa-surface 0.6.1 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (287) hide show
  1. package/README.md +163 -7
  2. package/capability-policy.json +1 -1
  3. package/lib/access/capability-catalog.js +144 -0
  4. package/lib/access/capability-catalog.js.map +1 -0
  5. package/lib/access/model.js +379 -0
  6. package/lib/access/model.js.map +1 -0
  7. package/lib/access/role-repository.js +195 -0
  8. package/lib/access/role-repository.js.map +1 -0
  9. package/lib/access/service.js +380 -0
  10. package/lib/access/service.js.map +1 -0
  11. package/lib/access/skill-metadata.js +234 -0
  12. package/lib/access/skill-metadata.js.map +1 -0
  13. package/lib/account-remotes.js +20 -10
  14. package/lib/account-remotes.js.map +1 -1
  15. package/lib/accounts/errors.js.map +1 -1
  16. package/lib/accounts/file.js.map +1 -1
  17. package/lib/accounts/store.js +202 -3
  18. package/lib/accounts/store.js.map +1 -1
  19. package/lib/admin/conversation-log.js +256 -0
  20. package/lib/admin/conversation-log.js.map +1 -0
  21. package/lib/admin/index.js +17 -0
  22. package/lib/admin/index.js.map +1 -0
  23. package/lib/admin/metrics.js +103 -0
  24. package/lib/admin/metrics.js.map +1 -0
  25. package/lib/admin/paging.js +23 -0
  26. package/lib/admin/paging.js.map +1 -0
  27. package/lib/admin/permissions.js +50 -0
  28. package/lib/admin/permissions.js.map +1 -0
  29. package/lib/admin/quality-store.js +485 -0
  30. package/lib/admin/quality-store.js.map +1 -0
  31. package/lib/admin/queue.js +107 -0
  32. package/lib/admin/queue.js.map +1 -0
  33. package/lib/admin/redaction.js +45 -0
  34. package/lib/admin/redaction.js.map +1 -0
  35. package/lib/admin/service.js +897 -0
  36. package/lib/admin/service.js.map +1 -0
  37. package/lib/admin/session-log.js +142 -0
  38. package/lib/admin/session-log.js.map +1 -0
  39. package/lib/cli.js +9 -6
  40. package/lib/cli.js.map +1 -1
  41. package/lib/client/QaSessionController.js +28 -2
  42. package/lib/client/QaSessionController.js.map +1 -1
  43. package/lib/client/QaSurface.js +143 -5
  44. package/lib/client/QaSurface.js.map +1 -1
  45. package/lib/client/QaTranscriptAdapter.js +1 -0
  46. package/lib/client/QaTranscriptAdapter.js.map +1 -1
  47. package/lib/client/admin/QaAdmin.js +458 -0
  48. package/lib/client/admin/QaAdmin.js.map +1 -0
  49. package/lib/client/admin/format.js +177 -0
  50. package/lib/client/admin/format.js.map +1 -0
  51. package/lib/client/admin/pages/Conversations.js +114 -0
  52. package/lib/client/admin/pages/Conversations.js.map +1 -0
  53. package/lib/client/admin/pages/Overview.js +24 -0
  54. package/lib/client/admin/pages/Overview.js.map +1 -0
  55. package/lib/client/admin/pages/Quality.js +71 -0
  56. package/lib/client/admin/pages/Quality.js.map +1 -0
  57. package/lib/client/admin/pages/Review.js +93 -0
  58. package/lib/client/admin/pages/Review.js.map +1 -0
  59. package/lib/client/admin/pages/Users.js +95 -0
  60. package/lib/client/admin/pages/Users.js.map +1 -0
  61. package/lib/client/admin/routes.js +143 -0
  62. package/lib/client/admin/routes.js.map +1 -0
  63. package/lib/client/admin/shared.js +91 -0
  64. package/lib/client/admin/shared.js.map +1 -0
  65. package/lib/client/admin/styles.js +111 -0
  66. package/lib/client/admin/styles.js.map +1 -0
  67. package/lib/client/components/QaChangelog.js +53 -0
  68. package/lib/client/components/QaChangelog.js.map +1 -1
  69. package/lib/client/components/QaHeader.js +3 -3
  70. package/lib/client/components/QaHeader.js.map +1 -1
  71. package/lib/client/components/QaMessage.js +61 -2
  72. package/lib/client/components/QaMessage.js.map +1 -1
  73. package/lib/client/create-session.js +1 -1
  74. package/lib/client/create-session.js.map +1 -1
  75. package/lib/client/index.js +48 -1
  76. package/lib/client/index.js.map +1 -1
  77. package/lib/client/role/RoleSelector.js +31 -0
  78. package/lib/client/role/RoleSelector.js.map +1 -0
  79. package/lib/client/session-sources.js +37 -1
  80. package/lib/client/session-sources.js.map +1 -1
  81. package/lib/client/settings/card.js +2 -2
  82. package/lib/client/settings/card.js.map +1 -1
  83. package/lib/client/settings/sections.js +0 -1
  84. package/lib/client/settings/sections.js.map +1 -1
  85. package/lib/client/settings-extensions/index.js +1 -0
  86. package/lib/client/settings-extensions/index.js.map +1 -1
  87. package/lib/client/settings-extensions/user-session.js +62 -0
  88. package/lib/client/settings-extensions/user-session.js.map +1 -0
  89. package/lib/client/styles.js +31 -0
  90. package/lib/client/styles.js.map +1 -1
  91. package/lib/client/types.js.map +1 -1
  92. package/lib/client.js +9993 -4848
  93. package/lib/client.js.map +1 -1
  94. package/lib/config-resolvers/defaults.js +0 -2
  95. package/lib/config-resolvers/defaults.js.map +1 -1
  96. package/lib/config.js +0 -249
  97. package/lib/config.js.map +1 -1
  98. package/lib/enforcement/skill-policy.js +172 -0
  99. package/lib/enforcement/skill-policy.js.map +1 -0
  100. package/lib/enforcement/tool-grants.js +151 -0
  101. package/lib/enforcement/tool-grants.js.map +1 -0
  102. package/lib/index.js +224 -42
  103. package/lib/index.js.map +1 -1
  104. package/lib/personal-skills/service.js +10 -3
  105. package/lib/personal-skills/service.js.map +1 -1
  106. package/lib/qa-tools/index.js +4 -0
  107. package/lib/qa-tools/index.js.map +1 -1
  108. package/lib/resolve-config.js +0 -2
  109. package/lib/resolve-config.js.map +1 -1
  110. package/lib/secure-session.js +71 -17
  111. package/lib/secure-session.js.map +1 -1
  112. package/lib/typert.host.js +2237 -202
  113. package/lib/typert.remote-client.d.ts +49 -3
  114. package/lib/typert.remote-client.js +1863 -183
  115. package/lib/types/access/capability-catalog.d.ts +37 -0
  116. package/lib/types/access/model.d.ts +60 -0
  117. package/lib/types/access/role-repository.d.ts +32 -0
  118. package/lib/types/access/service.d.ts +57 -0
  119. package/lib/types/access/skill-metadata.d.ts +53 -0
  120. package/lib/types/account-remotes.d.ts +6 -0
  121. package/lib/types/accounts/errors.d.ts +1 -1
  122. package/lib/types/accounts/file.d.ts +16 -5
  123. package/lib/types/accounts/store.d.ts +83 -3
  124. package/lib/types/admin/conversation-log.d.ts +39 -0
  125. package/lib/types/admin/index.d.ts +24 -0
  126. package/lib/types/admin/metrics.d.ts +29 -0
  127. package/lib/types/admin/paging.d.ts +33 -0
  128. package/lib/types/admin/permissions.d.ts +10 -0
  129. package/lib/types/admin/quality-store.d.ts +82 -0
  130. package/lib/types/admin/queue.d.ts +21 -0
  131. package/lib/types/admin/redaction.d.ts +29 -0
  132. package/lib/types/admin/service.d.ts +105 -0
  133. package/lib/types/admin/session-log.d.ts +53 -0
  134. package/lib/types/client/QaSessionController.d.ts +12 -1
  135. package/lib/types/client/QaSurface.d.ts +7 -1
  136. package/lib/types/client/admin/QaAdmin.d.ts +17 -0
  137. package/lib/types/client/admin/format.d.ts +43 -0
  138. package/lib/types/client/admin/pages/Conversations.d.ts +21 -0
  139. package/lib/types/client/admin/pages/Overview.d.ts +13 -0
  140. package/lib/types/client/admin/pages/Quality.d.ts +18 -0
  141. package/lib/types/client/admin/pages/Review.d.ts +15 -0
  142. package/lib/types/client/admin/pages/Users.d.ts +22 -0
  143. package/lib/types/client/admin/routes.d.ts +60 -0
  144. package/lib/types/client/admin/shared.d.ts +53 -0
  145. package/lib/types/client/admin/styles.d.ts +11 -0
  146. package/lib/types/client/components/QaHeader.d.ts +5 -1
  147. package/lib/types/client/components/QaMessage.d.ts +14 -1
  148. package/lib/types/client/create-session.d.ts +2 -0
  149. package/lib/types/client/role/RoleSelector.d.ts +14 -0
  150. package/lib/types/client/session-sources.d.ts +9 -0
  151. package/lib/types/client/settings/sections.d.ts +0 -1
  152. package/lib/types/client/settings-extensions/index.d.ts +2 -0
  153. package/lib/types/client/settings-extensions/user-session.d.ts +59 -0
  154. package/lib/types/client/types.d.ts +39 -2
  155. package/lib/types/enforcement/skill-policy.d.ts +29 -0
  156. package/lib/types/enforcement/tool-grants.d.ts +84 -0
  157. package/lib/types/index.d.ts +62 -14
  158. package/lib/types/qa-tools/index.d.ts +2 -0
  159. package/lib/types/secure-session.d.ts +10 -1
  160. package/lib/types/types.d.ts +568 -5
  161. package/package.json +2 -2
  162. package/lib/client/settings/sections/documents.js +0 -88
  163. package/lib/client/settings/sections/documents.js.map +0 -1
  164. package/lib/documents/artifacts/ids.js +0 -43
  165. package/lib/documents/artifacts/ids.js.map +0 -1
  166. package/lib/documents/artifacts/manifest.js +0 -66
  167. package/lib/documents/artifacts/manifest.js.map +0 -1
  168. package/lib/documents/artifacts/store.js +0 -169
  169. package/lib/documents/artifacts/store.js.map +0 -1
  170. package/lib/documents/capabilities.js +0 -93
  171. package/lib/documents/capabilities.js.map +0 -1
  172. package/lib/documents/config.js +0 -302
  173. package/lib/documents/config.js.map +0 -1
  174. package/lib/documents/defaults.js +0 -78
  175. package/lib/documents/defaults.js.map +0 -1
  176. package/lib/documents/errors.js +0 -101
  177. package/lib/documents/errors.js.map +0 -1
  178. package/lib/documents/index.js +0 -80
  179. package/lib/documents/index.js.map +0 -1
  180. package/lib/documents/inspect/facts.js +0 -161
  181. package/lib/documents/inspect/facts.js.map +0 -1
  182. package/lib/documents/inspect/zip.js +0 -108
  183. package/lib/documents/inspect/zip.js.map +0 -1
  184. package/lib/documents/markdown/directives.js +0 -135
  185. package/lib/documents/markdown/directives.js.map +0 -1
  186. package/lib/documents/markdown/frontmatter.js +0 -35
  187. package/lib/documents/markdown/frontmatter.js.map +0 -1
  188. package/lib/documents/markdown/normalize.js +0 -113
  189. package/lib/documents/markdown/normalize.js.map +0 -1
  190. package/lib/documents/orchestrator/assets.js +0 -243
  191. package/lib/documents/orchestrator/assets.js.map +0 -1
  192. package/lib/documents/orchestrator/convert-document.js +0 -186
  193. package/lib/documents/orchestrator/convert-document.js.map +0 -1
  194. package/lib/documents/orchestrator/create-document.js +0 -292
  195. package/lib/documents/orchestrator/create-document.js.map +0 -1
  196. package/lib/documents/orchestrator/extract-document.js +0 -162
  197. package/lib/documents/orchestrator/extract-document.js.map +0 -1
  198. package/lib/documents/orchestrator/inspect-document.js +0 -89
  199. package/lib/documents/orchestrator/inspect-document.js.map +0 -1
  200. package/lib/documents/orchestrator/runtime-deps.js +0 -59
  201. package/lib/documents/orchestrator/runtime-deps.js.map +0 -1
  202. package/lib/documents/orchestrator/scope.js +0 -132
  203. package/lib/documents/orchestrator/scope.js.map +0 -1
  204. package/lib/documents/providers/docling.js +0 -247
  205. package/lib/documents/providers/docling.js.map +0 -1
  206. package/lib/documents/providers/libreoffice.js +0 -130
  207. package/lib/documents/providers/libreoffice.js.map +0 -1
  208. package/lib/documents/providers/markitdown.js +0 -89
  209. package/lib/documents/providers/markitdown.js.map +0 -1
  210. package/lib/documents/providers/pandoc.js +0 -161
  211. package/lib/documents/providers/pandoc.js.map +0 -1
  212. package/lib/documents/providers/process.js +0 -164
  213. package/lib/documents/providers/process.js.map +0 -1
  214. package/lib/documents/providers/registry.js +0 -152
  215. package/lib/documents/providers/registry.js.map +0 -1
  216. package/lib/documents/providers/shared.js +0 -75
  217. package/lib/documents/providers/shared.js.map +0 -1
  218. package/lib/documents/runtime.js +0 -114
  219. package/lib/documents/runtime.js.map +0 -1
  220. package/lib/documents/security/file-types.js +0 -188
  221. package/lib/documents/security/file-types.js.map +0 -1
  222. package/lib/documents/security/limits.js +0 -78
  223. package/lib/documents/security/limits.js.map +0 -1
  224. package/lib/documents/security/mime.js +0 -43
  225. package/lib/documents/security/mime.js.map +0 -1
  226. package/lib/documents/security/paths.js +0 -133
  227. package/lib/documents/security/paths.js.map +0 -1
  228. package/lib/documents/templates/registry.js +0 -147
  229. package/lib/documents/templates/registry.js.map +0 -1
  230. package/lib/documents/templates/resolver.js +0 -59
  231. package/lib/documents/templates/resolver.js.map +0 -1
  232. package/lib/documents/tools/convert.js +0 -125
  233. package/lib/documents/tools/convert.js.map +0 -1
  234. package/lib/documents/tools/create.js +0 -187
  235. package/lib/documents/tools/create.js.map +0 -1
  236. package/lib/documents/tools/index.js +0 -41
  237. package/lib/documents/tools/index.js.map +0 -1
  238. package/lib/documents/tools/inspect.js +0 -135
  239. package/lib/documents/tools/inspect.js.map +0 -1
  240. package/lib/documents/tools/shared.js +0 -88
  241. package/lib/documents/tools/shared.js.map +0 -1
  242. package/lib/documents/tools/to-markdown.js +0 -125
  243. package/lib/documents/tools/to-markdown.js.map +0 -1
  244. package/lib/documents/types.js +0 -12
  245. package/lib/documents/types.js.map +0 -1
  246. package/lib/types/client/settings/sections/documents.d.ts +0 -13
  247. package/lib/types/documents/artifacts/ids.d.ts +0 -14
  248. package/lib/types/documents/artifacts/manifest.d.ts +0 -32
  249. package/lib/types/documents/artifacts/store.d.ts +0 -67
  250. package/lib/types/documents/capabilities.d.ts +0 -32
  251. package/lib/types/documents/config.d.ts +0 -27
  252. package/lib/types/documents/defaults.d.ts +0 -161
  253. package/lib/types/documents/errors.d.ts +0 -42
  254. package/lib/types/documents/index.d.ts +0 -63
  255. package/lib/types/documents/inspect/facts.d.ts +0 -43
  256. package/lib/types/documents/inspect/zip.d.ts +0 -28
  257. package/lib/types/documents/markdown/directives.d.ts +0 -39
  258. package/lib/types/documents/markdown/frontmatter.d.ts +0 -15
  259. package/lib/types/documents/markdown/normalize.d.ts +0 -30
  260. package/lib/types/documents/orchestrator/assets.d.ts +0 -55
  261. package/lib/types/documents/orchestrator/convert-document.d.ts +0 -25
  262. package/lib/types/documents/orchestrator/create-document.d.ts +0 -18
  263. package/lib/types/documents/orchestrator/extract-document.d.ts +0 -24
  264. package/lib/types/documents/orchestrator/inspect-document.d.ts +0 -12
  265. package/lib/types/documents/orchestrator/runtime-deps.d.ts +0 -43
  266. package/lib/types/documents/orchestrator/scope.d.ts +0 -52
  267. package/lib/types/documents/providers/docling.d.ts +0 -54
  268. package/lib/types/documents/providers/libreoffice.d.ts +0 -40
  269. package/lib/types/documents/providers/markitdown.d.ts +0 -28
  270. package/lib/types/documents/providers/pandoc.d.ts +0 -42
  271. package/lib/types/documents/providers/process.d.ts +0 -54
  272. package/lib/types/documents/providers/registry.d.ts +0 -68
  273. package/lib/types/documents/providers/shared.d.ts +0 -27
  274. package/lib/types/documents/runtime.d.ts +0 -59
  275. package/lib/types/documents/security/file-types.d.ts +0 -39
  276. package/lib/types/documents/security/limits.d.ts +0 -24
  277. package/lib/types/documents/security/mime.d.ts +0 -13
  278. package/lib/types/documents/security/paths.d.ts +0 -38
  279. package/lib/types/documents/templates/registry.d.ts +0 -50
  280. package/lib/types/documents/templates/resolver.d.ts +0 -30
  281. package/lib/types/documents/tools/convert.d.ts +0 -9
  282. package/lib/types/documents/tools/create.d.ts +0 -14
  283. package/lib/types/documents/tools/index.d.ts +0 -33
  284. package/lib/types/documents/tools/inspect.d.ts +0 -9
  285. package/lib/types/documents/tools/shared.d.ts +0 -77
  286. package/lib/types/documents/tools/to-markdown.d.ts +0 -12
  287. package/lib/types/documents/types.d.ts +0 -294
@@ -0,0 +1,93 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { ISSUE_GROUPS, ISSUE_LABELS, REVIEW_PRIORITY_LABELS, REVIEW_REASON_LABELS, SEVERITY_LABELS, TARGET_LABELS, formatStamp, } from "../format.js";
4
+ import { Badge, FilterField, Pager, adminErrorMessage, useAdminResource, } from "../shared.js";
5
+ /**
6
+ * The review form and its queue.
7
+ *
8
+ * A verdict here is the reviewer's own judgement, deliberately kept apart from
9
+ * the user's thumbs: the reviewer answers "does this match our quality bar",
10
+ * the user answered "was this useful to me". Both are stored against the exact
11
+ * message, and neither rewrites the other.
12
+ */
13
+ const PAGE_SIZE = 20;
14
+ export function AdminReviewQueue(props) {
15
+ const [rows, setRows] = useState([]);
16
+ const [cursor, setCursor] = useState(null);
17
+ const [total, setTotal] = useState(0);
18
+ const load = async (next, append) => {
19
+ const result = await props.api.reviewQueue(props.token, next, PAGE_SIZE);
20
+ if (!result.ok)
21
+ return;
22
+ setTotal(result.value.total);
23
+ setCursor(result.value.nextCursor);
24
+ setRows((current) => append ? [...current, ...result.value.items] : result.value.items);
25
+ };
26
+ const resource = useAdminResource(() => props.api.reviewQueue(props.token, null, PAGE_SIZE), [props.api, props.token]);
27
+ const items = resource.data?.items ?? rows;
28
+ return (_jsxs("section", { className: "dsh-qa-admin__page", "aria-label": "\u041E\u0447\u0435\u0440\u0435\u0434\u044C \u0440\u0430\u0437\u0431\u043E\u0440\u0430", children: [_jsx("div", { className: "dsh-qa-admin__title-row", children: _jsxs("div", { children: [_jsx("h1", { children: "\u041E\u0447\u0435\u0440\u0435\u0434\u044C \u0440\u0430\u0437\u0431\u043E\u0440\u0430" }), _jsx("p", { children: "\u0420\u0430\u0437\u0433\u043E\u0432\u043E\u0440\u044B, \u0442\u0440\u0435\u0431\u0443\u044E\u0449\u0438\u0435 \u0432\u043D\u0438\u043C\u0430\u043D\u0438\u044F: \u043D\u0435\u0433\u0430\u0442\u0438\u0432\u043D\u044B\u0435 \u043E\u0446\u0435\u043D\u043A\u0438, \u0440\u0443\u0447\u043D\u044B\u0435 \u0437\u0430\u043F\u0440\u043E\u0441\u044B \u0438 \u0441\u0431\u043E\u0438 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u0432. \u0420\u0430\u0437\u043E\u0431\u0440\u0430\u043D\u043D\u044B\u0439 \u043F\u0443\u043D\u043A\u0442 \u0443\u0445\u043E\u0434\u0438\u0442 \u0438\u0437 \u043E\u0447\u0435\u0440\u0435\u0434\u0438." })] }) }), resource.error === undefined ? null : (_jsx("p", { className: "dsh-qa-admin__error", role: "alert", children: adminErrorMessage(resource.error) })), items.length === 0 ? (_jsx("p", { className: "dsh-qa-admin__empty", children: resource.loading ? "Загружаю…" : "Очередь пуста." })) : (_jsx("ul", { className: "dsh-qa-admin__queue", children: items.map((row, index) => (_jsxs("li", { className: `dsh-qa-admin__queue-item dsh-qa-admin__queue-item--${row.priority}`, children: [_jsxs("div", { className: "dsh-qa-admin__queue-head", children: [_jsx("span", { className: "dsh-qa-admin__queue-priority", children: REVIEW_PRIORITY_LABELS[row.priority] }), _jsx("span", { children: REVIEW_REASON_LABELS[row.reason] }), _jsx(Badge, { tone: row.status === "reviewed" ? "positive" : "neutral", children: row.status === "reviewed"
29
+ ? "Разобрано"
30
+ : row.status === "needs_followup"
31
+ ? "Нужно вернуться"
32
+ : "Не разобрано" }), _jsx("time", { title: row.raisedAt, children: formatStamp(row.raisedAt) })] }), _jsx("button", { type: "button", onClick: () => props.onOpenConversation(row.conversationId, row.messageId), children: row.title ?? row.conversationId }), _jsxs("span", { className: "dsh-qa-admin__queue-owner", children: [row.displayName, row.subroleId === "" ? "" : ` · ${row.subroleId}`] }), row.issueSummary === undefined ? null : (_jsx("p", { className: "dsh-qa-admin__queue-issues", children: row.issueSummary
33
+ .map((issue) => ISSUE_LABELS[issue])
34
+ .join(", ") }))] }, `${row.conversationId}:${row.messageId ?? ""}:${index}`))) })), _jsx(Pager, { total: resource.data?.total ?? total, shown: items.length, hasMore: (resource.data?.nextCursor ?? cursor) !== null, loading: resource.loading, onMore: () => void load(resource.data?.nextCursor ?? cursor, true), onReset: () => void resource.reload() })] }));
35
+ }
36
+ const SEVERITIES = ["minor", "major", "critical"];
37
+ export function ReviewPanel(props) {
38
+ const [status, setStatus] = useState("reviewed");
39
+ const [issues, setIssues] = useState([]);
40
+ const [severity, setSeverity] = useState("minor");
41
+ const [notes, setNotes] = useState("");
42
+ const [target, setTarget] = useState("");
43
+ const [suggestedAction, setSuggestedAction] = useState("");
44
+ const [busy, setBusy] = useState(false);
45
+ const [error, setError] = useState();
46
+ const [queued, setQueued] = useState(false);
47
+ const toggleIssue = (issue) => {
48
+ setIssues((current) => current.includes(issue)
49
+ ? current.filter((value) => value !== issue)
50
+ : [...current, issue]);
51
+ };
52
+ const save = async () => {
53
+ setBusy(true);
54
+ const input = {
55
+ conversationId: props.detail.conversationId,
56
+ status,
57
+ issues,
58
+ severity,
59
+ ...(notes.trim() === "" ? {} : { notes: notes.trim() }),
60
+ ...(target === "" ? {} : { target }),
61
+ ...(suggestedAction.trim() === ""
62
+ ? {}
63
+ : { suggestedAction: suggestedAction.trim() }),
64
+ };
65
+ const result = await props.api.saveReview(props.token, input);
66
+ setBusy(false);
67
+ if (!result.ok) {
68
+ setError(adminErrorMessage(result.error));
69
+ return;
70
+ }
71
+ setError(undefined);
72
+ setNotes("");
73
+ setSuggestedAction("");
74
+ props.onSaved();
75
+ };
76
+ const queueIt = async () => {
77
+ setBusy(true);
78
+ const result = await props.api.queueConversation(props.token, props.detail.conversationId, null);
79
+ setBusy(false);
80
+ if (!result.ok) {
81
+ setError(adminErrorMessage(result.error));
82
+ return;
83
+ }
84
+ setQueued(true);
85
+ props.onSaved();
86
+ };
87
+ return (_jsxs("aside", { className: "dsh-qa-admin__review", "aria-label": "\u0420\u0430\u0437\u0431\u043E\u0440 \u0440\u0430\u0437\u0433\u043E\u0432\u043E\u0440\u0430", children: [_jsx("h2", { children: "\u0420\u0430\u0437\u0431\u043E\u0440" }), error === undefined ? null : (_jsx("p", { className: "dsh-qa-admin__error", role: "alert", children: error })), props.detail.reviews.length === 0 ? null : (_jsx("ul", { className: "dsh-qa-admin__reviews", children: props.detail.reviews.map((review) => (_jsxs("li", { children: [_jsxs("div", { children: [_jsx(Badge, { tone: review.status === "reviewed" ? "positive" : "negative", children: review.status === "reviewed"
88
+ ? "Разобрано"
89
+ : "Нужно вернуться" }), _jsx("span", { children: SEVERITY_LABELS[review.severity] }), _jsx("time", { title: review.createdAt, children: formatStamp(review.createdAt) })] }), review.issues.length === 0 ? null : (_jsx("p", { children: review.issues.map((issue) => ISSUE_LABELS[issue]).join(", ") })), review.notes === undefined ? null : _jsx("p", { children: review.notes }), review.target === undefined ? null : (_jsxs("p", { children: ["\u041F\u0440\u0438\u0447\u0438\u043D\u0430: ", TARGET_LABELS[review.target], review.suggestedAction === undefined
90
+ ? ""
91
+ : ` — ${review.suggestedAction}`] }))] }, review.id))) })), props.canReview ? (_jsxs(_Fragment, { children: [_jsx(FilterField, { label: "\u0421\u0442\u0430\u0442\u0443\u0441", children: _jsxs("select", { value: status, onChange: (event) => setStatus(event.currentTarget.value), children: [_jsx("option", { value: "reviewed", children: "\u0420\u0430\u0437\u043E\u0431\u0440\u0430\u043D\u043E" }), _jsx("option", { value: "needs_followup", children: "\u041D\u0443\u0436\u043D\u043E \u0432\u0435\u0440\u043D\u0443\u0442\u044C\u0441\u044F" })] }) }), _jsxs("fieldset", { className: "dsh-qa-admin__issues", children: [_jsx("legend", { children: "\u041F\u0440\u043E\u0431\u043B\u0435\u043C\u044B" }), ISSUE_GROUPS.map((group) => (_jsxs("div", { children: [_jsx("h4", { children: group.title }), group.issues.map((issue) => (_jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: issues.includes(issue), onChange: () => toggleIssue(issue) }), ISSUE_LABELS[issue]] }, issue)))] }, group.title)))] }), _jsx(FilterField, { label: "\u0412\u0430\u0436\u043D\u043E\u0441\u0442\u044C", children: _jsx("select", { value: severity, onChange: (event) => setSeverity(event.currentTarget.value), children: SEVERITIES.map((value) => (_jsx("option", { value: value, children: SEVERITY_LABELS[value] }, value))) }) }), _jsx(FilterField, { label: "\u041A\u0443\u0434\u0430 \u043D\u0430\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u0438\u0441\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435", children: _jsxs("select", { value: target, onChange: (event) => setTarget(event.currentTarget.value), children: [_jsx("option", { value: "", children: "\u041D\u0435 \u0443\u043A\u0430\u0437\u0430\u043D\u043E" }), Object.keys(TARGET_LABELS).map((value) => (_jsx("option", { value: value, children: TARGET_LABELS[value] }, value)))] }) }), _jsx(FilterField, { label: "\u0427\u0442\u043E \u0441\u0434\u0435\u043B\u0430\u0442\u044C", children: _jsx("input", { type: "text", value: suggestedAction, onChange: (event) => setSuggestedAction(event.currentTarget.value), placeholder: "\u041D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: \u0434\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0440\u0435\u0433\u043B\u0430\u043C\u0435\u043D\u0442 \u0432 \u0431\u0430\u0437\u0443 \u0437\u043D\u0430\u043D\u0438\u0439" }) }), _jsx(FilterField, { label: "\u0417\u0430\u043C\u0435\u0442\u043A\u0438", children: _jsx("textarea", { value: notes, rows: 4, onChange: (event) => setNotes(event.currentTarget.value) }) }), _jsxs("div", { className: "dsh-qa-admin__actions", children: [_jsx("button", { type: "button", className: "dsh-qa-admin__primary", disabled: busy, onClick: () => void save(), children: "\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u0440\u0430\u0437\u0431\u043E\u0440" }), _jsx("button", { type: "button", disabled: busy || queued, onClick: () => void queueIt(), children: queued ? "В очереди" : "Отправить на разбор" })] })] })) : (_jsx("p", { className: "dsh-qa-admin__empty", children: "\u041A\u043B\u0430\u0441\u0441\u0438\u0444\u0438\u0446\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0440\u0430\u0437\u0433\u043E\u0432\u043E\u0440\u044B \u043C\u043E\u0436\u0435\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u0440\u0435\u0432\u044C\u044E\u0435\u0440 \u0438\u043B\u0438 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440." }))] }));
92
+ }
93
+ //# sourceMappingURL=Review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Review.js","sourceRoot":"","sources":["../../../../src/client/admin/pages/Review.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useState } from "react";
3
+ import { ADMIN_ROLE_LABELS, formatCount, formatStamp } from "../format.js";
4
+ import { Badge, FilterField, Pager, Stamp, adminErrorMessage, useAdminResource, } from "../shared.js";
5
+ const PAGE_SIZE = 25;
6
+ /**
7
+ * Users: the table an administrator triages from, and the detail page that
8
+ * separates authorization from the QA subrole assignment — an admin may work
9
+ * as an analyst without that saying anything about their administrative reach.
10
+ */
11
+ export function AdminUsers(props) {
12
+ const [search, setSearch] = useState("");
13
+ const [role, setRole] = useState("");
14
+ const [status, setStatus] = useState("");
15
+ const [rows, setRows] = useState([]);
16
+ const [cursor, setCursor] = useState(null);
17
+ const [total, setTotal] = useState(0);
18
+ const [error, setError] = useState();
19
+ const [loading, setLoading] = useState(true);
20
+ // One loader owns the page: the filter state rebuilds the callback, which
21
+ // restarts paging from the first page, and "show more" continues from the
22
+ // cursor the Host returned.
23
+ const load = useCallback(async (next, append) => {
24
+ setLoading(true);
25
+ const result = await props.api.users(props.token, {
26
+ search: search === "" ? null : search,
27
+ role: role === "" ? null : role,
28
+ status: status === "" ? null : status,
29
+ }, next, PAGE_SIZE);
30
+ setLoading(false);
31
+ if (!result.ok) {
32
+ setError(adminErrorMessage(result.error));
33
+ return;
34
+ }
35
+ setError(undefined);
36
+ setTotal(result.value.total);
37
+ setCursor(result.value.nextCursor);
38
+ setRows((current) => append ? [...current, ...result.value.items] : result.value.items);
39
+ }, [props.api, props.token, search, role, status]);
40
+ useEffect(() => {
41
+ void load(null, false);
42
+ }, [load]);
43
+ return (_jsxs("section", { className: "dsh-qa-admin__page", "aria-label": "\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0438", children: [_jsx("div", { className: "dsh-qa-admin__title-row", children: _jsxs("div", { children: [_jsx("h1", { children: "\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0438" }), _jsx("p", { children: "\u0410\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u0438\u0432\u043D\u0430\u044F \u0440\u043E\u043B\u044C \u0438 \u043F\u0440\u043E\u0444\u0438\u043B\u0438 \u0430\u0433\u0435\u043D\u0442\u0430 \u043D\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u044E\u0442\u0441\u044F \u043D\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E. \u0423\u0434\u0430\u043B\u0435\u043D\u0438\u044F \u043D\u0435\u0442: \u0438\u0441\u0442\u043E\u0440\u0438\u044E \u0440\u0430\u0437\u0433\u043E\u0432\u043E\u0440\u043E\u0432 \u0441\u043E\u0445\u0440\u0430\u043D\u044F\u0435\u0442 \u043E\u0442\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u0435." })] }) }), _jsxs("div", { className: "dsh-qa-admin__filters", children: [_jsx(FilterField, { label: "\u041F\u043E\u0438\u0441\u043A", children: _jsx("input", { type: "search", value: search, placeholder: "\u0418\u043C\u044F \u0438\u043B\u0438 \u0430\u0434\u0440\u0435\u0441", onChange: (event) => setSearch(event.currentTarget.value) }) }), _jsx(FilterField, { label: "\u0420\u043E\u043B\u044C", children: _jsxs("select", { value: role, onChange: (event) => setRole(event.currentTarget.value), children: [_jsx("option", { value: "", children: "\u041B\u044E\u0431\u0430\u044F" }), _jsx("option", { value: "admin", children: "\u0410\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440" }), _jsx("option", { value: "reviewer", children: "\u0420\u0435\u0432\u044C\u044E\u0435\u0440" }), _jsx("option", { value: "user", children: "\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C" })] }) }), _jsx(FilterField, { label: "\u0421\u0442\u0430\u0442\u0443\u0441", children: _jsxs("select", { value: status, onChange: (event) => setStatus(event.currentTarget.value), children: [_jsx("option", { value: "", children: "\u041B\u044E\u0431\u043E\u0439" }), _jsx("option", { value: "active", children: "\u0410\u043A\u0442\u0438\u0432\u043D\u044B\u0435" }), _jsx("option", { value: "disabled", children: "\u041E\u0442\u043A\u043B\u044E\u0447\u0451\u043D\u043D\u044B\u0435" })] }) })] }), error === undefined ? null : (_jsx("p", { className: "dsh-qa-admin__error", role: "alert", children: error })), rows.length === 0 ? (_jsx("p", { className: "dsh-qa-admin__empty", children: loading ? "Загружаю…" : "Никого не нашлось." })) : (_jsxs("table", { className: "dsh-qa-admin__table", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C" }), _jsx("th", { children: "\u0421\u0442\u0430\u0442\u0443\u0441" }), _jsx("th", { children: "\u0420\u043E\u043B\u044C" }), _jsx("th", { children: "\u041F\u0440\u043E\u0444\u0438\u043B\u0438 QA" }), _jsx("th", { children: "\u041F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u0439 \u0432\u0445\u043E\u0434" }), _jsx("th", { children: "\u0420\u0430\u0437\u0433\u043E\u0432\u043E\u0440\u044B" }), _jsx("th", { children: "\u041E\u0446\u0435\u043D\u043A\u0438" }), _jsx("th", {})] }) }), _jsx("tbody", { children: rows.map((row) => (_jsxs("tr", { children: [_jsxs("td", { children: [_jsx("strong", { children: row.fullName === "" ? row.displayName : row.fullName }), _jsx("small", { children: row.email })] }), _jsx("td", { children: row.disabled ? (_jsx(Badge, { tone: "negative", children: "\u041E\u0442\u043A\u043B\u044E\u0447\u0451\u043D" })) : (_jsx(Badge, { tone: "positive", children: "\u0410\u043A\u0442\u0438\u0432\u0435\u043D" })) }), _jsx("td", { children: ADMIN_ROLE_LABELS[row.role] }), _jsx("td", { children: row.access.allowedSubroles.join(", ") || "—" }), _jsx("td", { children: _jsx(Stamp, { value: row.lastLoginAt ?? undefined }) }), _jsx("td", { children: formatCount(row.conversations) }), _jsx("td", { children: formatCount(row.feedbackGiven) }), _jsx("td", { children: _jsx("button", { type: "button", onClick: () => props.onOpenUser(row.id), children: "\u041E\u0442\u043A\u0440\u044B\u0442\u044C" }) })] }, row.id))) })] })), _jsx(Pager, { total: total, shown: rows.length, hasMore: cursor !== null, loading: loading, onMore: () => void load(cursor, true), onReset: () => void load(null, false) })] }));
44
+ }
45
+ /** Authorization, assignment and the activity counters of one account. */
46
+ export function AdminUserDetail(props) {
47
+ const resource = useAdminResource(() => props.api.user(props.token, props.userId), [props.api, props.token, props.userId]);
48
+ const roles = useAdminResource(() => props.accessApi.admin(props.token), [props.accessApi, props.token]);
49
+ const [error, setError] = useState();
50
+ const [busy, setBusy] = useState(false);
51
+ const detail = resource.data;
52
+ const subroles = (roles.data?.config.subroles ?? []).filter(({ enabled }) => enabled);
53
+ const write = async (update) => {
54
+ setBusy(true);
55
+ const result = await props.api.updateUser(props.token, props.userId, update);
56
+ setBusy(false);
57
+ if (!result.ok) {
58
+ setError(adminErrorMessage(result.error));
59
+ return;
60
+ }
61
+ setError(undefined);
62
+ await resource.reload();
63
+ };
64
+ if (resource.error !== undefined) {
65
+ return (_jsxs("section", { className: "dsh-qa-admin__page", children: [_jsx("p", { className: "dsh-qa-admin__error", role: "alert", children: adminErrorMessage(resource.error) }), _jsx("button", { type: "button", onClick: props.onBack, children: "\u041A \u0441\u043F\u0438\u0441\u043A\u0443" })] }));
66
+ }
67
+ if (detail === undefined) {
68
+ return (_jsx("section", { className: "dsh-qa-admin__page", children: _jsx("p", { className: "dsh-qa-admin__empty", children: "\u0417\u0430\u0433\u0440\u0443\u0436\u0430\u044E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F\u2026" }) }));
69
+ }
70
+ const access = detail.user.access;
71
+ const toggleSubrole = (id) => {
72
+ const allowed = access.allowedSubroles.includes(id)
73
+ ? access.allowedSubroles.filter((value) => value !== id)
74
+ : [...access.allowedSubroles, id];
75
+ if (allowed.length === 0) {
76
+ setError("Нужен хотя бы один доступный профиль QA.");
77
+ return;
78
+ }
79
+ const defaultSubrole = allowed.includes(access.defaultSubrole)
80
+ ? access.defaultSubrole
81
+ : allowed[0];
82
+ void write({ access: { allowedSubroles: allowed, defaultSubrole } });
83
+ };
84
+ return (_jsxs("section", { className: "dsh-qa-admin__page", "aria-label": "\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C", children: [_jsx("div", { className: "dsh-qa-admin__title-row", children: _jsxs("div", { children: [_jsx("button", { type: "button", onClick: props.onBack, children: "\u2190 \u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0438" }), _jsx("h1", { children: detail.user.fullName === ""
85
+ ? detail.user.displayName
86
+ : detail.user.fullName }), _jsxs("p", { children: [detail.user.email, " \u00B7 \u0441\u043E\u0437\u0434\u0430\u043D ", formatStamp(detail.user.createdAt), " \u00B7 \u0432\u0445\u043E\u0434 ", formatStamp(detail.user.lastLoginAt ?? undefined)] })] }) }), error === undefined ? null : (_jsx("p", { className: "dsh-qa-admin__error", role: "alert", children: error })), _jsxs("div", { className: "dsh-qa-admin__columns", children: [_jsxs("section", { className: "dsh-qa-admin__panel", children: [_jsx("h2", { children: "\u0414\u043E\u0441\u0442\u0443\u043F" }), _jsx(FilterField, { label: "\u0410\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u0438\u0432\u043D\u0430\u044F \u0440\u043E\u043B\u044C", children: _jsxs("select", { value: detail.user.role, disabled: busy, onChange: (event) => void write({
87
+ role: event.currentTarget.value,
88
+ }), children: [_jsx("option", { value: "user", children: "\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C" }), _jsx("option", { value: "reviewer", children: "\u0420\u0435\u0432\u044C\u044E\u0435\u0440" }), _jsx("option", { value: "admin", children: "\u0410\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440" })] }) }), _jsx(FilterField, { label: "\u0421\u0442\u0430\u0442\u0443\u0441", children: _jsx("button", { type: "button", disabled: busy, onClick: () => void write({ disabled: !detail.user.disabled }), children: detail.user.disabled ? "Включить" : "Отключить" }) }), _jsx("h3", { children: "\u0414\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0435 \u043F\u0440\u043E\u0444\u0438\u043B\u0438 QA" }), _jsx("ul", { className: "dsh-qa-admin__checks", children: subroles.map((role) => (_jsx("li", { children: _jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: access.allowedSubroles.includes(role.id), disabled: busy, onChange: () => toggleSubrole(role.id) }), role.name] }) }, role.id))) }), _jsx(FilterField, { label: "\u041F\u0440\u043E\u0444\u0438\u043B\u044C \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E", children: _jsx("select", { value: access.defaultSubrole, disabled: busy || access.allowedSubroles.length === 0, onChange: (event) => void write({
89
+ access: {
90
+ allowedSubroles: access.allowedSubroles,
91
+ defaultSubrole: event.currentTarget.value,
92
+ },
93
+ }), children: access.allowedSubroles.map((id) => (_jsx("option", { value: id, children: subroles.find((role) => role.id === id)?.name ?? id }, id))) }) }), _jsx("h3", { children: "\u0414\u0435\u0439\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0435 \u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E\u0441\u0442\u0438" }), _jsx("ul", { className: "dsh-qa-admin__effective", children: detail.effective.map((row) => (_jsxs("li", { children: [_jsx("strong", { children: row.name }), _jsxs("span", { children: [formatCount(row.tools), " \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u0432 \u00B7", " ", formatCount(row.skills), " \u043D\u0430\u0432\u044B\u043A\u043E\u0432"] })] }, row.subroleId))) })] }), _jsxs("section", { className: "dsh-qa-admin__panel", children: [_jsx("h2", { children: "\u0410\u043A\u0442\u0438\u0432\u043D\u043E\u0441\u0442\u044C" }), _jsxs("dl", { className: "dsh-qa-admin__facts", children: [_jsx("dt", { children: "\u0420\u0430\u0437\u0433\u043E\u0432\u043E\u0440\u044B" }), _jsx("dd", { children: formatCount(detail.activity.conversations) }), _jsx("dt", { children: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F" }), _jsx("dd", { children: formatCount(detail.activity.messages) }), _jsx("dt", { children: "\u041F\u043E\u043B\u043E\u0436\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u043E\u0446\u0435\u043D\u043A\u0438" }), _jsx("dd", { children: formatCount(detail.activity.positiveRatings) }), _jsx("dt", { children: "\u041D\u0435\u0433\u0430\u0442\u0438\u0432\u043D\u044B\u0435 \u043E\u0446\u0435\u043D\u043A\u0438" }), _jsx("dd", { children: formatCount(detail.activity.negativeRatings) })] }), _jsxs("div", { className: "dsh-qa-admin__actions", children: [_jsx("button", { type: "button", onClick: () => props.onOpenConversations(detail.user.id), children: "\u0420\u0430\u0437\u0433\u043E\u0432\u043E\u0440\u044B \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F" }), _jsx("button", { type: "button", onClick: props.onOpenAudit, children: "\u0418\u0441\u0442\u043E\u0440\u0438\u044F \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0439" })] })] })] })] }));
94
+ }
95
+ //# sourceMappingURL=Users.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Users.js","sourceRoot":"","sources":["../../../../src/client/admin/pages/Users.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,143 @@
1
+ /**
2
+ * The admin console's route model.
3
+ *
4
+ * The console lives under one host route (`/qa/admin`) and gives every entity
5
+ * with its own identity its own path, because a review finding is something
6
+ * people paste into a chat. Parsing and serializing live here, away from the
7
+ * components, so the mapping is testable without a DOM.
8
+ */
9
+ /** The console's own base path under the surface route. */
10
+ export function adminBasePath(routePath) {
11
+ return `${routePath === "/" ? "" : routePath}/admin`;
12
+ }
13
+ /**
14
+ * Whether a pathname addresses the console at all. Sections and entities each
15
+ * own a path under the base ({@link adminPath}), and the surface hosting the
16
+ * console must stay the console while any of them is open, so the test is by
17
+ * prefix. An equality test against the base alone unmounts the console on the
18
+ * first navigation inside it, and every deep link lands in the chat instead.
19
+ */
20
+ export function isAdminPath(pathname, routePath) {
21
+ const base = adminBasePath(routePath);
22
+ const trimmed = pathname.replace(/\/+$/u, "");
23
+ return trimmed === base || trimmed.startsWith(`${base}/`);
24
+ }
25
+ /** Path segments after `/qa/admin`, without the leading slash. */
26
+ export function adminSegments(pathname, routePath) {
27
+ const base = adminBasePath(routePath);
28
+ const rest = pathname.startsWith(base) ? pathname.slice(base.length) : "";
29
+ return rest
30
+ .split("/")
31
+ .map((segment) => segment.trim())
32
+ .filter((segment) => segment !== "");
33
+ }
34
+ /**
35
+ * Resolve a pathname into a console route. Unknown segments fall back to the
36
+ * section they live under rather than to an error page: a stale link should
37
+ * still land the reviewer somewhere useful.
38
+ */
39
+ export function parseAdminRoute(pathname, routePath) {
40
+ const segments = adminSegments(pathname, routePath);
41
+ const [section, ...rest] = segments;
42
+ const param = rest[0];
43
+ switch (section) {
44
+ case undefined:
45
+ case "":
46
+ return { page: "overview" };
47
+ case "users":
48
+ return param === undefined
49
+ ? { page: "users" }
50
+ : { page: "user", userId: decodeURIComponent(param) };
51
+ case "access":
52
+ if (rest[0] === "common")
53
+ return { page: "common" };
54
+ if (rest[0] === "skills")
55
+ return { page: "skills" };
56
+ return { page: "subroles" };
57
+ case "subroles":
58
+ return { page: "subroles" };
59
+ case "skills":
60
+ return { page: "skills" };
61
+ case "common":
62
+ return { page: "common" };
63
+ case "conversations":
64
+ return param === undefined
65
+ ? { page: "conversations" }
66
+ : {
67
+ page: "conversation",
68
+ conversationId: decodeURIComponent(param),
69
+ ...(rest[1] === undefined
70
+ ? {}
71
+ : { messageId: decodeURIComponent(rest[1]) }),
72
+ };
73
+ case "review":
74
+ return { page: "review" };
75
+ case "quality":
76
+ return rest[0] === "analytics"
77
+ ? { page: "quality" }
78
+ : { page: "feedback" };
79
+ case "feedback":
80
+ return { page: "feedback" };
81
+ case "analytics":
82
+ return { page: "quality" };
83
+ case "audit":
84
+ return { page: "audit" };
85
+ default:
86
+ return { page: "overview" };
87
+ }
88
+ }
89
+ /** The pathname for one console route; the inverse of {@link parseAdminRoute}. */
90
+ export function adminPath(routePath, route, search = "") {
91
+ const base = adminBasePath(routePath);
92
+ const suffix = (() => {
93
+ switch (route.page) {
94
+ case "overview":
95
+ return "";
96
+ case "users":
97
+ return "/users";
98
+ case "user":
99
+ return `/users/${encodeURIComponent(route.userId)}`;
100
+ case "subroles":
101
+ return "/access/subroles";
102
+ case "skills":
103
+ return "/access/skills";
104
+ case "common":
105
+ return "/access/common";
106
+ case "conversations":
107
+ return "/conversations";
108
+ case "conversation":
109
+ return `/conversations/${encodeURIComponent(route.conversationId)}${route.messageId === undefined
110
+ ? ""
111
+ : `/${encodeURIComponent(route.messageId)}`}`;
112
+ case "review":
113
+ return "/review";
114
+ case "feedback":
115
+ return "/quality/feedback";
116
+ case "quality":
117
+ return "/quality/analytics";
118
+ case "audit":
119
+ return "/audit";
120
+ }
121
+ })();
122
+ return `${base}${suffix}${search}`;
123
+ }
124
+ /** Which navigation entry is current for one route. */
125
+ export function adminSectionOf(route) {
126
+ switch (route.page) {
127
+ case "user":
128
+ case "users":
129
+ return "users";
130
+ case "subroles":
131
+ case "skills":
132
+ case "common":
133
+ return "access";
134
+ case "conversation":
135
+ case "conversations":
136
+ return "conversations";
137
+ case "feedback":
138
+ return "feedback";
139
+ default:
140
+ return route.page;
141
+ }
142
+ }
143
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/client/admin/routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useState } from "react";
3
+ import { formatRelative } from "./format.js";
4
+ /** The audience-safe text of a refused Remote call. */
5
+ export function errorMessage(error) {
6
+ if (typeof error === "string")
7
+ return error;
8
+ if (error !== null && typeof error === "object" && "message" in error) {
9
+ return String(error.message ?? error);
10
+ }
11
+ return String(error);
12
+ }
13
+ /**
14
+ * The refusal copy a console page shows. The Host sends a coarse reason code
15
+ * on the wire and nothing else, so the wording lives here — one place to edit,
16
+ * and no deployment detail leaks into the browser.
17
+ */
18
+ export function adminErrorMessage(error) {
19
+ const message = errorMessage(error);
20
+ if (/reason: forbidden/u.test(message)) {
21
+ return "У вашей роли нет прав на это действие.";
22
+ }
23
+ if (/reason: auth-required/u.test(message)) {
24
+ return "Сессия истекла: войдите заново.";
25
+ }
26
+ if (/QA accounts are not enabled/u.test(message)) {
27
+ return "Учётные записи на этом стенде выключены.";
28
+ }
29
+ return message;
30
+ }
31
+ /**
32
+ * Load one administrative resource, keeping the previous value visible while
33
+ * it refreshes. Reviewers page through lists while new conversations arrive;
34
+ * blanking the table on every reload would make that unusable.
35
+ */
36
+ export function useAdminResource(load, deps) {
37
+ const [data, setData] = useState();
38
+ const [error, setError] = useState();
39
+ const [loading, setLoading] = useState(true);
40
+ const reload = useCallback(async () => {
41
+ setLoading(true);
42
+ try {
43
+ const result = await load();
44
+ if (result.ok) {
45
+ setData(result.value);
46
+ setError(undefined);
47
+ }
48
+ else {
49
+ setError(errorMessage(result.error));
50
+ }
51
+ }
52
+ catch (cause) {
53
+ setError(errorMessage(cause));
54
+ }
55
+ finally {
56
+ setLoading(false);
57
+ }
58
+ // The caller owns the identity of `load`: every page passes a callback
59
+ // rebuilt from its own state, and lists the state in `deps`.
60
+ }, deps);
61
+ useEffect(() => {
62
+ void reload();
63
+ }, [reload]);
64
+ return { data, error, loading, reload };
65
+ }
66
+ /** A status chip; the modifier class carries the semantic colour. */
67
+ export function Badge(props) {
68
+ return (_jsx("span", { className: `dsh-qa-admin__badge${props.tone === undefined ? "" : ` dsh-qa-admin__badge--${props.tone}`}`, children: props.children }));
69
+ }
70
+ export function Empty(props) {
71
+ return _jsx("p", { className: "dsh-qa-admin__empty", children: props.children });
72
+ }
73
+ /** A relative timestamp with the exact one available on hover. */
74
+ export function Stamp(props) {
75
+ return (_jsx("time", { className: "dsh-qa-admin__stamp", dateTime: props.value, title: props.value, children: props.value === undefined ? "—" : formatRelative(props.value) }));
76
+ }
77
+ export function ErrorLine(props) {
78
+ return props.message === undefined ? null : (_jsx("p", { className: "dsh-qa-admin__error", role: "alert", children: props.message }));
79
+ }
80
+ /**
81
+ * Cursor paging controls. The cursor is opaque to the browser by design: only
82
+ * the Host knows how a page was cut.
83
+ */
84
+ export function Pager(props) {
85
+ return (_jsxs("div", { className: "dsh-qa-admin__pager", children: [_jsxs("span", { children: ["\u041F\u043E\u043A\u0430\u0437\u0430\u043D\u043E ", props.shown, " \u0438\u0437 ", props.total] }), props.hasMore ? (_jsx("button", { type: "button", disabled: props.loading, onClick: props.onMore, children: "\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0435\u0449\u0451" })) : null, props.shown > 0 && props.hasMore ? (_jsx("button", { type: "button", onClick: props.onReset, children: "\u0421\u043D\u0430\u0447\u0430\u043B\u0430" })) : null] }));
86
+ }
87
+ /** One labeled filter control in a table toolbar. */
88
+ export function FilterField(props) {
89
+ return (_jsxs("label", { className: "dsh-qa-admin__filter", children: [_jsx("span", { children: props.label }), props.children] }));
90
+ }
91
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/client/admin/shared.tsx"],"names":[],"mappings":"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"}