dsh-plugin-t-expert 0.2.4 → 0.2.5
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.
- package/README.md +33 -16
- package/THIRD-PARTY-NOTICES +23 -17
- package/data/source.json +3 -88
- package/data/team-profiles.py +1 -1
- package/data/zh/COVERAGE.json +1 -1
- package/lib/catalog.js +206 -42
- package/lib/client.js +458 -10
- package/lib/i18n.js +37 -5
- package/lib/index.js +315 -22
- package/lib/remote.js +173 -1
- package/lib/squads.js +9 -2
- package/package.json +2 -4
- package/vendor/dsh-agent-teams/VENDOR.md +0 -53
package/lib/client.js
CHANGED
|
@@ -19723,6 +19723,7 @@ var client_bundle_default = 'window.__ModuleLoader__.load({\n id: "dsh-plugin-t-
|
|
|
19723
19723
|
var NS = "t-team";
|
|
19724
19724
|
var PLUGIN_ID = "dsh-plugin-t-expert";
|
|
19725
19725
|
var DIVISION_FALLBACK = "specialized";
|
|
19726
|
+
var NEW_DIVISION = "__new";
|
|
19726
19727
|
var zh = {
|
|
19727
19728
|
"settings.title": "T\u4E13\u5BB6",
|
|
19728
19729
|
"settings.loading": "\u6B63\u5728\u8BFB\u53D6\u540D\u518C\u2026",
|
|
@@ -19761,6 +19762,7 @@ var zh = {
|
|
|
19761
19762
|
"button.close": "\u5173\u95ED",
|
|
19762
19763
|
"trigger.group": "T\u4E13\u5BB6 \xB7 {division}",
|
|
19763
19764
|
"tab.experts": "\u4E13\u5BB6",
|
|
19765
|
+
"tab.categories": "\u5206\u7C7B",
|
|
19764
19766
|
"tab.squads": "\u5C0F\u961F",
|
|
19765
19767
|
"tab.teams": "\u56E2\u961F",
|
|
19766
19768
|
"tab.roster": "\u961F\u4F0D",
|
|
@@ -19768,7 +19770,45 @@ var zh = {
|
|
|
19768
19770
|
"roster.squadsHint": "\u9884\u5148\u6311\u597D\u7684\u73ED\u5E95\uFF1A\u6210\u5458\u3001\u522B\u540D\u3001\u542F\u505C\u3002\u7528\u5B83\u5C31\u8BF4 /t <\u5C0F\u961F> <\u76EE\u6807>\uFF0C\u6216\u5728\u8F93\u5165\u6846\u5F39\u7A97\u91CC\u70B9\u300C\u586B\u5165\u300D\uFF1B\u6539\u5B8C\u4FDD\u5B58\u540E\u9700\u91CD\u542F DSH \u624D\u80FD\u7528\u4E8E\u5EFA\u961F\uFF08/t \u5217\u8868\u4F1A\u7ACB\u5373\u5237\u65B0\uFF09\u3002",
|
|
19769
19771
|
"roster.teams": "\u8FD0\u884C\u4E2D\u7684\u56E2\u961F",
|
|
19770
19772
|
"roster.teamsHint": "\u6BCF\u6B21\u7528\u6A21\u677F\u8DD1\u8D77\u6765\u7684\u4E00\u6B21\u5B9E\u4F8B\uFF1A\u53EF\u505C\u6B62\u3001\u770B\u8FDB\u5EA6\u3001\u6253\u5F00\u6D3B\u52A8\u9762\u677F\uFF1B\u5F52\u6863\u540E\u4ECD\u53EF\u5728\u8FD9\u91CC\u56DE\u770B\u3002",
|
|
19771
|
-
"roster.expertsHint": "\u540D\u518C\uFF1A\u80FD\u88AB @ \u53EC\u5524\u3001\u4E5F\u80FD\u88AB\u5C0F\u961F\u6311\u8FDB\u73ED\u5E95\u7684\u4E13\u5BB6\u3002",
|
|
19773
|
+
"roster.expertsHint": "\u540D\u518C\uFF1A\u80FD\u88AB @ \u53EC\u5524\u3001\u4E5F\u80FD\u88AB\u5C0F\u961F\u6311\u8FDB\u73ED\u5E95\u7684\u4E13\u5BB6\u3002\u5E26\u300C\u81EA\u5EFA\u300D\u6807\u8BB0\u7684\u53EF\u4EE5\u5728\u8FD9\u91CC\u6539\u6216\u5220\u3002",
|
|
19774
|
+
"custom.new": "\uFF0B \u65B0\u5EFA\u4E13\u5BB6",
|
|
19775
|
+
"custom.titleNew": "\u65B0\u5EFA\u4E13\u5BB6",
|
|
19776
|
+
"custom.titleEdit": "\u7F16\u8F91\u300C{name}\u300D",
|
|
19777
|
+
"custom.slug": "slug\uFF08\u6587\u4EF6\u540D\uFF1A\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u8FDE\u5B57\u7B26\uFF09",
|
|
19778
|
+
"custom.name": "\u540D\u79F0\uFF08\u4E2D\u6587\uFF09*",
|
|
19779
|
+
"custom.nameEn": "\u82F1\u6587\u540D\uFF08\u53EF\u9009\uFF09",
|
|
19780
|
+
"custom.emoji": "\u56FE\u6807 emoji",
|
|
19781
|
+
"custom.description": "\u4E00\u53E5\u8BDD\u7B80\u4ECB*\uFF08\u7F3A\u7B80\u4ECB\u7684\u4E13\u5BB6\u4E0D\u4F1A\u8FDB\u540D\u518C\uFF09",
|
|
19782
|
+
"custom.body": "\u4EBA\u683C\u6B63\u6587\uFF08Markdown\uFF09*\uFF1A\u5199\u6E05\u5B83\u662F\u8C01\u3001\u600E\u4E48\u5E72\u6D3B\u3001\u4EA4\u4ED8\u4EC0\u4E48",
|
|
19783
|
+
"custom.hint": "\u81EA\u5EFA\u4E13\u5BB6\u5355\u72EC\u5B58\u653E\uFF0C\u4E0E\u968F\u5305\u53D1\u5E03\u7684\u5185\u7F6E\u540D\u518C\u5206\u5F00\u2014\u2014\u5347\u7EA7\u63D2\u4EF6\u4E0D\u4F1A\u8986\u76D6\u5B83\u3002\u5B98\u65B9\u5206\u7C7B\u5C5E\u4E8E\u5305\u5185\u540D\u518C\uFF0C\u81EA\u5EFA\u4E13\u5BB6\u53EA\u80FD\u843D\u5728\u81EA\u5EFA\u5206\u7C7B\u91CC\u3002\u5EFA\u597D\u540E\u8BB0\u5F97\u53BB\u542F\u7528\u5B83\u3002",
|
|
19784
|
+
"custom.division": "\u5206\u7C7B",
|
|
19785
|
+
"custom.divisionNew": "\uFF0B \u65B0\u5EFA\u5206\u7C7B\u2026",
|
|
19786
|
+
"custom.divisionKey": "\u5206\u7C7B\u76EE\u5F55\u540D\uFF08\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u8FDE\u5B57\u7B26\uFF0C\u4EC5 ASCII\uFF09",
|
|
19787
|
+
"custom.divisionLabel": "\u5206\u7C7B\u663E\u793A\u540D\uFF08\u53EF\u9009\uFF0C\u4E2D\u6587\uFF09",
|
|
19788
|
+
"cat.hint": "\u5206\u7C7B\u662F\u4E13\u5BB6\u7684\u5F52\u7C7B\uFF1A\u5B98\u65B9\u5206\u7C7B\u6765\u81EA\u5185\u7F6E\u540D\u518C\uFF08\u53EA\u8BFB\uFF0C\u540D\u5B57\u8DDF\u968F\u4E0A\u6E38\u4E2D\u6587\uFF09\uFF0C\u81EA\u5EFA\u5206\u7C7B\u53EF\u4EE5\u65B0\u5EFA\u3001\u6539\u540D\u3001\u5220\u9664\u3002\u81EA\u5EFA\u4E13\u5BB6\u80FD\u5F52\u5230\u4EFB\u610F\u5206\u7C7B\uFF08\u542B\u5B98\u65B9\u5206\u7C7B\u540D\uFF09\uFF0C\u4F46\u6587\u4EF6\u59CB\u7EC8\u5199\u5728\u4F60\u81EA\u5DF1\u7684\u6570\u636E\u76EE\u5F55\u91CC\uFF0C\u4E0D\u4F1A\u78B0\u5B98\u65B9\u955C\u50CF\u3002",
|
|
19789
|
+
"cat.key": "\u5206\u7C7B\u76EE\u5F55\u540D\uFF08\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u8FDE\u5B57\u7B26\uFF0C\u4EC5 ASCII\uFF09",
|
|
19790
|
+
"cat.label": "\u663E\u793A\u540D\uFF08\u53EF\u9009\uFF0C\u4E2D\u6587\uFF09",
|
|
19791
|
+
"cat.create": "\u521B\u5EFA\u5206\u7C7B",
|
|
19792
|
+
"cat.mine": "\u81EA\u5EFA\u5206\u7C7B",
|
|
19793
|
+
"cat.official": "\u5B98\u65B9\u5206\u7C7B",
|
|
19794
|
+
"cat.officialNote": "\u5B98\u65B9\u5206\u7C7B\u7684\u540D\u5B57\u4E0E\u5B58\u4EA1\u90FD\u8DDF\u968F\u540D\u518C\u540C\u6B65\uFF0C\u8FD9\u91CC\u53EA\u8BFB\u3002",
|
|
19795
|
+
"cat.empty": "\u8FD8\u6CA1\u6709\u81EA\u5EFA\u5206\u7C7B\uFF1A\u4E0A\u9762\u586B\u76EE\u5F55\u540D\u4E0E\u663E\u793A\u540D\u5373\u53EF\u65B0\u5EFA\u4E00\u4E2A\u3002",
|
|
19796
|
+
"cat.officialBadge": "\u5B98\u65B9",
|
|
19797
|
+
"cat.customBadge": "\u81EA\u5EFA",
|
|
19798
|
+
"cat.count": "{count} \u4F4D\uFF08\u81EA\u5EFA {custom}\uFF09",
|
|
19799
|
+
"cat.rename": "\u6539\u540D",
|
|
19800
|
+
"cat.save": "\u4FDD\u5B58",
|
|
19801
|
+
"cat.delete": "\u5220\u9664",
|
|
19802
|
+
"cat.confirmDelete": "\u786E\u8BA4\u5220\u9664",
|
|
19803
|
+
"custom.save": "\u4FDD\u5B58",
|
|
19804
|
+
"custom.saving": "\u4FDD\u5B58\u4E2D\u2026",
|
|
19805
|
+
"custom.cancel": "\u53D6\u6D88",
|
|
19806
|
+
"custom.edit": "\u7F16\u8F91",
|
|
19807
|
+
"custom.delete": "\u5220\u9664",
|
|
19808
|
+
"custom.confirmDelete": "\u786E\u8BA4\u5220\u9664",
|
|
19809
|
+
"custom.deleteHint": "\u5220\u9664\u300C{name}\u300D\uFF1F\u53EA\u5220\u8FD9\u4E2A\u81EA\u5EFA\u4E13\u5BB6\u6587\u4EF6\uFF0C\u4E0D\u53EF\u64A4\u9500\u3002",
|
|
19810
|
+
"custom.badge": "\u81EA\u5EFA",
|
|
19811
|
+
"custom.loadingBody": "\u6B63\u5728\u8BFB\u53D6\u4EBA\u683C\u6B63\u6587\u2026",
|
|
19772
19812
|
"squads.loading": "\u6B63\u5728\u8BFB\u53D6\u5C0F\u961F\u2026",
|
|
19773
19813
|
"squads.count": "{count} \u652F\u5C0F\u961F \xB7 {experts} \u4F4D\u4E13\u5BB6\u53EF\u9009",
|
|
19774
19814
|
"squads.new": "\u65B0\u5EFA\u5C0F\u961F",
|
|
@@ -19867,6 +19907,7 @@ var en = {
|
|
|
19867
19907
|
"button.close": "Close",
|
|
19868
19908
|
"trigger.group": "T Expert \xB7 {division}",
|
|
19869
19909
|
"tab.experts": "Experts",
|
|
19910
|
+
"tab.categories": "Divisions",
|
|
19870
19911
|
"tab.squads": "Squads",
|
|
19871
19912
|
"tab.teams": "Teams",
|
|
19872
19913
|
"tab.roster": "Roster",
|
|
@@ -19874,7 +19915,45 @@ var en = {
|
|
|
19874
19915
|
"roster.squadsHint": "A pre-picked roster: members, aliases, enable/disable. Run it with /t <squad> <goal>, or tap Fill in the composer popup. After saving, restart DSH before the squad can start a team (the /t list refreshes immediately).",
|
|
19875
19916
|
"roster.teams": "Running teams",
|
|
19876
19917
|
"roster.teamsHint": "One instance per run: stop it, watch progress, open the activity panel; archived teams stay reviewable here.",
|
|
19877
|
-
"roster.expertsHint": "The roster: experts available for @-mention and for squad templates.",
|
|
19918
|
+
"roster.expertsHint": "The roster: experts available for @-mention and for squad templates. Custom ones can be edited or deleted here.",
|
|
19919
|
+
"custom.new": "\uFF0B New expert",
|
|
19920
|
+
"custom.titleNew": "New expert",
|
|
19921
|
+
"custom.titleEdit": "Edit \u201C{name}\u201D",
|
|
19922
|
+
"custom.slug": "slug (file name: lowercase letters, digits, hyphen)",
|
|
19923
|
+
"custom.name": "Name (Chinese)*",
|
|
19924
|
+
"custom.nameEn": "English name (optional)",
|
|
19925
|
+
"custom.emoji": "Emoji",
|
|
19926
|
+
"custom.description": "One-line description* (without it the expert never enters the roster)",
|
|
19927
|
+
"custom.body": "Persona body (Markdown)*: who it is, how it works, what it delivers",
|
|
19928
|
+
"custom.hint": "Custom experts live in their own directory, kept apart from the bundled roster \u2014 upgrades never overwrite them. Official divisions belong to that bundled roster, so custom experts can only live in custom divisions. Remember to enable them afterwards.",
|
|
19929
|
+
"custom.division": "Division",
|
|
19930
|
+
"custom.divisionNew": "\uFF0B New division\u2026",
|
|
19931
|
+
"custom.divisionKey": "Division directory name (lowercase ASCII letters, digits, hyphen)",
|
|
19932
|
+
"custom.divisionLabel": "Division display name (optional)",
|
|
19933
|
+
"cat.hint": "A division groups experts: the official ones come from the built-in roster (read-only, names follow upstream Chinese), while custom ones can be created, renamed and deleted. A custom expert can be filed under any division (including an official name), but its file always lives in your own data directory \u2014 the built-in mirror is never touched.",
|
|
19934
|
+
"cat.key": "Division directory name (lowercase ASCII letters, digits, hyphen)",
|
|
19935
|
+
"cat.label": "Display name (optional)",
|
|
19936
|
+
"cat.create": "Create division",
|
|
19937
|
+
"cat.mine": "Custom divisions",
|
|
19938
|
+
"cat.official": "Official divisions",
|
|
19939
|
+
"cat.officialNote": "Official divisions follow the roster sync \u2014 their names and existence are read-only here.",
|
|
19940
|
+
"cat.empty": "No custom division yet: fill in a directory name and a display name above to create one.",
|
|
19941
|
+
"cat.officialBadge": "Official",
|
|
19942
|
+
"cat.customBadge": "Custom",
|
|
19943
|
+
"cat.count": "{count} ({custom} custom)",
|
|
19944
|
+
"cat.rename": "Rename",
|
|
19945
|
+
"cat.save": "Save",
|
|
19946
|
+
"cat.delete": "Delete",
|
|
19947
|
+
"cat.confirmDelete": "Confirm delete",
|
|
19948
|
+
"custom.save": "Save",
|
|
19949
|
+
"custom.saving": "Saving\u2026",
|
|
19950
|
+
"custom.cancel": "Cancel",
|
|
19951
|
+
"custom.edit": "Edit",
|
|
19952
|
+
"custom.delete": "Delete",
|
|
19953
|
+
"custom.confirmDelete": "Confirm delete",
|
|
19954
|
+
"custom.deleteHint": "Delete \u201C{name}\u201D? Only this custom expert file is removed; this cannot be undone.",
|
|
19955
|
+
"custom.badge": "Custom",
|
|
19956
|
+
"custom.loadingBody": "Loading persona body\u2026",
|
|
19878
19957
|
"squads.loading": "Loading squads\u2026",
|
|
19879
19958
|
"squads.count": "{count} squads \xB7 {experts} experts available",
|
|
19880
19959
|
"squads.new": "New squad",
|
|
@@ -19965,6 +20044,11 @@ var CSS = `
|
|
|
19965
20044
|
/* \u8868\u5355\u91CC\u7684\u8F93\u5165\u6846\uFF1A.t-team-input \u7684 flex-basis \u662F\u7ED9\u6A2A\u5411\u641C\u7D22\u6761\u7528\u7684\uFF0C\u7AD6\u5411\u5BB9\u5668\u91CC\u4F1A\u628A\u5B83\u6491\u6210 200px \u9AD8 */
|
|
19966
20045
|
.t-team-field .t-team-input{flex:0 0 auto;width:100%;min-width:0;height:30px}
|
|
19967
20046
|
.t-team-editor .t-team-input{flex:0 0 auto;height:30px}
|
|
20047
|
+
/* \u81EA\u5EFA\u4E13\u5BB6\u7F16\u8F91\u5668\uFF1A\u6B63\u6587\u662F\u591A\u884C Markdown\uFF0C\u6587\u672C\u6846\u8981\u80FD\u62C9\u9AD8 */
|
|
20048
|
+
.t-team-editor textarea.t-team-input{height:auto;min-height:150px;resize:vertical;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:18px}
|
|
20049
|
+
.t-team-editor .t-team-editor-actions{display:flex;gap:8px;justify-content:flex-end}
|
|
20050
|
+
.t-team-badge-custom{display:inline-block;margin-left:6px;padding:0 6px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);font-size:10px;line-height:16px;vertical-align:middle;color:var(--dsw-alias-label-caption)}
|
|
20051
|
+
.t-team-danger{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}
|
|
19968
20052
|
/* \u7AD6\u5411 tab \u5BB9\u5668\u91CC\u7684\u641C\u7D22\u6846\u540C\u7406\uFF1A\u8BBE\u7F6E\u9875\u300C\u961F\u4F0D\u300Dtab \u7684\u641C\u7D22\u6846\u66FE\u7ECF\u88AB\u6491\u6210 200px \u9AD8 */
|
|
19969
20053
|
.t-team-tabbody > .t-team-input{flex:0 0 auto;width:100%;min-width:0;height:30px}
|
|
19970
20054
|
.t-team-picker{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:10px}
|
|
@@ -20019,6 +20103,20 @@ var CSS = `
|
|
|
20019
20103
|
.t-team-card-division{font-size:13px;line-height:18px;margin-top:2px;color:var(--dsw-alias-label-secondary)}
|
|
20020
20104
|
.t-team-card-slug{font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
20021
20105
|
.t-team-card-desc{grid-column:1/-1;margin:0;min-height:60px;font-size:14px;line-height:20px;color:var(--dsw-alias-label-secondary);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}
|
|
20106
|
+
.t-team-cat-list{display:flex;flex-direction:column;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-2);overflow:hidden}
|
|
20107
|
+
.t-team-cat-list[data-scroll="true"]{max-height:300px;overflow-y:auto}
|
|
20108
|
+
.t-team-cat-row{display:flex;flex-direction:row;align-items:center;gap:8px;min-height:28px;padding:3px 10px;border-top:1px solid var(--dsw-alias-border-l2)}
|
|
20109
|
+
.t-team-cat-row:first-child{border-top:0}
|
|
20110
|
+
.t-team-cat-row:hover{background:var(--dsw-alias-interactive-bg-hover)}
|
|
20111
|
+
.t-team-cat-name{flex:0 1 auto;min-width:0;font-size:13px;font-weight:600;line-height:18px;color:var(--dsw-alias-label-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
20112
|
+
.t-team-cat-key{flex:0 1 auto;min-width:0;font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
20113
|
+
.t-team-cat-count{flex:none;margin-left:auto;font-size:12px;line-height:16px;color:var(--dsw-alias-label-secondary);white-space:nowrap}
|
|
20114
|
+
.t-team-cat-actions{flex:none;display:flex;align-items:center;gap:6px}
|
|
20115
|
+
.t-team-cat-row .t-team-input{flex:0 1 180px;min-width:120px;height:26px;padding:2px 8px;font-size:12px}
|
|
20116
|
+
.t-team-cat-row .t-team-chip{flex:none;white-space:nowrap}
|
|
20117
|
+
.t-team-cat-empty{padding:8px 10px;font-size:12px;color:var(--dsw-alias-label-caption)}
|
|
20118
|
+
.t-team-cat-list .t-team-badge{flex:none}
|
|
20119
|
+
.t-team-badge[data-tone="custom"]{color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);background:transparent}
|
|
20022
20120
|
.t-team-switch{position:relative;flex:none;width:28px;height:16px;padding:0;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);cursor:pointer;transition:background .15s ease,border-color .15s ease}
|
|
20023
20121
|
.t-team-switch-knob{position:absolute;top:1px;left:1px;width:12px;height:12px;border-radius:50%;background:var(--dsw-alias-label-tertiary);transition:transform .15s ease,background .15s ease}
|
|
20024
20122
|
.t-team-switch[data-enabled="true"]{background:var(--dsw-alias-button-primary-fill);border-color:var(--dsw-alias-button-primary-fill)}
|
|
@@ -20057,12 +20155,40 @@ var expertSchema = external_exports.object({
|
|
|
20057
20155
|
division: external_exports.string(),
|
|
20058
20156
|
divisionZh: external_exports.string(),
|
|
20059
20157
|
divisionEn: external_exports.string(),
|
|
20060
|
-
conflict: external_exports.boolean().optional()
|
|
20158
|
+
conflict: external_exports.boolean().optional(),
|
|
20159
|
+
/** 用户自建专家:卡片上给编辑/删除入口。 */
|
|
20160
|
+
custom: external_exports.boolean().optional(),
|
|
20161
|
+
/** 自建专家内容指纹:编辑/删除时回传,服务端据此拦并发覆盖。 */
|
|
20162
|
+
hash: external_exports.string().optional()
|
|
20061
20163
|
});
|
|
20062
20164
|
var catalogSchema = external_exports.object({
|
|
20063
20165
|
experts: external_exports.array(expertSchema),
|
|
20064
20166
|
enabled: external_exports.array(external_exports.string()),
|
|
20065
|
-
revision: external_exports.number().int().min(0)
|
|
20167
|
+
revision: external_exports.number().int().min(0),
|
|
20168
|
+
/** 自建专家固定落在这个分类(服务端告知,避免两端各写一份常量)。 */
|
|
20169
|
+
customDivision: external_exports.string().optional(),
|
|
20170
|
+
customDivisionLabel: external_exports.string().optional(),
|
|
20171
|
+
/** 全部分类:官方在前(official=true,名字随包内名册、只读),自建在后(可改名/删除)。 */
|
|
20172
|
+
categories: external_exports.array(external_exports.object({
|
|
20173
|
+
key: external_exports.string(),
|
|
20174
|
+
label: external_exports.string(),
|
|
20175
|
+
official: external_exports.boolean(),
|
|
20176
|
+
count: external_exports.number().int().min(0),
|
|
20177
|
+
customCount: external_exports.number().int().min(0)
|
|
20178
|
+
})).optional()
|
|
20179
|
+
});
|
|
20180
|
+
var customExpertInputSchema = external_exports.object({
|
|
20181
|
+
slug: external_exports.string().min(1).max(128).optional(),
|
|
20182
|
+
name: external_exports.string().min(1).max(200),
|
|
20183
|
+
nameEn: external_exports.string().max(200).optional(),
|
|
20184
|
+
description: external_exports.string().min(1).max(1e3),
|
|
20185
|
+
descriptionEn: external_exports.string().max(1e3).optional(),
|
|
20186
|
+
emoji: external_exports.string().max(16).optional(),
|
|
20187
|
+
body: external_exports.string().min(1).max(6e4),
|
|
20188
|
+
/** 落点分区(自建分区目录名);留空=默认分区。 */
|
|
20189
|
+
division: external_exports.string().max(128).optional(),
|
|
20190
|
+
/** 新建分区时的中文显示名。 */
|
|
20191
|
+
divisionLabel: external_exports.string().max(40).optional()
|
|
20066
20192
|
});
|
|
20067
20193
|
var enabledStateSchema = external_exports.object({
|
|
20068
20194
|
enabled: external_exports.array(external_exports.string()),
|
|
@@ -20174,7 +20300,30 @@ var TYPERT_REMOTE = {
|
|
|
20174
20300
|
], "TTeamTeams", teamsSnapshotSchema),
|
|
20175
20301
|
direct("stopTeam", [
|
|
20176
20302
|
{ name: "teamId", wire: "teamId", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128) } }
|
|
20177
|
-
], "TTeamStopResult", stopResultSchema)
|
|
20303
|
+
], "TTeamStopResult", stopResultSchema),
|
|
20304
|
+
direct("createExpert", [
|
|
20305
|
+
{ name: "expert", wire: "expert", source: "json", codec: { mode: "strict", typeSymbol: "TTeamCustomExpertInput", schema: customExpertInputSchema } }
|
|
20306
|
+
], "TTeamCatalog", catalogSchema),
|
|
20307
|
+
direct("updateExpert", [
|
|
20308
|
+
{ name: "slug", wire: "slug", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128) } },
|
|
20309
|
+
{ name: "expert", wire: "expert", source: "json", codec: { mode: "strict", typeSymbol: "TTeamCustomExpertInput", schema: customExpertInputSchema } },
|
|
20310
|
+
{ name: "expectedHash", wire: "expectedHash", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().max(64) } }
|
|
20311
|
+
], "TTeamCatalog", catalogSchema),
|
|
20312
|
+
direct("deleteExpert", [
|
|
20313
|
+
{ name: "slug", wire: "slug", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128) } },
|
|
20314
|
+
{ name: "expectedHash", wire: "expectedHash", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().max(64) } }
|
|
20315
|
+
], "TTeamCatalog", catalogSchema),
|
|
20316
|
+
direct("createCategory", [
|
|
20317
|
+
{ name: "key", wire: "key", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128) } },
|
|
20318
|
+
{ name: "label", wire: "label", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().max(40) } }
|
|
20319
|
+
], "TTeamCatalog", catalogSchema),
|
|
20320
|
+
direct("updateCategory", [
|
|
20321
|
+
{ name: "key", wire: "key", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128) } },
|
|
20322
|
+
{ name: "label", wire: "label", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().max(40) } }
|
|
20323
|
+
], "TTeamCatalog", catalogSchema),
|
|
20324
|
+
direct("deleteCategory", [
|
|
20325
|
+
{ name: "key", wire: "key", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128) } }
|
|
20326
|
+
], "TTeamCatalog", catalogSchema)
|
|
20178
20327
|
]
|
|
20179
20328
|
};
|
|
20180
20329
|
var catalogCache = /* @__PURE__ */ new Map();
|
|
@@ -20265,6 +20414,8 @@ function SettingsPanel({ t, remote, getActive, refreshCatalog, initialTab, squad
|
|
|
20265
20414
|
const [error62, setError] = import_react.default.useState("");
|
|
20266
20415
|
const [busy, setBusy] = import_react.default.useState(false);
|
|
20267
20416
|
const [promptView, setPromptView] = import_react.default.useState(null);
|
|
20417
|
+
const [editor, setEditor] = import_react.default.useState(null);
|
|
20418
|
+
const [pendingDelete, setPendingDelete] = import_react.default.useState("");
|
|
20268
20419
|
const [tab, setTab] = import_react.default.useState(initialTab ?? "experts");
|
|
20269
20420
|
const reload = import_react.default.useCallback(async (force) => {
|
|
20270
20421
|
try {
|
|
@@ -20315,6 +20466,106 @@ function SettingsPanel({ t, remote, getActive, refreshCatalog, initialTab, squad
|
|
|
20315
20466
|
document.addEventListener("keydown", onKey);
|
|
20316
20467
|
return () => document.removeEventListener("keydown", onKey);
|
|
20317
20468
|
}, [promptView]);
|
|
20469
|
+
const customDivisionLabel = snapshot?.customDivisionLabel ?? "";
|
|
20470
|
+
const categories = snapshot?.categories ?? [];
|
|
20471
|
+
const divisionOptions = (() => {
|
|
20472
|
+
const base = categories.length > 0 ? categories.map((item) => ({ key: item.key, label: item.label })) : [{ key: snapshot?.customDivision ?? "", label: customDivisionLabel }];
|
|
20473
|
+
const fallback = snapshot?.customDivision ?? "";
|
|
20474
|
+
if (fallback !== "" && !base.some((item) => item.key === fallback)) {
|
|
20475
|
+
base.unshift({ key: fallback, label: snapshot?.customDivisionLabel ?? fallback });
|
|
20476
|
+
}
|
|
20477
|
+
return base;
|
|
20478
|
+
})();
|
|
20479
|
+
const editorDivisionOptions = editor !== null && editor.division !== "" && !divisionOptions.some((item) => item.key === editor.division) ? [{ key: editor.division, label: editor.division }, ...divisionOptions] : divisionOptions;
|
|
20480
|
+
function openEditorNew() {
|
|
20481
|
+
setError("");
|
|
20482
|
+
setEditor({
|
|
20483
|
+
mode: "new",
|
|
20484
|
+
slug: "",
|
|
20485
|
+
hash: "",
|
|
20486
|
+
name: "",
|
|
20487
|
+
nameEn: "",
|
|
20488
|
+
emoji: "\u{1F9E9}",
|
|
20489
|
+
description: "",
|
|
20490
|
+
body: "",
|
|
20491
|
+
division: snapshot?.customDivision ?? "",
|
|
20492
|
+
divisionNew: false,
|
|
20493
|
+
divisionKey: "",
|
|
20494
|
+
divisionLabel: "",
|
|
20495
|
+
loading: false,
|
|
20496
|
+
saving: false,
|
|
20497
|
+
error: ""
|
|
20498
|
+
});
|
|
20499
|
+
}
|
|
20500
|
+
async function openEditorEdit(expert) {
|
|
20501
|
+
setError("");
|
|
20502
|
+
setEditor({
|
|
20503
|
+
mode: "edit",
|
|
20504
|
+
slug: expert.slug,
|
|
20505
|
+
hash: expert.hash ?? "",
|
|
20506
|
+
name: expert.name ?? "",
|
|
20507
|
+
nameEn: expert.nameEn ?? "",
|
|
20508
|
+
emoji: expert.emoji || "\u{1F9E9}",
|
|
20509
|
+
description: expert.description ?? "",
|
|
20510
|
+
body: "",
|
|
20511
|
+
division: expert.division ?? "",
|
|
20512
|
+
divisionNew: false,
|
|
20513
|
+
divisionKey: "",
|
|
20514
|
+
divisionLabel: "",
|
|
20515
|
+
loading: true,
|
|
20516
|
+
saving: false,
|
|
20517
|
+
error: ""
|
|
20518
|
+
});
|
|
20519
|
+
try {
|
|
20520
|
+
const data = unwrap(await remote.getPrompt(expert.slug, expert.division), "getPrompt");
|
|
20521
|
+
setEditor((current) => current === null ? current : { ...current, body: data?.prompt ?? "", loading: false });
|
|
20522
|
+
} catch (cause) {
|
|
20523
|
+
setEditor((current) => current === null ? current : {
|
|
20524
|
+
...current,
|
|
20525
|
+
loading: false,
|
|
20526
|
+
error: cause instanceof Error ? cause.message : String(cause)
|
|
20527
|
+
});
|
|
20528
|
+
}
|
|
20529
|
+
}
|
|
20530
|
+
function patchEditor(patch) {
|
|
20531
|
+
setEditor((current) => current === null ? current : { ...current, ...patch });
|
|
20532
|
+
}
|
|
20533
|
+
async function saveEditor() {
|
|
20534
|
+
if (editor === null || editor.saving) return;
|
|
20535
|
+
patchEditor({ saving: true, error: "" });
|
|
20536
|
+
const payload = {
|
|
20537
|
+
slug: editor.slug.trim(),
|
|
20538
|
+
name: editor.name.trim(),
|
|
20539
|
+
nameEn: editor.nameEn.trim(),
|
|
20540
|
+
description: editor.description.trim(),
|
|
20541
|
+
emoji: editor.emoji.trim(),
|
|
20542
|
+
body: editor.body,
|
|
20543
|
+
// 新建分区时用的是输入框里的目录名,否则用下拉选中的分区(空=服务端默认分区)。
|
|
20544
|
+
division: (editor.divisionNew ? editor.divisionKey : editor.division).trim(),
|
|
20545
|
+
divisionLabel: editor.divisionNew ? editor.divisionLabel.trim() : ""
|
|
20546
|
+
};
|
|
20547
|
+
try {
|
|
20548
|
+
const result = editor.mode === "new" ? await remote.createExpert(payload) : await remote.updateExpert(editor.slug, payload, editor.hash);
|
|
20549
|
+
unwrap(result, editor.mode === "new" ? "createExpert" : "updateExpert");
|
|
20550
|
+
setEditor(null);
|
|
20551
|
+
await reload(true);
|
|
20552
|
+
} catch (cause) {
|
|
20553
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
20554
|
+
if (message.includes("custom-slug-taken") || message.includes("custom-name-taken")) await reload(true);
|
|
20555
|
+
patchEditor({ saving: false, error: message });
|
|
20556
|
+
}
|
|
20557
|
+
}
|
|
20558
|
+
async function removeExpert(expert) {
|
|
20559
|
+
setError("");
|
|
20560
|
+
try {
|
|
20561
|
+
unwrap(await remote.deleteExpert(expert.slug, expert.hash ?? ""), "deleteExpert");
|
|
20562
|
+
setPendingDelete("");
|
|
20563
|
+
await reload(true);
|
|
20564
|
+
} catch (cause) {
|
|
20565
|
+
setPendingDelete("");
|
|
20566
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
20567
|
+
}
|
|
20568
|
+
}
|
|
20318
20569
|
const experts = snapshot?.experts ?? [];
|
|
20319
20570
|
const enabledSet = snapshot !== void 0 ? new Set(snapshot.enabled) : /* @__PURE__ */ new Set();
|
|
20320
20571
|
const divisions = [];
|
|
@@ -20367,7 +20618,7 @@ function SettingsPanel({ t, remote, getActive, refreshCatalog, initialTab, squad
|
|
|
20367
20618
|
return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-settings" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-title" }, t("settings.title")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-meta" }, t("settings.loading")), error62 !== "" && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-error" }, t("settings.loadFailed", { detail: error62 })), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-row" }, /* @__PURE__ */ import_react.default.createElement("button", { className: "t-team-chip", type: "button", onClick: () => void reload(true) }, t("settings.retry")))));
|
|
20368
20619
|
}
|
|
20369
20620
|
const enabledCount = snapshot.enabled.length;
|
|
20370
|
-
return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-settings" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-head" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-title" }, t("settings.title")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-meta" }, t("settings.enabledCount", { enabled: enabledCount, total: experts.length }))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabs", role: "tablist" }, [["experts", "tab.experts"], ["roster", "tab.roster"]].map(([key, label]) => /* @__PURE__ */ import_react.default.createElement(
|
|
20621
|
+
return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-settings" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-head" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-title" }, t("settings.title")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-meta" }, t("settings.enabledCount", { enabled: enabledCount, total: experts.length }))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabs", role: "tablist" }, [["experts", "tab.experts"], ["categories", "tab.categories"], ["roster", "tab.roster"]].map(([key, label]) => /* @__PURE__ */ import_react.default.createElement(
|
|
20371
20622
|
"button",
|
|
20372
20623
|
{
|
|
20373
20624
|
className: "t-team-tab",
|
|
@@ -20379,7 +20630,7 @@ function SettingsPanel({ t, remote, getActive, refreshCatalog, initialTab, squad
|
|
|
20379
20630
|
onClick: () => setTab(key)
|
|
20380
20631
|
},
|
|
20381
20632
|
t(label)
|
|
20382
|
-
))), tab === "roster" && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabbody" }, /* @__PURE__ */ import_react.default.createElement(SectionBoundary, { t, reloadKey: tab }, /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-section-head" }, t("roster.squads")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-note" }, t("roster.squadsHint"))), /* @__PURE__ */ import_react.default.createElement(SquadsTab, { t, remote, initialData: squadsPreview, initialDraft: draftPreview }), /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-section-head" }, t("roster.teams")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-note" }, t("roster.teamsHint"))), /* @__PURE__ */ import_react.default.createElement(TeamsTab, { t, remote, initialTeams: teamsPreview }))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabbody", hidden: tab !== "experts" }, /* @__PURE__ */ import_react.default.createElement(SectionBoundary, { t, reloadKey: tab }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-note" }, t("roster.expertsHint")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-bar" }, /* @__PURE__ */ import_react.default.createElement(
|
|
20633
|
+
))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabbody", hidden: tab !== "categories" }, /* @__PURE__ */ import_react.default.createElement(SectionBoundary, { t, reloadKey: tab }, /* @__PURE__ */ import_react.default.createElement(CategoriesTab, { t, remote, categories, onChanged: () => reload(true) }))), tab === "roster" && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabbody" }, /* @__PURE__ */ import_react.default.createElement(SectionBoundary, { t, reloadKey: tab }, /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-section-head" }, t("roster.squads")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-note" }, t("roster.squadsHint"))), /* @__PURE__ */ import_react.default.createElement(SquadsTab, { t, remote, initialData: squadsPreview, initialDraft: draftPreview }), /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-section-head" }, t("roster.teams")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-note" }, t("roster.teamsHint"))), /* @__PURE__ */ import_react.default.createElement(TeamsTab, { t, remote, initialTeams: teamsPreview }))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabbody", hidden: tab !== "experts" }, /* @__PURE__ */ import_react.default.createElement(SectionBoundary, { t, reloadKey: tab }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-note" }, t("roster.expertsHint")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-bar" }, /* @__PURE__ */ import_react.default.createElement(
|
|
20383
20634
|
"input",
|
|
20384
20635
|
{
|
|
20385
20636
|
className: "t-team-input",
|
|
@@ -20425,10 +20676,10 @@ function SettingsPanel({ t, remote, getActive, refreshCatalog, initialTab, squad
|
|
|
20425
20676
|
}
|
|
20426
20677
|
},
|
|
20427
20678
|
t("filter.clear")
|
|
20428
|
-
)), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-meta" }, t("filter.summary", { shown: visible.length, total: experts.length, enabled: enabledSet.size })), error62 !== "" && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-error" }, error62 === "CONFLICT" ? t("settings.conflictRetry") : t("settings.saveFailed", { detail: error62 })), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-groups" }, grouped.map((group) => /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-group", key: group.division }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-division" }, divisionLabel(group.items[0], active), " \xB7 ", group.items.length), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-grid" }, group.items.map((expert) => {
|
|
20679
|
+
), /* @__PURE__ */ import_react.default.createElement("button", { className: "t-team-chip", type: "button", onClick: openEditorNew }, t("custom.new"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-meta" }, t("filter.summary", { shown: visible.length, total: experts.length, enabled: enabledSet.size })), error62 !== "" && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-error" }, error62 === "CONFLICT" ? t("settings.conflictRetry") : t("settings.saveFailed", { detail: error62 })), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-groups" }, grouped.map((group) => /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-group", key: group.division }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-division" }, divisionLabel(group.items[0], active), " \xB7 ", group.items.length), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-grid" }, group.items.map((expert) => {
|
|
20429
20680
|
const on = enabledSet.has(expert.slug);
|
|
20430
20681
|
const locked = busy || expert.conflict === true;
|
|
20431
|
-
return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-card", "data-enabled": on, key: expert.slug }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-card-body" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-avatar" }, expert.emoji || "\u{1F9E9}"), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-identity" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-card-name" }, displayName(expert, active)), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-card-division" }, divisionLabel(expert, active)), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-card-slug" }, expert.slug)), /* @__PURE__ */ import_react.default.createElement("p", { className: "t-team-card-desc" }, displayDescription(expert, active)), expert.conflict === true && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-conflict", style: { gridColumn: "1/-1" } }, t("settings.conflict"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-card-tools" }, /* @__PURE__ */ import_react.default.createElement(
|
|
20682
|
+
return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-card", "data-enabled": on, key: expert.slug }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-card-body" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-avatar" }, expert.emoji || "\u{1F9E9}"), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-identity" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-card-name" }, displayName(expert, active), expert.custom === true && /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-badge-custom" }, t("custom.badge"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-card-division" }, divisionLabel(expert, active)), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-card-slug" }, expert.slug)), /* @__PURE__ */ import_react.default.createElement("p", { className: "t-team-card-desc" }, displayDescription(expert, active)), expert.conflict === true && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-conflict", style: { gridColumn: "1/-1" } }, t("settings.conflict"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-card-tools" }, /* @__PURE__ */ import_react.default.createElement(
|
|
20432
20683
|
"button",
|
|
20433
20684
|
{
|
|
20434
20685
|
className: "t-team-icon-btn",
|
|
@@ -20438,7 +20689,36 @@ function SettingsPanel({ t, remote, getActive, refreshCatalog, initialTab, squad
|
|
|
20438
20689
|
onClick: () => void openPrompt(expert)
|
|
20439
20690
|
},
|
|
20440
20691
|
"\u{1F4C4}"
|
|
20441
|
-
), /* @__PURE__ */ import_react.default.createElement(
|
|
20692
|
+
), expert.custom === true && /* @__PURE__ */ import_react.default.createElement(
|
|
20693
|
+
"button",
|
|
20694
|
+
{
|
|
20695
|
+
className: "t-team-icon-btn",
|
|
20696
|
+
type: "button",
|
|
20697
|
+
title: t("custom.edit"),
|
|
20698
|
+
"aria-label": t("custom.edit"),
|
|
20699
|
+
onClick: () => void openEditorEdit(expert)
|
|
20700
|
+
},
|
|
20701
|
+
"\u270F\uFE0F"
|
|
20702
|
+
), expert.custom === true && (pendingDelete === expert.slug ? /* @__PURE__ */ import_react.default.createElement(
|
|
20703
|
+
"button",
|
|
20704
|
+
{
|
|
20705
|
+
className: "t-team-chip t-team-danger",
|
|
20706
|
+
type: "button",
|
|
20707
|
+
title: t("custom.deleteHint", { name: displayName(expert, active) }),
|
|
20708
|
+
onClick: () => void removeExpert(expert)
|
|
20709
|
+
},
|
|
20710
|
+
t("custom.confirmDelete")
|
|
20711
|
+
) : /* @__PURE__ */ import_react.default.createElement(
|
|
20712
|
+
"button",
|
|
20713
|
+
{
|
|
20714
|
+
className: "t-team-icon-btn",
|
|
20715
|
+
type: "button",
|
|
20716
|
+
title: t("custom.delete"),
|
|
20717
|
+
"aria-label": t("custom.delete"),
|
|
20718
|
+
onClick: () => setPendingDelete(expert.slug)
|
|
20719
|
+
},
|
|
20720
|
+
"\u{1F5D1}"
|
|
20721
|
+
)), /* @__PURE__ */ import_react.default.createElement(
|
|
20442
20722
|
"button",
|
|
20443
20723
|
{
|
|
20444
20724
|
className: "t-team-switch",
|
|
@@ -20462,6 +20742,82 @@ function SettingsPanel({ t, remote, getActive, refreshCatalog, initialTab, squad
|
|
|
20462
20742
|
}
|
|
20463
20743
|
},
|
|
20464
20744
|
/* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-modal", role: "dialog", "aria-modal": "true", "aria-label": t("card.promptTitle", { name: promptView.name }) }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-modal-head" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("card.promptTitle", { name: promptView.name })), /* @__PURE__ */ import_react.default.createElement("button", { className: "t-team-chip", type: "button", onClick: () => setPromptView(null) }, t("card.close"))), /* @__PURE__ */ import_react.default.createElement("pre", { className: "t-team-modal-body" }, promptView.loading ? t("card.promptLoading") : promptView.error !== "" ? t("card.promptFailed", { detail: promptView.error }) : promptView.text === "" ? t("card.promptEmpty") : promptView.text))
|
|
20745
|
+
), editor !== null && /* @__PURE__ */ import_react.default.createElement(
|
|
20746
|
+
"div",
|
|
20747
|
+
{
|
|
20748
|
+
className: "t-team-mask",
|
|
20749
|
+
onClick: (event) => {
|
|
20750
|
+
if (event.target === event.currentTarget && !editor.saving) setEditor(null);
|
|
20751
|
+
}
|
|
20752
|
+
},
|
|
20753
|
+
/* @__PURE__ */ import_react.default.createElement(
|
|
20754
|
+
"div",
|
|
20755
|
+
{
|
|
20756
|
+
className: "t-team-modal",
|
|
20757
|
+
role: "dialog",
|
|
20758
|
+
"aria-modal": "true",
|
|
20759
|
+
"aria-label": editor.mode === "new" ? t("custom.titleNew") : t("custom.titleEdit", { name: editor.name || editor.slug })
|
|
20760
|
+
},
|
|
20761
|
+
/* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-modal-head" }, /* @__PURE__ */ import_react.default.createElement("span", null, editor.mode === "new" ? t("custom.titleNew") : t("custom.titleEdit", { name: editor.name || editor.slug })), /* @__PURE__ */ import_react.default.createElement("button", { className: "t-team-chip", type: "button", disabled: editor.saving, onClick: () => setEditor(null) }, t("custom.cancel"))),
|
|
20762
|
+
/* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-editor", style: { padding: 14, overflow: "auto" } }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-note" }, t("custom.hint")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("custom.division")), /* @__PURE__ */ import_react.default.createElement(
|
|
20763
|
+
"select",
|
|
20764
|
+
{
|
|
20765
|
+
className: "t-team-select",
|
|
20766
|
+
value: editor.divisionNew ? NEW_DIVISION : editor.division,
|
|
20767
|
+
onChange: (event) => {
|
|
20768
|
+
const value = event.target.value;
|
|
20769
|
+
if (value === NEW_DIVISION) patchEditor({ divisionNew: true, divisionKey: "", divisionLabel: "" });
|
|
20770
|
+
else patchEditor({ divisionNew: false, division: value });
|
|
20771
|
+
}
|
|
20772
|
+
},
|
|
20773
|
+
editorDivisionOptions.map((item) => /* @__PURE__ */ import_react.default.createElement("option", { key: item.key, value: item.key }, `${item.label} \xB7 ${item.key}`)),
|
|
20774
|
+
/* @__PURE__ */ import_react.default.createElement("option", { value: NEW_DIVISION }, t("custom.divisionNew"))
|
|
20775
|
+
), editor.divisionNew && /* @__PURE__ */ import_react.default.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 6 } }, /* @__PURE__ */ import_react.default.createElement(
|
|
20776
|
+
"input",
|
|
20777
|
+
{
|
|
20778
|
+
className: "t-team-input",
|
|
20779
|
+
placeholder: t("custom.divisionKey"),
|
|
20780
|
+
spellCheck: false,
|
|
20781
|
+
value: editor.divisionKey,
|
|
20782
|
+
onChange: (event) => patchEditor({ divisionKey: event.target.value })
|
|
20783
|
+
}
|
|
20784
|
+
), /* @__PURE__ */ import_react.default.createElement(
|
|
20785
|
+
"input",
|
|
20786
|
+
{
|
|
20787
|
+
className: "t-team-input",
|
|
20788
|
+
placeholder: t("custom.divisionLabel"),
|
|
20789
|
+
value: editor.divisionLabel,
|
|
20790
|
+
onChange: (event) => patchEditor({ divisionLabel: event.target.value })
|
|
20791
|
+
}
|
|
20792
|
+
))), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("custom.slug")), /* @__PURE__ */ import_react.default.createElement(
|
|
20793
|
+
"input",
|
|
20794
|
+
{
|
|
20795
|
+
className: "t-team-input",
|
|
20796
|
+
value: editor.slug,
|
|
20797
|
+
readOnly: editor.mode === "edit",
|
|
20798
|
+
spellCheck: false,
|
|
20799
|
+
onChange: (event) => patchEditor({ slug: event.target.value })
|
|
20800
|
+
}
|
|
20801
|
+
)), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("custom.name")), /* @__PURE__ */ import_react.default.createElement("input", { className: "t-team-input", value: editor.name, onChange: (event) => patchEditor({ name: event.target.value }) })), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("custom.nameEn")), /* @__PURE__ */ import_react.default.createElement("input", { className: "t-team-input", value: editor.nameEn, onChange: (event) => patchEditor({ nameEn: event.target.value }) })), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("custom.emoji")), /* @__PURE__ */ import_react.default.createElement("input", { className: "t-team-input", maxLength: 8, value: editor.emoji, onChange: (event) => patchEditor({ emoji: event.target.value }) })), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("custom.description")), /* @__PURE__ */ import_react.default.createElement("input", { className: "t-team-input", value: editor.description, onChange: (event) => patchEditor({ description: event.target.value }) })), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, t("custom.body")), /* @__PURE__ */ import_react.default.createElement(
|
|
20802
|
+
"textarea",
|
|
20803
|
+
{
|
|
20804
|
+
className: "t-team-input",
|
|
20805
|
+
value: editor.body,
|
|
20806
|
+
disabled: editor.loading,
|
|
20807
|
+
onChange: (event) => patchEditor({ body: event.target.value })
|
|
20808
|
+
}
|
|
20809
|
+
)), editor.loading && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-meta" }, t("custom.loadingBody")), editor.error !== "" && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-error" }, editor.error), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-editor-actions" }, /* @__PURE__ */ import_react.default.createElement("button", { className: "t-team-chip", type: "button", disabled: editor.saving, onClick: () => setEditor(null) }, t("custom.cancel")), /* @__PURE__ */ import_react.default.createElement(
|
|
20810
|
+
"button",
|
|
20811
|
+
{
|
|
20812
|
+
className: "t-team-chip",
|
|
20813
|
+
type: "button",
|
|
20814
|
+
"data-active": "true",
|
|
20815
|
+
disabled: editor.saving || editor.loading,
|
|
20816
|
+
onClick: () => void saveEditor()
|
|
20817
|
+
},
|
|
20818
|
+
editor.saving ? t("custom.saving") : t("custom.save")
|
|
20819
|
+
)))
|
|
20820
|
+
)
|
|
20465
20821
|
));
|
|
20466
20822
|
}
|
|
20467
20823
|
function squadToInput(squad) {
|
|
@@ -20474,6 +20830,98 @@ function squadToInput(squad) {
|
|
|
20474
20830
|
members: (squad.members ?? []).map((member) => typeof member === "string" ? member : member.slug).filter((slug) => slug !== "")
|
|
20475
20831
|
};
|
|
20476
20832
|
}
|
|
20833
|
+
function CategoriesTab({ t, remote, categories, onChanged }) {
|
|
20834
|
+
const [key, setKey] = import_react.default.useState("");
|
|
20835
|
+
const [label, setLabel] = import_react.default.useState("");
|
|
20836
|
+
const [editing, setEditing] = import_react.default.useState(null);
|
|
20837
|
+
const [pendingDelete, setPendingDelete] = import_react.default.useState("");
|
|
20838
|
+
const [error62, setError] = import_react.default.useState("");
|
|
20839
|
+
const [busy, setBusy] = import_react.default.useState(false);
|
|
20840
|
+
const list = categories ?? [];
|
|
20841
|
+
const mine = list.filter((item) => !item.official);
|
|
20842
|
+
const official = list.filter((item) => item.official);
|
|
20843
|
+
async function run(action) {
|
|
20844
|
+
setBusy(true);
|
|
20845
|
+
setError("");
|
|
20846
|
+
try {
|
|
20847
|
+
unwrap(await action(), "category");
|
|
20848
|
+
setPendingDelete("");
|
|
20849
|
+
setEditing(null);
|
|
20850
|
+
setKey("");
|
|
20851
|
+
setLabel("");
|
|
20852
|
+
await onChanged();
|
|
20853
|
+
} catch (cause) {
|
|
20854
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
20855
|
+
} finally {
|
|
20856
|
+
setBusy(false);
|
|
20857
|
+
}
|
|
20858
|
+
}
|
|
20859
|
+
const row = (item) => /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-cat-row", key: item.key }, /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-cat-name", title: item.label }, item.label), /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-badge", "data-tone": item.official ? void 0 : "custom" }, item.official ? t("cat.officialBadge") : t("cat.customBadge")), /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-cat-key", title: item.key }, item.key), /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-cat-count" }, t("cat.count", { count: item.count, custom: item.customCount })), !item.official && /* @__PURE__ */ import_react.default.createElement("span", { className: "t-team-cat-actions" }, editing !== null && editing.key === item.key ? /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(
|
|
20860
|
+
"input",
|
|
20861
|
+
{
|
|
20862
|
+
className: "t-team-input",
|
|
20863
|
+
value: editing.label,
|
|
20864
|
+
placeholder: t("cat.label"),
|
|
20865
|
+
onChange: (event) => setEditing({ key: item.key, label: event.target.value })
|
|
20866
|
+
}
|
|
20867
|
+
), /* @__PURE__ */ import_react.default.createElement(
|
|
20868
|
+
"button",
|
|
20869
|
+
{
|
|
20870
|
+
className: "t-team-chip",
|
|
20871
|
+
type: "button",
|
|
20872
|
+
disabled: busy,
|
|
20873
|
+
onClick: () => void run(() => remote.updateCategory(item.key, editing.label.trim()))
|
|
20874
|
+
},
|
|
20875
|
+
t("cat.save")
|
|
20876
|
+
), /* @__PURE__ */ import_react.default.createElement("button", { className: "t-team-chip", type: "button", disabled: busy, onClick: () => setEditing(null) }, t("custom.cancel"))) : /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(
|
|
20877
|
+
"button",
|
|
20878
|
+
{
|
|
20879
|
+
className: "t-team-chip",
|
|
20880
|
+
type: "button",
|
|
20881
|
+
disabled: busy,
|
|
20882
|
+
onClick: () => setEditing({ key: item.key, label: item.label })
|
|
20883
|
+
},
|
|
20884
|
+
t("cat.rename")
|
|
20885
|
+
), pendingDelete === item.key ? /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(
|
|
20886
|
+
"button",
|
|
20887
|
+
{
|
|
20888
|
+
className: "t-team-chip",
|
|
20889
|
+
type: "button",
|
|
20890
|
+
"data-active": "true",
|
|
20891
|
+
disabled: busy,
|
|
20892
|
+
onClick: () => void run(() => remote.deleteCategory(item.key))
|
|
20893
|
+
},
|
|
20894
|
+
t("cat.confirmDelete")
|
|
20895
|
+
), /* @__PURE__ */ import_react.default.createElement("button", { className: "t-team-chip", type: "button", disabled: busy, onClick: () => setPendingDelete("") }, t("custom.cancel"))) : /* @__PURE__ */ import_react.default.createElement("button", { className: "t-team-chip", type: "button", disabled: busy, onClick: () => setPendingDelete(item.key) }, t("cat.delete")))));
|
|
20896
|
+
return /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-tabbody" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-note" }, t("cat.hint")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-bar" }, /* @__PURE__ */ import_react.default.createElement(
|
|
20897
|
+
"input",
|
|
20898
|
+
{
|
|
20899
|
+
className: "t-team-input",
|
|
20900
|
+
placeholder: t("cat.key"),
|
|
20901
|
+
spellCheck: false,
|
|
20902
|
+
value: key,
|
|
20903
|
+
onChange: (event) => setKey(event.target.value)
|
|
20904
|
+
}
|
|
20905
|
+
), /* @__PURE__ */ import_react.default.createElement(
|
|
20906
|
+
"input",
|
|
20907
|
+
{
|
|
20908
|
+
className: "t-team-input",
|
|
20909
|
+
placeholder: t("cat.label"),
|
|
20910
|
+
value: label,
|
|
20911
|
+
onChange: (event) => setLabel(event.target.value)
|
|
20912
|
+
}
|
|
20913
|
+
), /* @__PURE__ */ import_react.default.createElement(
|
|
20914
|
+
"button",
|
|
20915
|
+
{
|
|
20916
|
+
className: "t-team-chip",
|
|
20917
|
+
type: "button",
|
|
20918
|
+
"data-active": "true",
|
|
20919
|
+
disabled: busy || key.trim() === "",
|
|
20920
|
+
onClick: () => void run(() => remote.createCategory(key.trim(), label.trim()))
|
|
20921
|
+
},
|
|
20922
|
+
t("cat.create")
|
|
20923
|
+
)), error62 !== "" && /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-error" }, error62), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-section-head" }, t("cat.mine")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-cat-list" }, mine.length === 0 ? /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-cat-empty" }, t("cat.empty")) : mine.map(row)), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-section-head" }, t("cat.official")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-meta" }, t("cat.officialNote")), /* @__PURE__ */ import_react.default.createElement("div", { className: "t-team-cat-list", "data-scroll": "true" }, official.map(row)));
|
|
20924
|
+
}
|
|
20477
20925
|
function SquadsTab({ t, remote, initialData, initialDraft }) {
|
|
20478
20926
|
const [data, setData] = import_react.default.useState(initialData ?? null);
|
|
20479
20927
|
const [draft, setDraft] = import_react.default.useState(initialDraft ?? null);
|