@stephen1620/dsh-tomato-board 0.1.1 → 0.3.0
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 +44 -14
- package/cordis.patch.yml +1 -1
- package/lib/client.js +1335 -203
- package/lib/client.js.map +1 -1
- package/lib/index.js +248 -11
- package/lib/types/client/StoryPoints.d.ts +7 -0
- package/lib/types/client/Tag.d.ts +21 -0
- package/lib/types/client/TomatoBoard.d.ts +13 -0
- package/lib/types/index.d.ts +1 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -18,20 +18,25 @@ window.__ModuleLoader__.load({
|
|
|
18
18
|
}
|
|
19
19
|
//#endregion
|
|
20
20
|
//#region \0dsh-css:/Users/gengfeng/deepseek-harness/packages/client/tomato-board/src/client/tomato-board.module.css.mjs
|
|
21
|
-
const css = ".Y6kksa_sidebarAction{width:100%;min-height:36px;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;white-space:nowrap;transition:background var(--ds-transition-duration-fast) var(--ds-ease-in-out), border-color var(--ds-transition-duration-fast) var(--ds-ease-in-out);background:0 0;border:0;border-radius:10px;align-items:center;gap:9px;margin:0;padding:0 10px;display:flex}.Y6kksa_sidebarAction:hover{background:var(--dsw-alias-interactive-bg-hover)}.Y6kksa_tomatoIcon{width:18px;height:18px;color:var(--dsw-alias-label-primary-inverted);background:var(--dsw-alias-state-error-primary);border-radius:6px;flex:none;place-items:center;font-size:11px;font-weight:750;display:inline-grid}.Y6kksa_transitionTrigger{align-items:center;gap:6px;display:inline-flex}.Y6kksa_transitionCaption{color:var(--dsw-alias-label-secondary);font-size:12px}.Y6kksa_transitionTrigger strong{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:650}.Y6kksa_transitionDivider{background:var(--dsw-alias-border-l2);width:1px;height:14px;margin:0 2px}.Y6kksa_transitionAction{color:var(--dsw-alias-state-business-primary);font-size:12px;font-weight:650}.Y6kksa_transitionChevron{color:var(--dsw-alias-state-business-primary);transition:transform var(--ds-transition-duration-fast) var(--ds-ease-in-out)}.Y6kksa_transitionTrigger[aria-expanded=true] .Y6kksa_transitionChevron{transform:rotate(180deg)}.Y6kksa_workbench{min-width:0;height:100%;min-height:0;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-base);font-family:var(--dsw-font-family);flex-direction:column;flex:1;display:flex;position:relative}.Y6kksa_createDialog{width:min(480px,100%)}.Y6kksa_dialogBody{flex-direction:column;gap:12px;display:flex}.Y6kksa_dialogBody>span{color:var(--dsw-alias-state-error-primary);font-size:12px;font-weight:700}.Y6kksa_dialogBody code{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;font-size:13px}.Y6kksa_workspaceTrigger{justify-content:space-between;width:100%;display:flex}.Y6kksa_header{border-bottom:1px solid color-mix(in srgb, var(--dsw-alias-border-l2) 72%, transparent);background:color-mix(in srgb, var(--dsw-alias-bg-layer-1) 72%, transparent);backdrop-filter:blur(16px);justify-content:space-between;align-items:center;min-height:52px;padding:8px 16px;display:flex}.Y6kksa_header h1{margin:0;font-size:16px;line-height:22px}.Y6kksa_header p{color:var(--dsw-alias-label-secondary);margin:1px 0 0;font-size:12px;line-height:16px}.Y6kksa_actions{align-items:center;gap:8px;display:flex}.Y6kksa_actions button{border:1px solid var(--dsw-alias-border-l2);min-height:34px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-button-elevated-fill);cursor:pointer;transition:background var(--ds-transition-duration-fast) var(--ds-ease-in-out), border-color var(--ds-transition-duration-fast) var(--ds-ease-in-out);border-radius:10px;padding:0 14px}.Y6kksa_actions button:hover{border-color:var(--dsw-alias-border-l3);background:var(--dsw-alias-button-floating-hover)}.Y6kksa_actions button:disabled{cursor:wait;opacity:.55}.Y6kksa_actions .Y6kksa_headerIconButton{border-radius:8px;width:34px;min-width:34px;height:34px;min-height:34px;padding:0}.Y6kksa_searchField{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:10px;align-items:center;gap:6px;width:220px;min-height:34px;padding:0 8px;display:flex}.Y6kksa_searchField input{min-width:0;color:inherit;font:inherit;background:0 0;border:0;outline:0;flex:1}.Y6kksa_searchField button{border:0;min-height:24px;padding:0 5px}.Y6kksa_filterMenu{position:relative}.Y6kksa_filterMenu summary{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);cursor:pointer;border-radius:10px;place-items:center;width:34px;height:34px;list-style:none;display:grid;position:relative}.Y6kksa_filterMenu summary::-webkit-details-marker{display:none}.Y6kksa_filterMenu summary i{background:var(--dsw-alias-state-error-primary);border-radius:50%;width:5px;height:5px;position:absolute;top:5px;right:5px}.Y6kksa_filterPopover{z-index:10;border:1px solid var(--dsw-alias-border-l2);background:color-mix(in srgb, var(--dsw-alias-bg-layer-2) 94%, transparent);width:min(760px,100vw - 320px);box-shadow:var(--dsw-shadow-lv3);backdrop-filter:blur(18px);border-radius:16px;gap:12px;padding:14px;display:grid;position:absolute;top:calc(100% + 8px);right:0}.Y6kksa_filterRow{align-items:flex-start;gap:12px;display:flex}.Y6kksa_filterRow>span{width:36px;color:var(--dsw-alias-label-secondary);padding-top:7px;font-size:13px}.Y6kksa_filterRow>div{flex-wrap:wrap;flex:1;gap:7px;display:flex}.Y6kksa_filterRow button{min-height:30px;color:var(--dsw-alias-label-secondary);padding:3px 11px}.Y6kksa_filterRow .Y6kksa_selectedFilter{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary);background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 10%, transparent)}.Y6kksa_error{color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-state-error-secondary);border-radius:12px;margin:16px 24px 0;padding:12px 14px}.Y6kksa_notice{color:var(--dsw-alias-label-secondary);margin:0;padding:8px 20px;font-size:11px}.Y6kksa_board{flex:1;align-items:flex-start;gap:12px;padding:8px 12px;display:flex;overflow:auto}.Y6kksa_lane{border:1px solid var(--dsw-alias-border-l2);background:color-mix(in srgb, var(--dsw-alias-bg-module-platform) 86%, transparent);border-radius:16px;flex-direction:column;width:300px;min-width:300px;max-height:100%;display:flex}.Y6kksa_laneHeader{justify-content:space-between;align-items:center;padding:12px 14px 10px;display:flex}.Y6kksa_laneHeader h2{margin:0;font-size:14px}.Y6kksa_laneHeader span{text-align:center;min-width:22px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-overlay);border-radius:999px;padding:2px 6px;font-size:12px}.Y6kksa_cards{padding:0 8px 8px;overflow-y:auto}.Y6kksa_card{border:1px solid var(--dsw-alias-border-l2);min-width:0;max-width:100%;color:inherit;background:color-mix(in srgb, var(--dsw-alias-bg-layer-1) 96%, transparent);box-shadow:var(--dsw-shadow-lv1);text-align:left;transition:background var(--ds-transition-duration-fast) var(--ds-ease-in-out), border-color var(--ds-transition-duration-fast) var(--ds-ease-in-out), box-shadow var(--ds-transition-duration-fast) var(--ds-ease-in-out);cursor:pointer;border-radius:14px;flex-direction:column;gap:7px;margin-top:8px;padding:12px;text-decoration:none;display:flex;overflow:hidden}.Y6kksa_card:hover{border-color:var(--dsw-alias-border-l3);background:var(--dsw-alias-button-floating-hover);box-shadow:var(--dsw-shadow-lv2)}.Y6kksa_cardMuted{opacity:.46;filter:saturate(.2);box-shadow:none}.Y6kksa_cardMuted:hover{opacity:.62}.Y6kksa_card:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.Y6kksa_card strong,.Y6kksa_key,.Y6kksa_meta{overflow-wrap:anywhere;word-break:normal;min-width:0}.Y6kksa_cardTopline{justify-content:space-between;align-items:center;gap:8px;min-width:0;display:flex}.Y6kksa_cardButtons{align-items:center;gap:2px;display:inline-flex}.Y6kksa_muteButton,.Y6kksa_tomatoLink{border-radius:8px;flex:none;place-items:center;width:28px;min-width:28px;height:28px;min-height:28px;padding:0;line-height:1;display:inline-grid}.Y6kksa_muteButton{color:var(--dsw-alias-label-tertiary);font-size:9px}.Y6kksa_muteButton[aria-pressed=true]{color:var(--dsw-alias-label-primary)}.Y6kksa_card strong{font-size:14px;font-weight:600;line-height:1.45}.Y6kksa_key{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:650}.Y6kksa_meta{color:var(--dsw-alias-label-tertiary);font-size:12px}.Y6kksa_empty{color:var(--dsw-alias-label-tertiary);margin:auto}@media (width<=820px){.Y6kksa_header{align-items:flex-start;gap:10px}.Y6kksa_actions{flex-wrap:wrap;justify-content:flex-end}.Y6kksa_searchField{width:170px}}";
|
|
22
|
-
const tagId = "@stephen1620/dsh-tomato-board/tomato-board.module.css";
|
|
23
|
-
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
21
|
+
const css$2 = ".Y6kksa_sidebarAction{width:100%;min-height:36px;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;white-space:nowrap;transition:background var(--ds-transition-duration-fast) var(--ds-ease-in-out), border-color var(--ds-transition-duration-fast) var(--ds-ease-in-out);background:0 0;border:0;border-radius:10px;align-items:center;gap:9px;margin:0;padding:0 10px;display:flex}.Y6kksa_sidebarAction:hover{background:var(--dsw-alias-interactive-bg-hover)}.Y6kksa_topbarAction{border:1px solid var(--dsw-alias-border-l2);min-height:28px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-base);cursor:pointer;font:inherit;white-space:nowrap;border-radius:8px;align-items:center;gap:7px;padding:4px 9px;font-size:12px;font-weight:600;display:inline-flex}.Y6kksa_topbarAction:hover{border-color:color-mix(in srgb, var(--tomato-accent,var(--dsw-alias-state-error-primary)) 45%, var(--dsw-alias-border-l2));background:var(--dsw-alias-interactive-bg-hover)}.Y6kksa_topbarAction:focus-visible{outline:2px solid var(--tomato-accent,var(--dsw-alias-state-error-primary));outline-offset:2px}.Y6kksa_topbarAction .Y6kksa_tomatoIcon{border-radius:5px;width:16px;height:16px;font-size:10px}.Y6kksa_tomatoIcon{width:18px;height:18px;color:var(--dsw-alias-label-primary-inverted);background:var(--tomato-accent,var(--dsw-alias-state-error-primary));border-radius:6px;flex:none;place-items:center;font-size:11px;font-weight:750;display:inline-grid}.Y6kksa_transitionTrigger{align-items:center;gap:6px;display:inline-flex}.Y6kksa_transitionCaption{color:var(--dsw-alias-label-secondary);font-size:12px}.Y6kksa_transitionTrigger strong{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:650}.Y6kksa_transitionDivider{background:var(--dsw-alias-border-l2);width:1px;height:14px;margin:0 2px}.Y6kksa_transitionAction{color:var(--tomato-accent,var(--dsw-alias-state-business-primary));font-size:12px;font-weight:650}.Y6kksa_transitionChevron{color:var(--tomato-accent,var(--dsw-alias-state-business-primary));transition:transform var(--ds-transition-duration-fast) var(--ds-ease-in-out)}.Y6kksa_transitionTrigger[aria-expanded=true] .Y6kksa_transitionChevron{transform:rotate(180deg)}.Y6kksa_workbench{--tomato-accent:var(--dsw-alias-state-business-primary,#3478c8);--tomato-accent-soft:color-mix(in srgb, var(--tomato-accent) 12%, transparent);--tomato-accent-border:color-mix(in srgb, var(--tomato-accent) 48%, var(--dsw-alias-border-l2));min-width:0;height:100%;min-height:0;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-base);font-family:var(--dsw-font-family);flex-direction:column;flex:1;display:flex;position:relative}.Y6kksa_createDialog{width:min(480px,100%)}.Y6kksa_dialogBody{flex-direction:column;gap:12px;display:flex}.Y6kksa_dialogBody>span{color:var(--tomato-accent,var(--dsw-alias-state-error-primary));font-size:12px;font-weight:700}.Y6kksa_dialogBody code{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;font-size:13px}.Y6kksa_workspaceTrigger{justify-content:space-between;width:100%;display:flex}.Y6kksa_header{z-index:20;border-bottom:1px solid #0000;flex:none;padding:12px 28px 0 20px;position:relative}.Y6kksa_header:after{content:\"\";z-index:0;background:var(--dsw-alias-border-l2);pointer-events:none;height:1px;position:absolute;bottom:1px;left:0;right:0}.Y6kksa_titleRow{align-items:center;gap:10px;min-height:32px;display:flex}.Y6kksa_header h1{text-overflow:ellipsis;white-space:nowrap;border-radius:12px;flex:1;min-width:0;margin:0;padding:4px 8px;font-size:14px;font-weight:500;line-height:20px;overflow:hidden}.Y6kksa_pageTabs{z-index:1;gap:36px;margin-top:4px;padding-left:8px;display:flex;position:relative}.Y6kksa_pageTabs button{color:var(--dsw-alias-label-tertiary);cursor:pointer;font:inherit;background:0 0;border:0;padding:0 0 11px;font-size:13px;font-weight:500;line-height:16px;position:relative}.Y6kksa_pageTabs button:after{content:\"\";background:0 0;border-radius:2px;height:2px;position:absolute;bottom:1px;left:0;right:0}.Y6kksa_pageTabs button:hover,.Y6kksa_pageTabs button[aria-current=page]{color:var(--dsw-alias-state-business-primary)}.Y6kksa_pageTabs button[aria-current=page]:after{background:var(--dsw-alias-state-business-primary)}.Y6kksa_pageTabs button:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:3px}.Y6kksa_actions{z-index:1;align-items:center;gap:8px;min-height:32px;display:flex;position:relative}.Y6kksa_actions .Y6kksa_headerIconButton{width:28px;min-width:28px;height:28px;padding:0}.Y6kksa_searchField{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:10px;align-items:center;gap:6px;width:220px;min-height:28px;padding:0 8px;display:flex}.Y6kksa_searchField input{min-width:0;color:inherit;font:inherit;background:0 0;border:0;outline:0;flex:1}.Y6kksa_searchField button{border:0;min-height:24px;padding:0 5px}.Y6kksa_filterMenu{position:relative}.Y6kksa_filterMenu summary{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);cursor:pointer;border-radius:10px;place-items:center;width:28px;height:28px;list-style:none;display:grid;position:relative}.Y6kksa_filterMenu summary::-webkit-details-marker{display:none}.Y6kksa_filterMenu summary i{background:var(--tomato-accent,var(--dsw-alias-state-error-primary));border-radius:50%;width:5px;height:5px;position:absolute;top:5px;right:5px}.Y6kksa_filterPopover{z-index:30;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);width:min(500px,100vw - 320px);box-shadow:var(--dsw-shadow-lv3);border-radius:16px;gap:10px;padding:12px;display:grid;position:absolute;top:calc(100% + 8px);right:0}.Y6kksa_assigneeFilter{align-items:flex-start;gap:12px;display:flex}.Y6kksa_assigneeFilter>span{width:48px;color:var(--dsw-alias-label-secondary);white-space:nowrap;flex:0 0 48px;padding-top:8px;font-size:13px}.Y6kksa_assigneePicker{min-width:260px;position:relative}.Y6kksa_assigneeFilter .Y6kksa_assigneeTrigger{border:1px solid color-mix(in srgb, var(--dsw-alias-border-l2) 82%, transparent);width:100%;height:30px;color:var(--dsw-alias-label-secondary);background:color-mix(in srgb, var(--dsw-alias-bg-overlay) 46%, transparent);border-radius:999px;justify-content:space-between;align-items:center;gap:12px;padding:0 8px 0 12px;font-size:12px;display:flex}.Y6kksa_assigneeFilter .Y6kksa_assigneeTrigger:hover{background:var(--dsw-alias-interactive-bg-hover)}.Y6kksa_assigneeTrigger>span{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.Y6kksa_assigneeDropdown{z-index:40;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);width:320px;box-shadow:var(--dsw-shadow-lv3);border-radius:10px;padding:8px;position:absolute;top:calc(100% + 5px);left:0}.Y6kksa_assigneeDropdown>input{border:1px solid var(--dsw-alias-border-l2);width:100%;height:32px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-base);font:inherit;border-radius:7px;outline:0;padding:0 9px}.Y6kksa_assigneeDropdown>input:focus{border-color:var(--tomato-accent,var(--dsw-alias-state-business-primary))}.Y6kksa_assigneeDropdown>[role=listbox]{max-height:260px;margin-top:7px;overflow:auto}.Y6kksa_assigneeDropdown [role=option]{width:100%;min-height:38px;color:var(--dsw-alias-label-primary);text-align:left;cursor:pointer;background:0 0;border:0;border-radius:7px;flex-direction:column;justify-content:center;align-items:flex-start;gap:2px;padding:6px 9px;display:flex}.Y6kksa_assigneeDropdown [role=option]:hover,.Y6kksa_assigneeDropdown [role=option][aria-selected=true]{background:var(--dsw-alias-interactive-bg-hover)}.Y6kksa_assigneeDropdown strong{font-size:12px;font-weight:550}.Y6kksa_assigneeDropdown small{color:var(--dsw-alias-label-secondary);font-size:10px}.Y6kksa_assigneeDropdown p{color:var(--dsw-alias-label-secondary);text-align:center;margin:0;padding:18px 8px;font-size:11px}.Y6kksa_filterRow{align-items:flex-start;gap:12px;display:flex}.Y6kksa_filterRow>span{width:48px;color:var(--dsw-alias-label-secondary);white-space:nowrap;flex:0 0 48px;padding-top:7px;font-size:13px}.Y6kksa_filterRow>div{flex-wrap:wrap;flex:1;gap:7px;display:flex}.Y6kksa_workspaceSelect{flex:1;min-width:0;display:block;position:relative}.Y6kksa_workspaceSelect>span{flex:1}.Y6kksa_filterRow .Y6kksa_workspaceTrigger{border:1px solid color-mix(in srgb, var(--dsw-alias-border-l2) 82%, transparent);width:100%;min-height:30px;color:var(--dsw-alias-label-secondary);background:color-mix(in srgb, var(--dsw-alias-bg-overlay) 46%, transparent);font:inherit;text-align:left;cursor:pointer;border-radius:999px;justify-content:space-between;align-items:center;gap:10px;padding:3px 8px 3px 12px;font-size:12px;display:flex}.Y6kksa_filterRow .Y6kksa_workspaceTrigger:hover{background:var(--dsw-alias-interactive-bg-hover)}.Y6kksa_filterRow .Y6kksa_workspaceTrigger>span{min-width:0;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.Y6kksa_workspaceChevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s;display:inline-flex}.Y6kksa_workspaceTrigger[aria-expanded=true] .Y6kksa_workspaceChevron{color:var(--tomato-accent,var(--dsw-alias-state-business-primary));transform:rotate(180deg)}.Y6kksa_error{color:var(--tomato-accent,var(--dsw-alias-state-error-primary));background:var(--dsw-alias-state-error-secondary);border-radius:12px;margin:16px 24px 0;padding:12px 14px}.Y6kksa_notice{color:var(--dsw-alias-label-secondary);margin:0;padding:8px 20px;font-size:11px}.Y6kksa_board{z-index:1;flex:1;align-items:flex-start;gap:12px;padding:8px 12px;display:flex;position:relative;overflow:auto}.Y6kksa_lane{border:1px solid var(--dsw-alias-border-l2);background:color-mix(in srgb, var(--dsw-alias-bg-module-platform) 86%, transparent);width:300px;min-width:300px;max-height:100%;transition:transform .16s var(--ds-ease-in-out), opacity .16s var(--ds-ease-in-out), box-shadow .16s var(--ds-ease-in-out);border-radius:16px;flex-direction:column;display:flex}.Y6kksa_laneDragging{opacity:.5;transform:scale(.985)}.Y6kksa_laneDropBefore{box-shadow:-4px 0 0 var(--tomato-accent,var(--dsw-alias-state-business-primary));transform:translate(8px)}.Y6kksa_laneDropAfter{box-shadow:4px 0 0 var(--tomato-accent,var(--dsw-alias-state-business-primary));transform:translate(-8px)}.Y6kksa_laneHeader{cursor:grab;user-select:none;justify-content:space-between;align-items:center;padding:12px 14px 10px;display:flex}.Y6kksa_laneHeader:active{cursor:grabbing}@media (prefers-reduced-motion:reduce){.Y6kksa_lane{transition:none}}.Y6kksa_laneHeader h2{margin:0;font-size:14px}.Y6kksa_laneHeader span{text-align:center;min-width:22px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-overlay);border-radius:999px;padding:2px 6px;font-size:12px}.Y6kksa_cards{padding:0 8px 8px;overflow-y:auto}.Y6kksa_card{border:1px solid var(--dsw-alias-border-l2);min-width:0;max-width:100%;color:inherit;background:color-mix(in srgb, var(--dsw-alias-bg-layer-1) 96%, transparent);box-shadow:var(--dsw-shadow-lv1);text-align:left;transition:background var(--ds-transition-duration-fast) var(--ds-ease-in-out), border-color var(--ds-transition-duration-fast) var(--ds-ease-in-out), box-shadow var(--ds-transition-duration-fast) var(--ds-ease-in-out);cursor:pointer;border-radius:14px;flex-direction:column;gap:7px;margin-top:8px;padding:12px;text-decoration:none;display:flex;overflow:hidden}.Y6kksa_card:hover{border-color:var(--dsw-alias-border-l3);background:var(--dsw-alias-button-floating-hover);box-shadow:var(--dsw-shadow-lv2)}.Y6kksa_cardMuted{opacity:.46;filter:saturate(.2);box-shadow:none}.Y6kksa_cardMuted:hover{opacity:.62}.Y6kksa_card:focus-visible{outline:2px solid var(--tomato-accent,var(--dsw-alias-state-business-primary));outline-offset:2px}.Y6kksa_card strong,.Y6kksa_key,.Y6kksa_meta{overflow-wrap:anywhere;word-break:normal;min-width:0}.Y6kksa_cardTopline{justify-content:space-between;align-items:center;gap:8px;min-width:0;display:flex}.Y6kksa_cardButtons{align-items:center;gap:2px;display:inline-flex}.Y6kksa_muteButton,.Y6kksa_tomatoLink{border-radius:8px;flex:none;place-items:center;width:28px;min-width:28px;height:28px;min-height:28px;padding:0;line-height:1;display:inline-grid}.Y6kksa_muteButton{color:var(--dsw-alias-label-tertiary);font-size:9px}.Y6kksa_muteButton[aria-pressed=true]{color:var(--dsw-alias-label-primary)}.Y6kksa_card strong{font-size:14px;font-weight:600;line-height:1.45}.Y6kksa_key{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:650}.Y6kksa_cardMeta{flex-wrap:wrap;align-items:center;gap:5px;min-width:0;display:flex}.Y6kksa_empty{color:var(--dsw-alias-label-tertiary);margin:auto}@media (width<=820px){.Y6kksa_titleRow{flex-wrap:wrap}.Y6kksa_actions{flex-wrap:wrap;justify-content:flex-end}.Y6kksa_searchField{width:170px}}";
|
|
22
|
+
const tagId$2 = "@stephen1620/dsh-tomato-board/tomato-board.module.css";
|
|
23
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
|
|
24
24
|
const tag = document.createElement("style");
|
|
25
25
|
tag.dataset.plugin = "@stephen1620/dsh-tomato-board";
|
|
26
|
-
tag.dataset.pluginCss = tagId;
|
|
27
|
-
tag.textContent = css;
|
|
26
|
+
tag.dataset.pluginCss = tagId$2;
|
|
27
|
+
tag.textContent = css$2;
|
|
28
28
|
document.head.appendChild(tag);
|
|
29
29
|
}
|
|
30
30
|
var tomato_board_module_css_default = {
|
|
31
31
|
"actions": "Y6kksa_actions",
|
|
32
|
+
"assigneeDropdown": "Y6kksa_assigneeDropdown",
|
|
33
|
+
"assigneeFilter": "Y6kksa_assigneeFilter",
|
|
34
|
+
"assigneePicker": "Y6kksa_assigneePicker",
|
|
35
|
+
"assigneeTrigger": "Y6kksa_assigneeTrigger",
|
|
32
36
|
"board": "Y6kksa_board",
|
|
33
37
|
"card": "Y6kksa_card",
|
|
34
38
|
"cardButtons": "Y6kksa_cardButtons",
|
|
39
|
+
"cardMeta": "Y6kksa_cardMeta",
|
|
35
40
|
"cardMuted": "Y6kksa_cardMuted",
|
|
36
41
|
"cardTopline": "Y6kksa_cardTopline",
|
|
37
42
|
"cards": "Y6kksa_cards",
|
|
@@ -46,28 +51,745 @@ window.__ModuleLoader__.load({
|
|
|
46
51
|
"headerIconButton": "Y6kksa_headerIconButton",
|
|
47
52
|
"key": "Y6kksa_key",
|
|
48
53
|
"lane": "Y6kksa_lane",
|
|
54
|
+
"laneDragging": "Y6kksa_laneDragging",
|
|
55
|
+
"laneDropAfter": "Y6kksa_laneDropAfter",
|
|
56
|
+
"laneDropBefore": "Y6kksa_laneDropBefore",
|
|
49
57
|
"laneHeader": "Y6kksa_laneHeader",
|
|
50
58
|
"meta": "Y6kksa_meta",
|
|
51
59
|
"muteButton": "Y6kksa_muteButton",
|
|
52
60
|
"notice": "Y6kksa_notice",
|
|
61
|
+
"pageTabs": "Y6kksa_pageTabs",
|
|
53
62
|
"searchField": "Y6kksa_searchField",
|
|
54
|
-
"selectedFilter": "Y6kksa_selectedFilter",
|
|
55
63
|
"sidebarAction": "Y6kksa_sidebarAction",
|
|
64
|
+
"titleRow": "Y6kksa_titleRow",
|
|
56
65
|
"tomatoIcon": "Y6kksa_tomatoIcon",
|
|
57
66
|
"tomatoLink": "Y6kksa_tomatoLink",
|
|
67
|
+
"topbarAction": "Y6kksa_topbarAction",
|
|
58
68
|
"transitionAction": "Y6kksa_transitionAction",
|
|
59
69
|
"transitionCaption": "Y6kksa_transitionCaption",
|
|
60
70
|
"transitionChevron": "Y6kksa_transitionChevron",
|
|
61
71
|
"transitionDivider": "Y6kksa_transitionDivider",
|
|
62
72
|
"transitionTrigger": "Y6kksa_transitionTrigger",
|
|
63
73
|
"workbench": "Y6kksa_workbench",
|
|
74
|
+
"workspaceChevron": "Y6kksa_workspaceChevron",
|
|
75
|
+
"workspaceSelect": "Y6kksa_workspaceSelect",
|
|
64
76
|
"workspaceTrigger": "Y6kksa_workspaceTrigger"
|
|
65
77
|
};
|
|
66
78
|
//#endregion
|
|
79
|
+
//#region \0dsh-css:/Users/gengfeng/deepseek-harness/packages/client/tomato-board/src/client/story-points.module.css.mjs
|
|
80
|
+
const css$1 = ".LfvjxG_page{--tomato-accent:var(--dsw-alias-state-business-primary,#3478c8);--tomato-accent-soft:color-mix(in srgb, var(--tomato-accent) 10%, transparent);min-height:0;color:var(--dsw-alias-label-primary,#292d32);flex:1;padding:14px 18px 18px;overflow:auto}.LfvjxG_page *{box-sizing:border-box}.LfvjxG_page button,.LfvjxG_page select,.LfvjxG_page input{font:inherit;color:inherit;border:1px solid var(--dsw-alias-border-l2,#dedfdf);background:var(--dsw-alias-bg-base,white);border-radius:8px;min-width:0;padding:8px 12px}.LfvjxG_page button{cursor:pointer;white-space:nowrap}.LfvjxG_page button:hover{background:var(--dsw-alias-interactive-bg-hover,#f4f4f2)}.LfvjxG_page button:disabled{opacity:.5;cursor:wait}.LfvjxG_page :focus-visible{outline:2px solid var(--tomato-accent);outline-offset:3px}.LfvjxG_page h3,.LfvjxG_page h4,.LfvjxG_page p{margin:0}.LfvjxG_panelHeader,.LfvjxG_listHeading,.LfvjxG_rankLabel{justify-content:space-between;align-items:center;gap:12px;display:flex}.LfvjxG_caption,.LfvjxG_footnote,.LfvjxG_itemText small,.LfvjxG_rankRow small,.LfvjxG_listHeading span{color:var(--dsw-alias-label-secondary,#797c80);font-size:12px;line-height:1.5}.LfvjxG_eyebrow{letter-spacing:1.6px;color:var(--dsw-alias-label-secondary,#797c80);font-size:10px;font-weight:650}.LfvjxG_headerControls{align-items:center;gap:8px;display:flex}.LfvjxG_headerControls label{color:var(--dsw-alias-label-secondary,#797c80);align-items:center;gap:7px;font-size:12px;display:flex}.LfvjxG_headerControls select{border:1px solid var(--dsw-alias-border-l2,#dedfdf);width:min(320px,34vw);min-width:0;height:28px;color:var(--dsw-alias-label-primary,#292d32);background:var(--dsw-alias-bg-base,white);font:inherit;border-radius:9px;padding:0 10px}.LfvjxG_headerIconButton{border-radius:8px;width:28px;min-width:28px;height:28px;min-height:28px;padding:0!important}.LfvjxG_columns{grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);align-items:start;gap:14px;display:grid}.LfvjxG_teamsHeader{border-bottom:1px solid var(--dsw-alias-border-l2,#e4e4df);justify-content:space-between;align-items:center;padding-bottom:12px;display:flex}.LfvjxG_teamsHeader h3{font-size:16px}.LfvjxG_addTeamButton{height:30px;font-weight:600;min-width:0!important;padding:0 10px!important;font-size:12px!important}.LfvjxG_teamEditor{background:var(--dsw-alias-interactive-bg-hover,#f3f3f1);border-radius:9px;align-items:center;gap:7px;margin:9px 0;padding:8px;display:flex}.LfvjxG_teamEditor input{flex:1;min-width:0}.LfvjxG_teamEditor button{padding:6px 8px;font-size:11px}.LfvjxG_teamAccordions{gap:8px;margin-top:10px;display:grid}.LfvjxG_teamAccordion{border:1px solid var(--dsw-alias-border-l2,#e4e4df);border-radius:10px;overflow:visible}.LfvjxG_teamAccordionHeader{align-items:center;gap:2px;min-height:42px;padding:4px 6px;display:flex}.LfvjxG_teamToggle{text-align:left;align-items:center;gap:8px;min-width:0;display:flex;background:0 0!important;border:0!important;padding:6px!important}.LfvjxG_teamToggle strong{text-overflow:ellipsis;min-width:0;font-size:13px;overflow:hidden}.LfvjxG_teamToggle small{color:var(--dsw-alias-label-secondary);font-size:10px}.LfvjxG_renameTeam{width:27px;height:27px;margin-left:-3px;min-width:27px!important;color:var(--dsw-alias-label-secondary)!important;background:0 0!important;border-color:#0000!important;padding:0!important}.LfvjxG_renameTeam:hover{color:var(--tomato-accent)!important}.LfvjxG_chevron{color:var(--dsw-alias-label-tertiary);font-size:18px;line-height:1;transition:transform .16s}.LfvjxG_teamToggle[aria-expanded=true] .LfvjxG_chevron{color:var(--tomato-accent);transform:rotate(90deg)}.LfvjxG_teamRowActions{gap:2px;margin-left:auto;display:flex}.LfvjxG_teamRowActions button{width:27px;min-width:27px;height:27px;color:var(--dsw-alias-label-secondary);background:0 0;border-color:#0000;padding:0}.LfvjxG_teamRowActions button:last-child:hover{color:var(--dsw-alias-state-error-primary,#bd4336)}.LfvjxG_teamBody{border-top:1px solid var(--dsw-alias-border-l2,#e4e4df);padding:10px 12px 12px;position:relative}.LfvjxG_teamBodyToolbar{color:var(--dsw-alias-label-secondary);justify-content:space-between;align-items:center;gap:8px;font-size:11px;display:flex}.LfvjxG_smallAddButton{border-radius:6px!important;padding:4px 7px!important;font-size:10px!important}.LfvjxG_teamBodyEmpty{color:var(--dsw-alias-label-secondary);text-align:center;padding:20px 8px 10px;font-size:11px}.LfvjxG_memberRow{align-items:center;gap:4px;display:flex}.LfvjxG_memberRow .LfvjxG_rankLabel{flex:1;min-width:0}.LfvjxG_rankIndex{font-variant-numeric:tabular-nums;flex:0 0 22px;width:22px;color:var(--dsw-alias-label-tertiary)!important}.LfvjxG_memberAvatar{background:var(--tomato-accent-soft);border-radius:9px;flex:0 0 28px;place-items:center;width:28px;height:28px;font-weight:750;display:inline-grid;color:var(--tomato-accent)!important;font-size:12px!important}.LfvjxG_memberIdentity{z-index:1;flex:1;gap:1px;min-width:0;display:grid;position:relative}.LfvjxG_memberIdentity strong{text-overflow:ellipsis;overflow:hidden}.LfvjxG_memberIdentity small{color:var(--dsw-alias-label-tertiary);font-size:10px;font-weight:400}.LfvjxG_rankFill{z-index:0;border-radius:inherit;background:color-mix(in srgb, var(--tomato-accent) 11%, transparent);pointer-events:none;max-width:100%;position:absolute;inset:0 auto 0 0}.LfvjxG_rankLabel>.LfvjxG_rankIndex,.LfvjxG_rankLabel>.LfvjxG_memberAvatar,.LfvjxG_rankLabel>b{z-index:1;position:relative}.LfvjxG_removeMember{opacity:0;width:25px;height:25px;min-width:25px!important;color:var(--dsw-alias-label-tertiary)!important;background:0 0!important;border-color:#0000!important;padding:0!important}.LfvjxG_memberRow:hover .LfvjxG_removeMember,.LfvjxG_removeMember:focus-visible{opacity:1}.LfvjxG_removeMember:hover{color:var(--dsw-alias-state-error-primary,#bd4336)!important}.LfvjxG_panel{border:1px solid var(--dsw-alias-border-l2,#e4e4df);background:var(--dsw-alias-bg-base,white);border-radius:14px;min-width:0;padding:16px}.LfvjxG_panelHeader{border-bottom:1px solid var(--dsw-alias-border-l2,#e4e4df);padding-bottom:12px}.LfvjxG_panelHeader h3{white-space:nowrap;font-size:16px}.LfvjxG_panelHeader select{max-width:65%;font-size:12px}.LfvjxG_panelHeader button{font-size:12px}.LfvjxG_summary{justify-content:space-between;align-items:center;gap:16px;padding:16px 0;display:flex}.LfvjxG_total{font-variant-numeric:tabular-nums;letter-spacing:-2px;font-size:48px;font-weight:600;line-height:1.15}.LfvjxG_total small{letter-spacing:0;color:var(--dsw-alias-label-secondary,#797c80);font-size:15px}.LfvjxG_pie{background:var(--dsw-alias-border-l2,#e7e7e2);width:136px;height:136px;box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--dsw-alias-border-l2,#ddd) 55%, transparent), 0 14px 36px #00000012;border-radius:50%;flex:0 0 136px;padding:17px;position:relative;transform:rotate(-90deg)}.LfvjxG_pie:after{content:\"\";border:1px solid color-mix(in srgb, var(--tomato-accent) 24%, transparent);border-radius:50%;position:absolute;inset:-6px}.LfvjxG_pie>div{z-index:1;background:var(--dsw-alias-bg-base,white);width:100%;height:100%;box-shadow:inset 0 0 0 1px var(--dsw-alias-border-l2,#e7e7e2);border-radius:50%;flex-direction:column;justify-content:center;align-items:center;display:flex;position:relative;transform:rotate(90deg)}.LfvjxG_pie strong{font-size:28px;line-height:1}.LfvjxG_pie span{letter-spacing:.08em;color:var(--dsw-alias-label-secondary,#797c80);margin-top:5px;font-size:10px}.LfvjxG_listHeading{padding:10px 0}.LfvjxG_listHeading h4{font-size:13px}.LfvjxG_item{border-top:1px solid var(--dsw-alias-border-l2,#e4e4df);align-items:center;gap:10px;padding:10px 12px;display:flex}.LfvjxG_dot{border-radius:3px;flex-shrink:0;width:8px;height:8px}.LfvjxG_itemText{flex:1;min-width:0}.LfvjxG_itemTitle{color:inherit;overflow-wrap:anywhere;font-size:13px;line-height:1.5;text-decoration:none}.LfvjxG_itemTitle:hover{text-decoration:underline}.LfvjxG_itemText small{margin-right:7px;font-size:10px;display:inline-block}.LfvjxG_itemPoints{white-space:nowrap;font-variant-numeric:tabular-nums;font-size:12px}.LfvjxG_item button{padding:5px 8px;font-size:11px}.LfvjxG_chips{flex-wrap:wrap;gap:8px;margin:12px 0 8px;display:flex}.LfvjxG_chips>span{background:var(--dsw-alias-interactive-bg-hover,#f2f3f0);border-radius:6px;align-items:center;gap:6px;padding:3px 5px 3px 10px;font-size:12px;display:flex}.LfvjxG_chips button{background:0 0;border:0;padding:1px 5px}.LfvjxG_ranking{gap:3px;margin-top:8px;display:grid}.LfvjxG_rankRow{border-radius:9px}.LfvjxG_rankRow:hover{background:color-mix(in srgb, var(--dsw-alias-interactive-bg-hover,#f1f2ee) 70%, transparent)}.LfvjxG_rankLabel{text-align:left;background:0 0;border:0;border-radius:9px;gap:8px;width:100%;min-height:48px;padding:6px 4px;font-size:13px;position:relative}.LfvjxG_rankLabel:hover{color:var(--tomato-accent);background:0 0!important}.LfvjxG_rankLabel[aria-pressed=true]{color:var(--tomato-accent);background:var(--tomato-accent-soft)!important}.LfvjxG_rankLabel b{font-variant-numeric:tabular-nums;flex:none;font-size:13px}.LfvjxG_track{display:none}.LfvjxG_footnote{border-top:1px solid var(--dsw-alias-border-l2,#e4e4df);padding-top:12px;font-size:11px;margin-top:20px!important}.LfvjxG_empty{text-align:center;color:var(--dsw-alias-label-secondary,#797c80);padding:36px 12px;font-size:13px}.LfvjxG_empty h4{margin-bottom:8px}.LfvjxG_emptyIcon{color:var(--tomato-accent);margin-bottom:12px;font-size:32px;display:block}.LfvjxG_error{color:var(--dsw-alias-state-error-primary,#bd4336);overflow-wrap:anywhere;padding:10px 0;font-size:12px}.LfvjxG_notice{color:var(--dsw-alias-label-secondary,#797c80);padding:8px 0;font-size:12px}.LfvjxG_teamHeader{overflow:visible}.LfvjxG_addPeopleRoot{position:relative}.LfvjxG_addPeople{z-index:30;border:1px solid var(--dsw-alias-border-l2,#ddd);background:var(--dsw-alias-bg-layer-2,white);border-radius:12px;width:min(330px,72vw);padding:10px;position:absolute;top:calc(100% + 7px);right:0;box-shadow:0 16px 46px #0002}.LfvjxG_addPeopleTitle{justify-content:space-between;align-items:center;gap:10px;display:flex;margin:0 0 8px!important}.LfvjxG_addPeopleTitle strong{font-size:12px}.LfvjxG_addPeopleTitle button{justify-content:center;min-width:26px;height:26px;width:26px!important;padding:0!important}.LfvjxG_addPeople input{width:100%}.LfvjxG_addPeople>div:last-child{max-height:210px;margin-top:8px;overflow:auto}.LfvjxG_addPeople>div:last-child>button{text-align:left;border:0;gap:8px;width:100%;display:flex}.LfvjxG_addPeople small{opacity:.6;flex:1}@media (width<=1000px){.LfvjxG_columns{grid-template-columns:1fr}.LfvjxG_page{padding:14px}}@media (width<=620px){.LfvjxG_teamHeader{flex-direction:column;align-items:flex-start}.LfvjxG_teamActions{justify-content:flex-start}.LfvjxG_memberToolbar{flex-direction:column;align-items:stretch}}@media (width<=540px){.LfvjxG_page{padding:10px}.LfvjxG_panel{padding:12px}.LfvjxG_headerControls label>span{display:none}.LfvjxG_headerControls select{width:min(220px,55vw)}.LfvjxG_pie{flex-basis:120px;width:120px;height:120px;padding:16px}.LfvjxG_total{font-size:42px}.LfvjxG_item{gap:7px}}.LfvjxG_item[role=button]{cursor:pointer;border-radius:8px}.LfvjxG_item[role=button]:hover{background:var(--dsw-alias-interactive-bg-hover)}.LfvjxG_item[role=button]:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.LfvjxG_item .LfvjxG_tomatoLink{background:0 0;border:0;flex:none;width:28px;height:28px;padding:0}";
|
|
81
|
+
const tagId$1 = "@stephen1620/dsh-tomato-board/story-points.module.css";
|
|
82
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
83
|
+
const tag = document.createElement("style");
|
|
84
|
+
tag.dataset.plugin = "@stephen1620/dsh-tomato-board";
|
|
85
|
+
tag.dataset.pluginCss = tagId$1;
|
|
86
|
+
tag.textContent = css$1;
|
|
87
|
+
document.head.appendChild(tag);
|
|
88
|
+
}
|
|
89
|
+
var story_points_module_css_default = {
|
|
90
|
+
"addPeople": "LfvjxG_addPeople",
|
|
91
|
+
"addPeopleRoot": "LfvjxG_addPeopleRoot",
|
|
92
|
+
"addPeopleTitle": "LfvjxG_addPeopleTitle",
|
|
93
|
+
"addTeamButton": "LfvjxG_addTeamButton",
|
|
94
|
+
"caption": "LfvjxG_caption",
|
|
95
|
+
"chevron": "LfvjxG_chevron",
|
|
96
|
+
"chips": "LfvjxG_chips",
|
|
97
|
+
"columns": "LfvjxG_columns",
|
|
98
|
+
"dot": "LfvjxG_dot",
|
|
99
|
+
"empty": "LfvjxG_empty",
|
|
100
|
+
"emptyIcon": "LfvjxG_emptyIcon",
|
|
101
|
+
"error": "LfvjxG_error",
|
|
102
|
+
"eyebrow": "LfvjxG_eyebrow",
|
|
103
|
+
"footnote": "LfvjxG_footnote",
|
|
104
|
+
"headerControls": "LfvjxG_headerControls",
|
|
105
|
+
"headerIconButton": "LfvjxG_headerIconButton",
|
|
106
|
+
"item": "LfvjxG_item",
|
|
107
|
+
"itemPoints": "LfvjxG_itemPoints",
|
|
108
|
+
"itemText": "LfvjxG_itemText",
|
|
109
|
+
"itemTitle": "LfvjxG_itemTitle",
|
|
110
|
+
"listHeading": "LfvjxG_listHeading",
|
|
111
|
+
"memberAvatar": "LfvjxG_memberAvatar",
|
|
112
|
+
"memberIdentity": "LfvjxG_memberIdentity",
|
|
113
|
+
"memberRow": "LfvjxG_memberRow",
|
|
114
|
+
"memberToolbar": "LfvjxG_memberToolbar",
|
|
115
|
+
"notice": "LfvjxG_notice",
|
|
116
|
+
"page": "LfvjxG_page",
|
|
117
|
+
"panel": "LfvjxG_panel",
|
|
118
|
+
"panelHeader": "LfvjxG_panelHeader",
|
|
119
|
+
"pie": "LfvjxG_pie",
|
|
120
|
+
"rankFill": "LfvjxG_rankFill",
|
|
121
|
+
"rankIndex": "LfvjxG_rankIndex",
|
|
122
|
+
"rankLabel": "LfvjxG_rankLabel",
|
|
123
|
+
"rankRow": "LfvjxG_rankRow",
|
|
124
|
+
"ranking": "LfvjxG_ranking",
|
|
125
|
+
"removeMember": "LfvjxG_removeMember",
|
|
126
|
+
"renameTeam": "LfvjxG_renameTeam",
|
|
127
|
+
"smallAddButton": "LfvjxG_smallAddButton",
|
|
128
|
+
"summary": "LfvjxG_summary",
|
|
129
|
+
"teamAccordion": "LfvjxG_teamAccordion",
|
|
130
|
+
"teamAccordionHeader": "LfvjxG_teamAccordionHeader",
|
|
131
|
+
"teamAccordions": "LfvjxG_teamAccordions",
|
|
132
|
+
"teamActions": "LfvjxG_teamActions",
|
|
133
|
+
"teamBody": "LfvjxG_teamBody",
|
|
134
|
+
"teamBodyEmpty": "LfvjxG_teamBodyEmpty",
|
|
135
|
+
"teamBodyToolbar": "LfvjxG_teamBodyToolbar",
|
|
136
|
+
"teamEditor": "LfvjxG_teamEditor",
|
|
137
|
+
"teamHeader": "LfvjxG_teamHeader",
|
|
138
|
+
"teamRowActions": "LfvjxG_teamRowActions",
|
|
139
|
+
"teamToggle": "LfvjxG_teamToggle",
|
|
140
|
+
"teamsHeader": "LfvjxG_teamsHeader",
|
|
141
|
+
"tomatoLink": "LfvjxG_tomatoLink",
|
|
142
|
+
"total": "LfvjxG_total",
|
|
143
|
+
"track": "LfvjxG_track"
|
|
144
|
+
};
|
|
145
|
+
//#endregion
|
|
146
|
+
//#region \0dsh-css:/Users/gengfeng/deepseek-harness/packages/client/tomato-board/src/client/tag.module.css.mjs
|
|
147
|
+
const css = ".vN3RbG_tag{--tag-border-color:color-mix(in srgb, var(--dsw-alias-border-l2) 82%, transparent);--tag-text-color:var(--dsw-alias-label-secondary);--tag-bg-color:color-mix(in srgb, var(--dsw-alias-bg-overlay) 46%, transparent);--tag-weight:550;overflow-wrap:anywhere;border:1px solid var(--tag-border-color);max-width:100%;color:var(--tag-text-color);background:var(--tag-bg-color);font-size:10px;font-weight:var(--tag-weight);white-space:normal;border-radius:999px;flex:none;padding:2px 9px;line-height:1.4}.vN3RbG_toned{--tag-border-color:color-mix(in srgb, var(--tag-tone) 38%, transparent);--tag-text-color:var(--tag-tone);--tag-bg-color:color-mix(in srgb, var(--tag-tone) 13%, transparent);--tag-weight:700}.vN3RbG_tag.vN3RbG_toggle{cursor:pointer;min-height:26px;font:inherit;font-size:10px;font-weight:var(--tag-weight);align-items:center;padding:2px 10px;line-height:1.4;display:inline-flex}.vN3RbG_tag.vN3RbG_toggle:hover{background:var(--dsw-alias-interactive-bg-hover)}.vN3RbG_tag.vN3RbG_toned.vN3RbG_toggle:hover{background:color-mix(in srgb, var(--tag-tone) 18%, transparent)}.vN3RbG_tag.vN3RbG_toggle:focus-visible{outline:2px solid var(--tag-tone,var(--dsw-alias-state-business-primary));outline-offset:2px}.vN3RbG_off{opacity:.5;filter:saturate(.55)}";
|
|
148
|
+
const tagId = "@stephen1620/dsh-tomato-board/tag.module.css";
|
|
149
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
150
|
+
const tag = document.createElement("style");
|
|
151
|
+
tag.dataset.plugin = "@stephen1620/dsh-tomato-board";
|
|
152
|
+
tag.dataset.pluginCss = tagId;
|
|
153
|
+
tag.textContent = css;
|
|
154
|
+
document.head.appendChild(tag);
|
|
155
|
+
}
|
|
156
|
+
var tag_module_css_default = {
|
|
157
|
+
"off": "vN3RbG_off",
|
|
158
|
+
"tag": "vN3RbG_tag",
|
|
159
|
+
"toggle": "vN3RbG_toggle",
|
|
160
|
+
"toned": "vN3RbG_toned"
|
|
161
|
+
};
|
|
162
|
+
//#endregion
|
|
163
|
+
//#region src/client/Tag.tsx
|
|
164
|
+
/**
|
|
165
|
+
* The one tag chip used across the workbench — card metadata, filter chips and
|
|
166
|
+
* status labels. Static usage renders a span; interactive usage renders a
|
|
167
|
+
* toggle button. Only callers that pass `tone` get a colored chip (by
|
|
168
|
+
* convention just the item-type tags).
|
|
169
|
+
*/
|
|
170
|
+
function Tag({ children, tone, interactive = false, pressed, title, className, onClick }) {
|
|
171
|
+
const style = tone === void 0 ? void 0 : { "--tag-tone": tone };
|
|
172
|
+
const classes = [
|
|
173
|
+
tag_module_css_default.tag,
|
|
174
|
+
tone === void 0 ? "" : tag_module_css_default.toned,
|
|
175
|
+
interactive ? tag_module_css_default.toggle : "",
|
|
176
|
+
interactive && pressed === false ? tag_module_css_default.off : "",
|
|
177
|
+
className
|
|
178
|
+
].filter(Boolean).join(" ");
|
|
179
|
+
if (interactive) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
180
|
+
type: "button",
|
|
181
|
+
className: classes,
|
|
182
|
+
style,
|
|
183
|
+
title,
|
|
184
|
+
"aria-pressed": pressed,
|
|
185
|
+
onClick,
|
|
186
|
+
children
|
|
187
|
+
});
|
|
188
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
189
|
+
className: classes,
|
|
190
|
+
style,
|
|
191
|
+
title,
|
|
192
|
+
children
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
//#endregion
|
|
196
|
+
//#region src/client/StoryPoints.tsx
|
|
197
|
+
const LEGACY_TEAM_KEY = "taskboard.tomatoStoryTeam.v1";
|
|
198
|
+
const TEAMS_KEY = "taskboard.tomatoStoryTeams.v2";
|
|
199
|
+
const SPRINT_KEY = "taskboard.tomatoStorySprint.v1";
|
|
200
|
+
const OWNER_KEY = "taskboard.tomatoStoryOwner.v1";
|
|
201
|
+
const colors = [
|
|
202
|
+
"#d76b50",
|
|
203
|
+
"#458e88",
|
|
204
|
+
"#c79940",
|
|
205
|
+
"#687fb2",
|
|
206
|
+
"#976f9c",
|
|
207
|
+
"#75914f",
|
|
208
|
+
"#be7f92",
|
|
209
|
+
"#698b9d"
|
|
210
|
+
];
|
|
211
|
+
const number = (value) => new Intl.NumberFormat("zh-CN", { maximumFractionDigits: 4 }).format(value);
|
|
212
|
+
const total = (items) => items.reduce((sum, item) => sum + (item.storyPoints ?? 0), 0);
|
|
213
|
+
const savedValue = (key, fallback) => {
|
|
214
|
+
try {
|
|
215
|
+
return localStorage.getItem(key) || fallback;
|
|
216
|
+
} catch {
|
|
217
|
+
return fallback;
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
const teamId = () => `team-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`;
|
|
221
|
+
async function json(url, signal) {
|
|
222
|
+
const response = await fetch(url, {
|
|
223
|
+
signal: signal ?? null,
|
|
224
|
+
cache: "no-store",
|
|
225
|
+
headers: {
|
|
226
|
+
accept: "application/json",
|
|
227
|
+
"cache-control": "no-cache"
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
const text = await response.text();
|
|
231
|
+
let body;
|
|
232
|
+
try {
|
|
233
|
+
body = text ? JSON.parse(text) : {};
|
|
234
|
+
} catch {
|
|
235
|
+
throw new Error(response.status === 404 || text.trim() === "not found" ? "迭代故事点接口尚未加载,请完全重启 DSH Desktop" : `服务返回了无法识别的内容 (${response.status})`);
|
|
236
|
+
}
|
|
237
|
+
if (!response.ok) throw new Error(typeof body.error === "string" ? body.error : `请求失败 (${response.status})`);
|
|
238
|
+
return body;
|
|
239
|
+
}
|
|
240
|
+
function readTeams() {
|
|
241
|
+
try {
|
|
242
|
+
const saved = JSON.parse(localStorage.getItem(TEAMS_KEY) ?? "[]");
|
|
243
|
+
if (Array.isArray(saved) && saved.length) return saved.flatMap((value) => value && typeof value === "object" ? [{
|
|
244
|
+
id: String(value.id),
|
|
245
|
+
name: String(value.name),
|
|
246
|
+
members: Array.isArray(value.members) ? [...new Set(value.members)] : []
|
|
247
|
+
}] : []);
|
|
248
|
+
const legacy = JSON.parse(localStorage.getItem(LEGACY_TEAM_KEY) ?? "[]");
|
|
249
|
+
return Array.isArray(legacy) && legacy.length ? [{
|
|
250
|
+
id: "team-default",
|
|
251
|
+
name: "默认团队",
|
|
252
|
+
members: legacy.filter((value) => typeof value === "string")
|
|
253
|
+
}] : [];
|
|
254
|
+
} catch {
|
|
255
|
+
return [];
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
function StoryPoints({ toolbarTarget, onOpenItem }) {
|
|
259
|
+
const [sprints, setSprints] = (0, react.useState)([]);
|
|
260
|
+
const [users, setUsers] = (0, react.useState)([]);
|
|
261
|
+
const [sprint, setSprint] = (0, react.useState)(() => savedValue(SPRINT_KEY, ""));
|
|
262
|
+
const [owner, setOwner] = (0, react.useState)(() => savedValue(OWNER_KEY, "currentUser()"));
|
|
263
|
+
const [teams, setTeams] = (0, react.useState)(readTeams);
|
|
264
|
+
const [openTeamId, setOpenTeamId] = (0, react.useState)(() => readTeams()[0]?.id ?? "");
|
|
265
|
+
const [loadedTeams, setLoadedTeams] = (0, react.useState)(() => {
|
|
266
|
+
const first = readTeams()[0]?.id;
|
|
267
|
+
return new Set(first ? [first] : []);
|
|
268
|
+
});
|
|
269
|
+
const [teamDraft, setTeamDraft] = (0, react.useState)("");
|
|
270
|
+
const [teamEditor, setTeamEditor] = (0, react.useState)(null);
|
|
271
|
+
const [addingTeamId, setAddingTeamId] = (0, react.useState)("");
|
|
272
|
+
const addPeopleRef = (0, react.useRef)(null);
|
|
273
|
+
const addPeopleInputRef = (0, react.useRef)(null);
|
|
274
|
+
const [search, setSearch] = (0, react.useState)("");
|
|
275
|
+
const [results, setResults] = (0, react.useState)({});
|
|
276
|
+
const [errors, setErrors] = (0, react.useState)({});
|
|
277
|
+
const [directoryError, setDirectoryError] = (0, react.useState)("");
|
|
278
|
+
const [directoryLoading, setDirectoryLoading] = (0, react.useState)(true);
|
|
279
|
+
const [version, setVersion] = (0, react.useState)(0);
|
|
280
|
+
const [directoryVersion, setDirectoryVersion] = (0, react.useState)(0);
|
|
281
|
+
(0, react.useEffect)(() => {
|
|
282
|
+
const controller = new AbortController();
|
|
283
|
+
setDirectoryLoading(true);
|
|
284
|
+
setDirectoryError("");
|
|
285
|
+
Promise.all([json("/api/tomato-board/sprints", controller.signal), json("/api/tomato-board/filters", controller.signal)]).then(([data, directory]) => {
|
|
286
|
+
const sorted = [...data.sprints].sort((a, b) => (b.startDate ?? "").localeCompare(a.startDate ?? ""));
|
|
287
|
+
setSprints(sorted);
|
|
288
|
+
setUsers(directory.users);
|
|
289
|
+
setSprint((current) => sorted.some((value) => value.sprintId === current) ? current : sorted[0]?.sprintId || "");
|
|
290
|
+
}).catch((error) => {
|
|
291
|
+
if (!controller.signal.aborted) setDirectoryError(error.message);
|
|
292
|
+
}).finally(() => {
|
|
293
|
+
if (!controller.signal.aborted) setDirectoryLoading(false);
|
|
294
|
+
});
|
|
295
|
+
return () => controller.abort();
|
|
296
|
+
}, [directoryVersion]);
|
|
297
|
+
(0, react.useEffect)(() => {
|
|
298
|
+
try {
|
|
299
|
+
localStorage.setItem(TEAMS_KEY, JSON.stringify(teams));
|
|
300
|
+
} catch {}
|
|
301
|
+
}, [teams]);
|
|
302
|
+
(0, react.useEffect)(() => {
|
|
303
|
+
if (sprint) try {
|
|
304
|
+
localStorage.setItem(SPRINT_KEY, sprint);
|
|
305
|
+
} catch {}
|
|
306
|
+
}, [sprint]);
|
|
307
|
+
(0, react.useEffect)(() => {
|
|
308
|
+
try {
|
|
309
|
+
localStorage.setItem(OWNER_KEY, owner);
|
|
310
|
+
} catch {}
|
|
311
|
+
}, [owner]);
|
|
312
|
+
const openMembers = teams.find((team) => team.id === openTeamId)?.members ?? [];
|
|
313
|
+
const ownersKey = JSON.stringify([...new Set([owner, ...loadedTeams.has(openTeamId) ? openMembers : []])].sort());
|
|
314
|
+
(0, react.useEffect)(() => {
|
|
315
|
+
if (!sprint) return;
|
|
316
|
+
const controller = new AbortController();
|
|
317
|
+
const owners = JSON.parse(ownersKey).filter((username) => !results[username] && !errors[username]);
|
|
318
|
+
const worker = async () => {
|
|
319
|
+
while (owners.length && !controller.signal.aborted) {
|
|
320
|
+
const username = owners.shift();
|
|
321
|
+
try {
|
|
322
|
+
const data = await json(`/api/tomato-board/story-points?${new URLSearchParams({
|
|
323
|
+
sprint,
|
|
324
|
+
assignee: username,
|
|
325
|
+
refresh: String(version)
|
|
326
|
+
})}`, controller.signal);
|
|
327
|
+
if (!controller.signal.aborted) setResults((current) => ({
|
|
328
|
+
...current,
|
|
329
|
+
[username]: data
|
|
330
|
+
}));
|
|
331
|
+
} catch (error) {
|
|
332
|
+
if (!controller.signal.aborted) setErrors((current) => ({
|
|
333
|
+
...current,
|
|
334
|
+
[username]: error instanceof Error ? error.message : "读取失败"
|
|
335
|
+
}));
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
Promise.all([
|
|
340
|
+
worker(),
|
|
341
|
+
worker(),
|
|
342
|
+
worker()
|
|
343
|
+
]);
|
|
344
|
+
return () => controller.abort();
|
|
345
|
+
}, [
|
|
346
|
+
sprint,
|
|
347
|
+
ownersKey,
|
|
348
|
+
version
|
|
349
|
+
]);
|
|
350
|
+
const personal = results[owner];
|
|
351
|
+
const items = (0, react.useMemo)(() => [...personal?.items ?? []].sort((a, b) => (b.storyPoints ?? -1) - (a.storyPoints ?? -1) || a.itemKey.localeCompare(b.itemKey)), [personal]);
|
|
352
|
+
const sum = total(items);
|
|
353
|
+
const slices = items.filter((item) => item.storyPoints !== null && item.storyPoints > 0);
|
|
354
|
+
let offset = 0;
|
|
355
|
+
const gradient = slices.map((item, index) => {
|
|
356
|
+
const start = offset;
|
|
357
|
+
offset += item.storyPoints / sum * 100;
|
|
358
|
+
return `${colors[index % colors.length]} ${start}% ${offset}%`;
|
|
359
|
+
}).join(", ");
|
|
360
|
+
const userName = (username) => username === "currentUser()" ? "我" : users.find((user) => user.username === username)?.name ?? username;
|
|
361
|
+
const toggleTeam = (id) => {
|
|
362
|
+
setOpenTeamId((current) => current === id ? "" : id);
|
|
363
|
+
setLoadedTeams((current) => new Set(current).add(id));
|
|
364
|
+
setAddingTeamId("");
|
|
365
|
+
setTeamEditor(null);
|
|
366
|
+
};
|
|
367
|
+
const ranking = openMembers.map((username) => ({
|
|
368
|
+
username,
|
|
369
|
+
result: results[username],
|
|
370
|
+
points: total(results[username]?.items ?? [])
|
|
371
|
+
})).sort((a, b) => Number(Boolean(b.result)) - Number(Boolean(a.result)) || b.points - a.points || a.username.localeCompare(b.username));
|
|
372
|
+
const max = Math.max(1, ...ranking.map((row) => row.points));
|
|
373
|
+
const available = users.filter((user) => !openMembers.includes(user.username) && `${user.name} ${user.username}`.toLowerCase().includes(search.toLowerCase()));
|
|
374
|
+
const submitTeam = () => {
|
|
375
|
+
const name = teamDraft.trim();
|
|
376
|
+
if (!name || !teamEditor) return;
|
|
377
|
+
if (teamEditor.mode === "create") {
|
|
378
|
+
const team = {
|
|
379
|
+
id: teamId(),
|
|
380
|
+
name,
|
|
381
|
+
members: []
|
|
382
|
+
};
|
|
383
|
+
setTeams((current) => [...current, team]);
|
|
384
|
+
setOpenTeamId(team.id);
|
|
385
|
+
setLoadedTeams((current) => new Set(current).add(team.id));
|
|
386
|
+
} else setTeams((current) => current.map((team) => team.id === teamEditor.id ? {
|
|
387
|
+
...team,
|
|
388
|
+
name
|
|
389
|
+
} : team));
|
|
390
|
+
setTeamDraft("");
|
|
391
|
+
setTeamEditor(null);
|
|
392
|
+
};
|
|
393
|
+
const deleteTeam = (id) => {
|
|
394
|
+
setTeams((current) => current.filter((team) => team.id !== id));
|
|
395
|
+
if (openTeamId === id) setOpenTeamId("");
|
|
396
|
+
setLoadedTeams((current) => {
|
|
397
|
+
const next = new Set(current);
|
|
398
|
+
next.delete(id);
|
|
399
|
+
return next;
|
|
400
|
+
});
|
|
401
|
+
};
|
|
402
|
+
const updateMembers = (id, updater) => setTeams((current) => current.map((team) => team.id === id ? {
|
|
403
|
+
...team,
|
|
404
|
+
members: updater(team.members)
|
|
405
|
+
} : team));
|
|
406
|
+
(0, react.useEffect)(() => {
|
|
407
|
+
if (!addingTeamId) return;
|
|
408
|
+
const close = (event) => {
|
|
409
|
+
if (event.target instanceof Node && !addPeopleRef.current?.contains(event.target)) {
|
|
410
|
+
setAddingTeamId("");
|
|
411
|
+
setSearch("");
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
document.addEventListener("pointerdown", close, true);
|
|
415
|
+
requestAnimationFrame(() => addPeopleInputRef.current?.focus());
|
|
416
|
+
return () => document.removeEventListener("pointerdown", close, true);
|
|
417
|
+
}, [addingTeamId]);
|
|
418
|
+
(0, react.useEffect)(() => {
|
|
419
|
+
toolbarTarget(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
420
|
+
className: story_points_module_css_default.headerControls,
|
|
421
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "迭代" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
422
|
+
"aria-label": "选择迭代",
|
|
423
|
+
value: sprint,
|
|
424
|
+
disabled: directoryLoading,
|
|
425
|
+
onChange: (event) => {
|
|
426
|
+
setSprint(event.target.value);
|
|
427
|
+
setResults({});
|
|
428
|
+
setErrors({});
|
|
429
|
+
setLoadedTeams(/* @__PURE__ */ new Set());
|
|
430
|
+
},
|
|
431
|
+
children: [!sprints.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
432
|
+
value: "",
|
|
433
|
+
children: directoryLoading ? "正在读取迭代…" : "暂无迭代"
|
|
434
|
+
}), sprints.map((value) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
|
|
435
|
+
value: value.sprintId,
|
|
436
|
+
children: [
|
|
437
|
+
value.name,
|
|
438
|
+
" · ",
|
|
439
|
+
value.workspaceKey,
|
|
440
|
+
value.status === "completed" ? "(已结束)" : ""
|
|
441
|
+
]
|
|
442
|
+
}, value.sprintId))]
|
|
443
|
+
})] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
444
|
+
variant: "toolbar",
|
|
445
|
+
size: "sm",
|
|
446
|
+
className: story_points_module_css_default.headerIconButton,
|
|
447
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline16, {}),
|
|
448
|
+
title: "刷新",
|
|
449
|
+
"aria-label": "刷新迭代故事点",
|
|
450
|
+
onClick: () => {
|
|
451
|
+
setResults({});
|
|
452
|
+
setErrors({});
|
|
453
|
+
setVersion((value) => value + 1);
|
|
454
|
+
if (directoryError || !sprints.length) setDirectoryVersion((value) => value + 1);
|
|
455
|
+
}
|
|
456
|
+
})]
|
|
457
|
+
}));
|
|
458
|
+
return () => toolbarTarget(null);
|
|
459
|
+
}, [
|
|
460
|
+
directoryError,
|
|
461
|
+
directoryLoading,
|
|
462
|
+
sprint,
|
|
463
|
+
sprints,
|
|
464
|
+
toolbarTarget
|
|
465
|
+
]);
|
|
466
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
467
|
+
className: story_points_module_css_default.page,
|
|
468
|
+
children: [directoryError && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
469
|
+
className: story_points_module_css_default.error,
|
|
470
|
+
children: [directoryError, ",请点击刷新重试。"]
|
|
471
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
472
|
+
className: story_points_module_css_default.columns,
|
|
473
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
474
|
+
className: story_points_module_css_default.panel,
|
|
475
|
+
"aria-label": "个人故事点",
|
|
476
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
477
|
+
className: story_points_module_css_default.panelHeader,
|
|
478
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: "个人分布" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
479
|
+
"aria-label": "选择个人负责人",
|
|
480
|
+
value: owner,
|
|
481
|
+
onChange: (event) => setOwner(event.target.value),
|
|
482
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
483
|
+
value: "currentUser()",
|
|
484
|
+
children: "我负责的"
|
|
485
|
+
}), users.map((user) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
|
|
486
|
+
value: user.username,
|
|
487
|
+
children: [
|
|
488
|
+
user.name,
|
|
489
|
+
" · ",
|
|
490
|
+
user.username
|
|
491
|
+
]
|
|
492
|
+
}, user.username))]
|
|
493
|
+
})]
|
|
494
|
+
}), errors[owner] ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
495
|
+
className: story_points_module_css_default.error,
|
|
496
|
+
children: errors[owner]
|
|
497
|
+
}) : !personal ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
498
|
+
className: story_points_module_css_default.empty,
|
|
499
|
+
children: sprint ? "正在读取个人故事点…" : "请选择迭代"
|
|
500
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
501
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
502
|
+
className: story_points_module_css_default.summary,
|
|
503
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
504
|
+
className: story_points_module_css_default.eyebrow,
|
|
505
|
+
children: "故事点总数"
|
|
506
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
507
|
+
className: story_points_module_css_default.total,
|
|
508
|
+
children: [number(sum), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: " SP" })]
|
|
509
|
+
})] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
510
|
+
className: story_points_module_css_default.pie,
|
|
511
|
+
style: { background: gradient ? `conic-gradient(${gradient})` : void 0 },
|
|
512
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: slices.length }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "项占比" })] })
|
|
513
|
+
})]
|
|
514
|
+
}),
|
|
515
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
516
|
+
className: story_points_module_css_default.listHeading,
|
|
517
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", { children: "需求列表" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [items.length, " 项"] })]
|
|
518
|
+
}),
|
|
519
|
+
!items.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
520
|
+
className: story_points_module_css_default.empty,
|
|
521
|
+
children: "该负责人在本迭代暂无事项。"
|
|
522
|
+
}),
|
|
523
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: items.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
524
|
+
className: story_points_module_css_default.item,
|
|
525
|
+
role: "button",
|
|
526
|
+
tabIndex: 0,
|
|
527
|
+
"aria-label": `打开 ${item.itemKey} 的对话`,
|
|
528
|
+
onClick: () => onOpenItem(item),
|
|
529
|
+
onKeyDown: (event) => {
|
|
530
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
531
|
+
event.preventDefault();
|
|
532
|
+
onOpenItem(item);
|
|
533
|
+
}
|
|
534
|
+
},
|
|
535
|
+
children: [
|
|
536
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
537
|
+
className: story_points_module_css_default.dot,
|
|
538
|
+
style: { background: item.storyPoints && item.storyPoints > 0 ? colors[slices.indexOf(item) % colors.length] : "var(--dsw-alias-border-l2, #ddd)" }
|
|
539
|
+
}),
|
|
540
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
541
|
+
className: story_points_module_css_default.itemText,
|
|
542
|
+
children: [
|
|
543
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
544
|
+
className: story_points_module_css_default.itemTitle,
|
|
545
|
+
children: item.title
|
|
546
|
+
}),
|
|
547
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: item.itemKey }),
|
|
548
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tag, { children: item.status })
|
|
549
|
+
]
|
|
550
|
+
}),
|
|
551
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
|
|
552
|
+
className: story_points_module_css_default.itemPoints,
|
|
553
|
+
children: item.storyPoints === null ? "未估点" : `${number(item.storyPoints)} SP`
|
|
554
|
+
}),
|
|
555
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
556
|
+
className: story_points_module_css_default.tomatoLink,
|
|
557
|
+
variant: "ghost",
|
|
558
|
+
size: "sm",
|
|
559
|
+
title: "在番茄中打开事项",
|
|
560
|
+
"aria-label": `在番茄中打开 ${item.itemKey}`,
|
|
561
|
+
onClick: (event) => {
|
|
562
|
+
event.stopPropagation();
|
|
563
|
+
window.open(item.tomatoUrl, "_blank", "noopener,noreferrer");
|
|
564
|
+
},
|
|
565
|
+
onKeyDown: (event) => event.stopPropagation(),
|
|
566
|
+
children: "↗"
|
|
567
|
+
})
|
|
568
|
+
]
|
|
569
|
+
}, item.itemKey)) })
|
|
570
|
+
] })]
|
|
571
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
572
|
+
className: story_points_module_css_default.panel,
|
|
573
|
+
"aria-label": "团队故事点",
|
|
574
|
+
children: [
|
|
575
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
576
|
+
className: story_points_module_css_default.teamsHeader,
|
|
577
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: "团队分布" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
578
|
+
className: story_points_module_css_default.addTeamButton,
|
|
579
|
+
"aria-label": "创建团队",
|
|
580
|
+
title: "创建团队",
|
|
581
|
+
onClick: () => {
|
|
582
|
+
setTeamEditor({ mode: "create" });
|
|
583
|
+
setTeamDraft("");
|
|
584
|
+
},
|
|
585
|
+
children: "+ 创建团队"
|
|
586
|
+
})]
|
|
587
|
+
}),
|
|
588
|
+
teamEditor?.mode === "create" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
|
|
589
|
+
className: story_points_module_css_default.teamEditor,
|
|
590
|
+
onSubmit: (event) => {
|
|
591
|
+
event.preventDefault();
|
|
592
|
+
submitTeam();
|
|
593
|
+
},
|
|
594
|
+
children: [
|
|
595
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
596
|
+
autoFocus: true,
|
|
597
|
+
placeholder: "团队名称",
|
|
598
|
+
value: teamDraft,
|
|
599
|
+
onChange: (event) => setTeamDraft(event.target.value)
|
|
600
|
+
}),
|
|
601
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
602
|
+
type: "button",
|
|
603
|
+
onClick: () => setTeamEditor(null),
|
|
604
|
+
children: "取消"
|
|
605
|
+
}),
|
|
606
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
607
|
+
type: "submit",
|
|
608
|
+
children: "创建"
|
|
609
|
+
})
|
|
610
|
+
]
|
|
611
|
+
}),
|
|
612
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
613
|
+
className: story_points_module_css_default.teamAccordions,
|
|
614
|
+
children: teams.map((team) => {
|
|
615
|
+
const open = openTeamId === team.id;
|
|
616
|
+
const rows = open ? ranking : [];
|
|
617
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
618
|
+
className: story_points_module_css_default.teamAccordion,
|
|
619
|
+
children: [
|
|
620
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
621
|
+
className: story_points_module_css_default.teamAccordionHeader,
|
|
622
|
+
children: [
|
|
623
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
624
|
+
className: story_points_module_css_default.teamToggle,
|
|
625
|
+
"aria-expanded": open,
|
|
626
|
+
onClick: () => toggleTeam(team.id),
|
|
627
|
+
children: [
|
|
628
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
629
|
+
className: story_points_module_css_default.chevron,
|
|
630
|
+
children: "›"
|
|
631
|
+
}),
|
|
632
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: team.name }),
|
|
633
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("small", { children: [team.members.length, " 人"] })
|
|
634
|
+
]
|
|
635
|
+
}),
|
|
636
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
637
|
+
className: story_points_module_css_default.renameTeam,
|
|
638
|
+
"aria-label": `改名 ${team.name}`,
|
|
639
|
+
title: "改名",
|
|
640
|
+
onClick: () => {
|
|
641
|
+
setTeamEditor({
|
|
642
|
+
mode: "rename",
|
|
643
|
+
id: team.id
|
|
644
|
+
});
|
|
645
|
+
setTeamDraft(team.name);
|
|
646
|
+
setOpenTeamId(team.id);
|
|
647
|
+
},
|
|
648
|
+
children: "✎"
|
|
649
|
+
}),
|
|
650
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
651
|
+
className: story_points_module_css_default.teamRowActions,
|
|
652
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
653
|
+
"aria-label": `删除 ${team.name}`,
|
|
654
|
+
title: "删除",
|
|
655
|
+
onClick: () => deleteTeam(team.id),
|
|
656
|
+
children: "×"
|
|
657
|
+
})
|
|
658
|
+
})
|
|
659
|
+
]
|
|
660
|
+
}),
|
|
661
|
+
teamEditor?.mode === "rename" && teamEditor.id === team.id && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
|
|
662
|
+
className: story_points_module_css_default.teamEditor,
|
|
663
|
+
onSubmit: (event) => {
|
|
664
|
+
event.preventDefault();
|
|
665
|
+
submitTeam();
|
|
666
|
+
},
|
|
667
|
+
children: [
|
|
668
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
669
|
+
autoFocus: true,
|
|
670
|
+
value: teamDraft,
|
|
671
|
+
onChange: (event) => setTeamDraft(event.target.value)
|
|
672
|
+
}),
|
|
673
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
674
|
+
type: "button",
|
|
675
|
+
onClick: () => setTeamEditor(null),
|
|
676
|
+
children: "取消"
|
|
677
|
+
}),
|
|
678
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
679
|
+
type: "submit",
|
|
680
|
+
children: "保存"
|
|
681
|
+
})
|
|
682
|
+
]
|
|
683
|
+
}),
|
|
684
|
+
open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
685
|
+
className: story_points_module_css_default.teamBody,
|
|
686
|
+
children: [
|
|
687
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
688
|
+
className: story_points_module_css_default.teamBodyToolbar,
|
|
689
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: team.members.length ? "成员故事点" : "暂无成员" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
690
|
+
ref: addingTeamId === team.id ? addPeopleRef : void 0,
|
|
691
|
+
className: story_points_module_css_default.addPeopleRoot,
|
|
692
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
693
|
+
className: story_points_module_css_default.smallAddButton,
|
|
694
|
+
onClick: () => setAddingTeamId((current) => current === team.id ? "" : team.id),
|
|
695
|
+
children: "+ 添加成员"
|
|
696
|
+
}), addingTeamId === team.id && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
697
|
+
className: story_points_module_css_default.addPeople,
|
|
698
|
+
role: "dialog",
|
|
699
|
+
children: [
|
|
700
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
701
|
+
className: story_points_module_css_default.addPeopleTitle,
|
|
702
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: "添加成员" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
703
|
+
onClick: () => setAddingTeamId(""),
|
|
704
|
+
children: "×"
|
|
705
|
+
})]
|
|
706
|
+
}),
|
|
707
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
708
|
+
ref: addPeopleInputRef,
|
|
709
|
+
value: search,
|
|
710
|
+
onChange: (event) => setSearch(event.target.value),
|
|
711
|
+
placeholder: "搜索姓名或用户名…"
|
|
712
|
+
}),
|
|
713
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [available.map((user) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
714
|
+
onClick: () => {
|
|
715
|
+
updateMembers(team.id, (current) => [...current, user.username]);
|
|
716
|
+
setAddingTeamId("");
|
|
717
|
+
setSearch("");
|
|
718
|
+
},
|
|
719
|
+
children: [
|
|
720
|
+
user.name,
|
|
721
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: user.username }),
|
|
722
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "+" })
|
|
723
|
+
]
|
|
724
|
+
}, user.username)), !available.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: "没有可添加的成员" })] })
|
|
725
|
+
]
|
|
726
|
+
})]
|
|
727
|
+
})]
|
|
728
|
+
}),
|
|
729
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
730
|
+
className: story_points_module_css_default.ranking,
|
|
731
|
+
children: rows.map((row, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
732
|
+
className: story_points_module_css_default.rankRow,
|
|
733
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
734
|
+
className: story_points_module_css_default.memberRow,
|
|
735
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
736
|
+
className: story_points_module_css_default.rankLabel,
|
|
737
|
+
"aria-pressed": owner === row.username,
|
|
738
|
+
onClick: () => setOwner(row.username),
|
|
739
|
+
children: [
|
|
740
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("i", {
|
|
741
|
+
className: story_points_module_css_default.rankFill,
|
|
742
|
+
style: { width: `${row.points / max * 100}%` }
|
|
743
|
+
}),
|
|
744
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
745
|
+
className: story_points_module_css_default.rankIndex,
|
|
746
|
+
children: String(index + 1).padStart(2, "0")
|
|
747
|
+
}),
|
|
748
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
749
|
+
className: story_points_module_css_default.memberAvatar,
|
|
750
|
+
children: userName(row.username).slice(0, 1)
|
|
751
|
+
}),
|
|
752
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
753
|
+
className: story_points_module_css_default.memberIdentity,
|
|
754
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: userName(row.username) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: row.result ? `${row.result.items.length} 个事项` : errors[row.username] ? "读取失败" : "读取中…" })]
|
|
755
|
+
}),
|
|
756
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: row.result ? `${number(row.points)} SP` : "—" })
|
|
757
|
+
]
|
|
758
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
759
|
+
className: story_points_module_css_default.removeMember,
|
|
760
|
+
"aria-label": `移除 ${userName(row.username)}`,
|
|
761
|
+
title: "移除成员",
|
|
762
|
+
onClick: () => updateMembers(team.id, (current) => current.filter((value) => value !== row.username)),
|
|
763
|
+
children: "×"
|
|
764
|
+
})]
|
|
765
|
+
})
|
|
766
|
+
}, row.username))
|
|
767
|
+
}),
|
|
768
|
+
!team.members.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
769
|
+
className: story_points_module_css_default.teamBodyEmpty,
|
|
770
|
+
children: "添加成员后查看故事点分布"
|
|
771
|
+
})
|
|
772
|
+
]
|
|
773
|
+
})
|
|
774
|
+
]
|
|
775
|
+
}, team.id);
|
|
776
|
+
})
|
|
777
|
+
}),
|
|
778
|
+
!teams.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
779
|
+
className: story_points_module_css_default.empty,
|
|
780
|
+
children: "点击右上角加号创建团队。"
|
|
781
|
+
})
|
|
782
|
+
]
|
|
783
|
+
})]
|
|
784
|
+
})]
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
//#endregion
|
|
67
788
|
//#region src/client/TomatoBoard.tsx
|
|
68
789
|
let state = {
|
|
69
790
|
open: false,
|
|
70
791
|
loading: false,
|
|
792
|
+
loaded: false,
|
|
71
793
|
items: [],
|
|
72
794
|
error: null,
|
|
73
795
|
selectedItem: null,
|
|
@@ -88,14 +810,6 @@ window.__ModuleLoader__.load({
|
|
|
88
810
|
};
|
|
89
811
|
const snapshot = () => state;
|
|
90
812
|
const TOMATO_ITEM_KEY_PATTERN = /^\[([A-Za-z][A-Za-z0-9]*(?:-[A-Za-z0-9]+)*-\d+)\]/u;
|
|
91
|
-
const TOMATO_TYPE_OPTIONS = [
|
|
92
|
-
"测试缺陷",
|
|
93
|
-
"缺陷",
|
|
94
|
-
"Bug",
|
|
95
|
-
"EnablerStory",
|
|
96
|
-
"Story",
|
|
97
|
-
"Task"
|
|
98
|
-
];
|
|
99
813
|
const TOMATO_STATUS_ORDER = [
|
|
100
814
|
"新建",
|
|
101
815
|
"Bugfix",
|
|
@@ -115,6 +829,48 @@ window.__ModuleLoader__.load({
|
|
|
115
829
|
const TOMATO_FILTER_BLACKLIST_KEY = "taskboard.tomatoFilterBlacklist.v1";
|
|
116
830
|
const TOMATO_SESSION_LINKS_KEY = "taskboard.tomatoSessionLinks.v1";
|
|
117
831
|
const TOMATO_MUTED_ITEMS_KEY = "taskboard.tomatoMutedItems.v1";
|
|
832
|
+
const TOMATO_LANE_ORDER_KEY = "taskboard.tomatoLaneOrder.v1";
|
|
833
|
+
function readLaneOrder() {
|
|
834
|
+
try {
|
|
835
|
+
const value = JSON.parse(window.localStorage.getItem(TOMATO_LANE_ORDER_KEY) ?? "{}");
|
|
836
|
+
return {
|
|
837
|
+
head: typeof value?.head === "string" ? value.head : null,
|
|
838
|
+
next: value?.next && typeof value.next === "object" ? value.next : {}
|
|
839
|
+
};
|
|
840
|
+
} catch {
|
|
841
|
+
return {
|
|
842
|
+
head: null,
|
|
843
|
+
next: {}
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
function laneOrderValues(order) {
|
|
848
|
+
const values = [];
|
|
849
|
+
const seen = /* @__PURE__ */ new Set();
|
|
850
|
+
let current = order.head;
|
|
851
|
+
while (current && !seen.has(current) && values.length < 1e3) {
|
|
852
|
+
values.push(current);
|
|
853
|
+
seen.add(current);
|
|
854
|
+
current = order.next[current] ?? null;
|
|
855
|
+
}
|
|
856
|
+
return values;
|
|
857
|
+
}
|
|
858
|
+
function createLaneOrder(values) {
|
|
859
|
+
const next = {};
|
|
860
|
+
values.forEach((value, index) => {
|
|
861
|
+
next[value] = values[index + 1] ?? null;
|
|
862
|
+
});
|
|
863
|
+
return {
|
|
864
|
+
head: values[0] ?? null,
|
|
865
|
+
next
|
|
866
|
+
};
|
|
867
|
+
}
|
|
868
|
+
function applyLaneOrder(statuses, order) {
|
|
869
|
+
const available = new Set(statuses);
|
|
870
|
+
const tracked = laneOrderValues(order).filter((status) => available.has(status));
|
|
871
|
+
const trackedSet = new Set(tracked);
|
|
872
|
+
return [...tracked, ...statuses.filter((status) => !trackedSet.has(status))];
|
|
873
|
+
}
|
|
118
874
|
function readSessionLinks() {
|
|
119
875
|
try {
|
|
120
876
|
const value = JSON.parse(window.localStorage.getItem(TOMATO_SESSION_LINKS_KEY) ?? "{}");
|
|
@@ -137,12 +893,14 @@ window.__ModuleLoader__.load({
|
|
|
137
893
|
const value = JSON.parse(window.localStorage.getItem(TOMATO_FILTER_BLACKLIST_KEY) ?? "{}");
|
|
138
894
|
return {
|
|
139
895
|
types: new Set(Array.isArray(value?.types) ? value.types.filter((item) => typeof item === "string") : []),
|
|
140
|
-
statuses: new Set(Array.isArray(value?.statuses) ? value.statuses.filter((item) => typeof item === "string") : [])
|
|
896
|
+
statuses: new Set(Array.isArray(value?.statuses) ? value.statuses.filter((item) => typeof item === "string") : []),
|
|
897
|
+
workspaces: new Set(Array.isArray(value?.workspaces) ? value.workspaces.filter((item) => typeof item === "string") : [])
|
|
141
898
|
};
|
|
142
899
|
} catch {
|
|
143
900
|
return {
|
|
144
901
|
types: /* @__PURE__ */ new Set(),
|
|
145
|
-
statuses: /* @__PURE__ */ new Set()
|
|
902
|
+
statuses: /* @__PURE__ */ new Set(),
|
|
903
|
+
workspaces: /* @__PURE__ */ new Set()
|
|
146
904
|
};
|
|
147
905
|
}
|
|
148
906
|
}
|
|
@@ -154,18 +912,20 @@ window.__ModuleLoader__.load({
|
|
|
154
912
|
return /* @__PURE__ */ new Set();
|
|
155
913
|
}
|
|
156
914
|
}
|
|
157
|
-
async function refresh() {
|
|
915
|
+
async function refresh(assignee = "currentUser()") {
|
|
158
916
|
emit({
|
|
159
917
|
loading: true,
|
|
160
918
|
error: null
|
|
161
919
|
});
|
|
162
920
|
try {
|
|
163
|
-
const
|
|
921
|
+
const query = new URLSearchParams({ assignee });
|
|
922
|
+
const response = await fetch(`/api/tomato-board/items?${query}`, { headers: { accept: "application/json" } });
|
|
164
923
|
const body = await response.json();
|
|
165
924
|
if (!response.ok) throw new Error(body.error || `请求失败 (${response.status})`);
|
|
166
925
|
emit({
|
|
167
926
|
items: body.items ?? [],
|
|
168
|
-
truncated: body.truncated === true
|
|
927
|
+
truncated: body.truncated === true,
|
|
928
|
+
loaded: true
|
|
169
929
|
});
|
|
170
930
|
} catch (error) {
|
|
171
931
|
emit({ error: error instanceof Error ? error.message : "番茄事项读取失败" });
|
|
@@ -178,7 +938,9 @@ window.__ModuleLoader__.load({
|
|
|
178
938
|
disposeWorkbench = null;
|
|
179
939
|
emit({
|
|
180
940
|
open: false,
|
|
181
|
-
selectedItem: null
|
|
941
|
+
selectedItem: null,
|
|
942
|
+
loaded: false,
|
|
943
|
+
error: null
|
|
182
944
|
});
|
|
183
945
|
dispose?.();
|
|
184
946
|
}
|
|
@@ -195,6 +957,19 @@ window.__ModuleLoader__.load({
|
|
|
195
957
|
}), wide && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "番茄工作台" })]
|
|
196
958
|
});
|
|
197
959
|
}
|
|
960
|
+
function TomatoBoardTopbarAction({ openWorkbench }) {
|
|
961
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
962
|
+
className: tomato_board_module_css_default.topbarAction,
|
|
963
|
+
type: "button",
|
|
964
|
+
title: "打开番茄工作台",
|
|
965
|
+
onClick: openWorkbench,
|
|
966
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
967
|
+
className: tomato_board_module_css_default.tomatoIcon,
|
|
968
|
+
"aria-hidden": "true",
|
|
969
|
+
children: "T"
|
|
970
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "番茄工作台" })]
|
|
971
|
+
});
|
|
972
|
+
}
|
|
198
973
|
function CreateConversationDialog({ ctx, item }) {
|
|
199
974
|
const [workspaceId, setWorkspaceId] = (0, react.useState)("");
|
|
200
975
|
const [workspaceMenuOpen, setWorkspaceMenuOpen] = (0, react.useState)(false);
|
|
@@ -293,18 +1068,36 @@ window.__ModuleLoader__.load({
|
|
|
293
1068
|
function TomatoBoardPanel({ ctx }) {
|
|
294
1069
|
const board = (0, react.useSyncExternalStore)(subscribe, snapshot, snapshot);
|
|
295
1070
|
const workbenchRef = (0, react.useRef)(null);
|
|
1071
|
+
const filterMenuRef = (0, react.useRef)(null);
|
|
1072
|
+
const [page, setPage] = (0, react.useState)("board");
|
|
1073
|
+
const [storyToolbar, setStoryToolbar] = (0, react.useState)(null);
|
|
296
1074
|
const [search, setSearch] = (0, react.useState)("");
|
|
297
1075
|
const [blacklist, setBlacklist] = (0, react.useState)(readFilterBlacklist);
|
|
298
1076
|
const [mutedItems, setMutedItems] = (0, react.useState)(readMutedItems);
|
|
1077
|
+
const [selectedAssignee, setSelectedAssignee] = (0, react.useState)("currentUser()");
|
|
1078
|
+
const [filterDirectory, setFilterDirectory] = (0, react.useState)({
|
|
1079
|
+
users: [],
|
|
1080
|
+
workspaces: []
|
|
1081
|
+
});
|
|
1082
|
+
const [directoryVersion, setDirectoryVersion] = (0, react.useState)(0);
|
|
1083
|
+
const [laneOrder, setLaneOrder] = (0, react.useState)(readLaneOrder);
|
|
1084
|
+
const [draggedLane, setDraggedLane] = (0, react.useState)(null);
|
|
1085
|
+
const [dropLane, setDropLane] = (0, react.useState)(null);
|
|
1086
|
+
const laneElements = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
1087
|
+
const previousLanePositions = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
299
1088
|
const sessions = (0, react.useSyncExternalStore)((listener) => ctx.sessions.list.subscribe(listener), () => ctx.sessions.list.getSnapshot(), () => ctx.sessions.list.getSnapshot());
|
|
300
1089
|
(0, react.useEffect)(() => {
|
|
301
|
-
if (board.open && board.
|
|
1090
|
+
if (board.open && !board.loaded && !board.loading && !board.error) refresh();
|
|
302
1091
|
}, [
|
|
303
1092
|
board.error,
|
|
304
|
-
board.
|
|
1093
|
+
board.loaded,
|
|
305
1094
|
board.loading,
|
|
306
1095
|
board.open
|
|
307
1096
|
]);
|
|
1097
|
+
(0, react.useEffect)(() => {
|
|
1098
|
+
if (!board.open) return;
|
|
1099
|
+
fetch("/api/tomato-board/filters", { headers: { accept: "application/json" } }).then((response) => response.ok ? response.json() : Promise.reject(/* @__PURE__ */ new Error(`HTTP ${response.status}`))).then((value) => setFilterDirectory(value)).catch(() => {});
|
|
1100
|
+
}, [board.open, directoryVersion]);
|
|
308
1101
|
(0, react.useEffect)(() => {
|
|
309
1102
|
if (!board.open) return;
|
|
310
1103
|
const closeOnOutsideNavigation = (event) => {
|
|
@@ -316,6 +1109,41 @@ window.__ModuleLoader__.load({
|
|
|
316
1109
|
document.addEventListener("pointerdown", closeOnOutsideNavigation, true);
|
|
317
1110
|
return () => document.removeEventListener("pointerdown", closeOnOutsideNavigation, true);
|
|
318
1111
|
}, [board.open]);
|
|
1112
|
+
(0, react.useEffect)(() => {
|
|
1113
|
+
const closeFilterMenu = (event) => {
|
|
1114
|
+
const menu = filterMenuRef.current;
|
|
1115
|
+
if (menu?.open && event.target instanceof Node && !menu.contains(event.target)) menu.open = false;
|
|
1116
|
+
};
|
|
1117
|
+
const closeFilterMenuOnEscape = (event) => {
|
|
1118
|
+
if (event.key === "Escape" && filterMenuRef.current?.open) filterMenuRef.current.open = false;
|
|
1119
|
+
};
|
|
1120
|
+
document.addEventListener("pointerdown", closeFilterMenu, true);
|
|
1121
|
+
document.addEventListener("keydown", closeFilterMenuOnEscape);
|
|
1122
|
+
return () => {
|
|
1123
|
+
document.removeEventListener("pointerdown", closeFilterMenu, true);
|
|
1124
|
+
document.removeEventListener("keydown", closeFilterMenuOnEscape);
|
|
1125
|
+
};
|
|
1126
|
+
}, []);
|
|
1127
|
+
(0, react.useLayoutEffect)(() => {
|
|
1128
|
+
const previous = previousLanePositions.current;
|
|
1129
|
+
if (previous.size === 0) return;
|
|
1130
|
+
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
|
1131
|
+
previous.clear();
|
|
1132
|
+
return;
|
|
1133
|
+
}
|
|
1134
|
+
for (const [status, element] of laneElements.current) {
|
|
1135
|
+
const before = previous.get(status);
|
|
1136
|
+
if (!before) continue;
|
|
1137
|
+
const after = element.getBoundingClientRect();
|
|
1138
|
+
const deltaX = before.left - after.left;
|
|
1139
|
+
const deltaY = before.top - after.top;
|
|
1140
|
+
if (deltaX || deltaY) element.animate([{ transform: `translate(${deltaX}px, ${deltaY}px)` }, { transform: "translate(0, 0)" }], {
|
|
1141
|
+
duration: 240,
|
|
1142
|
+
easing: "cubic-bezier(.2,.8,.2,1)"
|
|
1143
|
+
});
|
|
1144
|
+
}
|
|
1145
|
+
previous.clear();
|
|
1146
|
+
}, [laneOrder]);
|
|
319
1147
|
if (!board.open) return null;
|
|
320
1148
|
function openItem(item) {
|
|
321
1149
|
const stored = linkedSessionId(item.itemKey);
|
|
@@ -334,32 +1162,55 @@ window.__ModuleLoader__.load({
|
|
|
334
1162
|
emit({ selectedItem: item });
|
|
335
1163
|
}
|
|
336
1164
|
const normalizedSearch = search.trim().toLowerCase();
|
|
337
|
-
const filteredItems = board.items.filter((item) => !blacklist.types.has(item.itemType) && !blacklist.statuses.has(item.status) && (!normalizedSearch || [
|
|
1165
|
+
const filteredItems = board.items.filter((item) => !blacklist.types.has(item.itemType) && !blacklist.statuses.has(item.status) && !blacklist.workspaces.has(item.workspaceKey) && !blacklist.workspaces.has(item.workspaceName) && (!normalizedSearch || [
|
|
338
1166
|
item.itemKey,
|
|
339
1167
|
item.title,
|
|
340
1168
|
item.itemType,
|
|
341
1169
|
item.status,
|
|
342
|
-
item.
|
|
1170
|
+
item.workspaceKey,
|
|
1171
|
+
item.workspaceName,
|
|
343
1172
|
item.creator,
|
|
1173
|
+
item.assignees.join(" "),
|
|
344
1174
|
item.priority
|
|
345
1175
|
].join(" ").toLowerCase().includes(normalizedSearch)));
|
|
346
|
-
const typeOptions = [...new Set(
|
|
347
|
-
const statusOptions = [...new Set([...TOMATO_STATUS_ORDER, ...board.items.map((item) => item.status).filter((status) => !TOMATO_STATUS_ORDER.includes(status))])];
|
|
348
|
-
const
|
|
1176
|
+
const typeOptions = [...new Set(board.items.map((item) => item.itemType).filter(Boolean))].sort((left, right) => left.localeCompare(right));
|
|
1177
|
+
const statusOptions = applyLaneOrder([...new Set([...TOMATO_STATUS_ORDER, ...board.items.map((item) => item.status).filter((status) => !TOMATO_STATUS_ORDER.includes(status))])], laneOrder);
|
|
1178
|
+
const workspaceOptions = (() => {
|
|
1179
|
+
const entries = /* @__PURE__ */ new Map();
|
|
1180
|
+
for (const item of board.items) {
|
|
1181
|
+
const value = item.workspaceKey || item.workspaceName || item.workspace;
|
|
1182
|
+
if (!value) continue;
|
|
1183
|
+
const label = item.workspaceName && item.workspaceKey && item.workspaceName !== item.workspaceKey ? `${item.workspaceName} (${item.workspaceKey})` : value;
|
|
1184
|
+
if (!entries.has(value)) entries.set(value, {
|
|
1185
|
+
value,
|
|
1186
|
+
label
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1189
|
+
return [...entries.values()];
|
|
1190
|
+
})();
|
|
1191
|
+
const defaultStatuses = [...new Set([...TOMATO_STATUS_ORDER.filter((status) => filteredItems.some((item) => item.status === status)), ...filteredItems.map((item) => item.status).filter((status) => !TOMATO_STATUS_ORDER.includes(status))])];
|
|
1192
|
+
const statuses = applyLaneOrder(defaultStatuses, laneOrder);
|
|
1193
|
+
const persistBlacklist = (next) => {
|
|
1194
|
+
window.localStorage.setItem(TOMATO_FILTER_BLACKLIST_KEY, JSON.stringify({
|
|
1195
|
+
types: [...next.types],
|
|
1196
|
+
statuses: [...next.statuses],
|
|
1197
|
+
workspaces: [...next.workspaces]
|
|
1198
|
+
}));
|
|
1199
|
+
return next;
|
|
1200
|
+
};
|
|
349
1201
|
const toggleBlacklist = (kind, value) => setBlacklist((current) => {
|
|
350
1202
|
const nextValues = new Set(current[kind]);
|
|
351
1203
|
if (nextValues.has(value)) nextValues.delete(value);
|
|
352
1204
|
else nextValues.add(value);
|
|
353
|
-
|
|
1205
|
+
return persistBlacklist({
|
|
354
1206
|
...current,
|
|
355
1207
|
[kind]: nextValues
|
|
356
|
-
};
|
|
357
|
-
window.localStorage.setItem(TOMATO_FILTER_BLACKLIST_KEY, JSON.stringify({
|
|
358
|
-
types: [...next.types],
|
|
359
|
-
statuses: [...next.statuses]
|
|
360
|
-
}));
|
|
361
|
-
return next;
|
|
1208
|
+
});
|
|
362
1209
|
});
|
|
1210
|
+
const setWorkspaceFilterAll = (visible) => setBlacklist((current) => persistBlacklist({
|
|
1211
|
+
...current,
|
|
1212
|
+
workspaces: visible ? /* @__PURE__ */ new Set() : new Set(workspaceOptions.map((option) => option.value))
|
|
1213
|
+
}));
|
|
363
1214
|
const toggleMutedItem = (itemKey) => setMutedItems((current) => {
|
|
364
1215
|
const next = new Set(current);
|
|
365
1216
|
if (next.has(itemKey)) next.delete(itemKey);
|
|
@@ -367,6 +1218,25 @@ window.__ModuleLoader__.load({
|
|
|
367
1218
|
window.localStorage.setItem(TOMATO_MUTED_ITEMS_KEY, JSON.stringify([...next]));
|
|
368
1219
|
return next;
|
|
369
1220
|
});
|
|
1221
|
+
const moveLane = (dragged, target, after) => {
|
|
1222
|
+
if (dragged === target) return;
|
|
1223
|
+
previousLanePositions.current = new Map([...laneElements.current].map(([status, element]) => [status, element.getBoundingClientRect()]));
|
|
1224
|
+
setLaneOrder((current) => {
|
|
1225
|
+
const visible = applyLaneOrder(defaultStatuses, current).filter((status) => status !== dragged);
|
|
1226
|
+
const targetIndex = visible.indexOf(target);
|
|
1227
|
+
visible.splice(targetIndex + (after ? 1 : 0), 0, dragged);
|
|
1228
|
+
const previousTracked = laneOrderValues(current);
|
|
1229
|
+
const trackedSet = new Set([
|
|
1230
|
+
...previousTracked,
|
|
1231
|
+
dragged,
|
|
1232
|
+
target
|
|
1233
|
+
]);
|
|
1234
|
+
const hiddenTracked = previousTracked.filter((status) => !visible.includes(status));
|
|
1235
|
+
const next = createLaneOrder([...visible.filter((status) => trackedSet.has(status)), ...hiddenTracked]);
|
|
1236
|
+
window.localStorage.setItem(TOMATO_LANE_ORDER_KEY, JSON.stringify(next));
|
|
1237
|
+
return next;
|
|
1238
|
+
});
|
|
1239
|
+
};
|
|
370
1240
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
371
1241
|
ref: workbenchRef,
|
|
372
1242
|
className: tomato_board_module_css_default.workbench,
|
|
@@ -374,171 +1244,265 @@ window.__ModuleLoader__.load({
|
|
|
374
1244
|
children: [
|
|
375
1245
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
376
1246
|
className: tomato_board_module_css_default.header,
|
|
377
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
378
|
-
className: tomato_board_module_css_default.
|
|
379
|
-
children: [
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
1247
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1248
|
+
className: tomato_board_module_css_default.titleRow,
|
|
1249
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", { children: "番茄工作台" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1250
|
+
className: tomato_board_module_css_default.actions,
|
|
1251
|
+
children: [
|
|
1252
|
+
page === "points" && storyToolbar,
|
|
1253
|
+
page === "board" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1254
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1255
|
+
className: tomato_board_module_css_default.searchField,
|
|
1256
|
+
children: [
|
|
1257
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1258
|
+
"aria-hidden": "true",
|
|
1259
|
+
children: "⌕"
|
|
1260
|
+
}),
|
|
1261
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1262
|
+
type: "search",
|
|
1263
|
+
value: search,
|
|
1264
|
+
onChange: (event) => setSearch(event.target.value),
|
|
1265
|
+
placeholder: "搜索标题或 tag…",
|
|
1266
|
+
"aria-label": "搜索标题或 tag"
|
|
1267
|
+
}),
|
|
1268
|
+
search && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1269
|
+
type: "button",
|
|
1270
|
+
"aria-label": "清空搜索词",
|
|
1271
|
+
onClick: () => setSearch(""),
|
|
1272
|
+
children: "×"
|
|
1273
|
+
})
|
|
1274
|
+
]
|
|
386
1275
|
}),
|
|
387
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
1276
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
1277
|
+
ref: filterMenuRef,
|
|
1278
|
+
className: tomato_board_module_css_default.filterMenu,
|
|
1279
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", {
|
|
1280
|
+
"aria-label": "空间、负责人、类型和状态筛选",
|
|
1281
|
+
title: "空间、负责人、类型和状态筛选",
|
|
1282
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1283
|
+
"aria-hidden": "true",
|
|
1284
|
+
children: "▽"
|
|
1285
|
+
}), (blacklist.types.size > 0 || blacklist.statuses.size > 0 || blacklist.workspaces.size > 0 || selectedAssignee !== "currentUser()") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("i", {})]
|
|
1286
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1287
|
+
className: tomato_board_module_css_default.filterPopover,
|
|
1288
|
+
children: [
|
|
1289
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkspaceFilterRow, {
|
|
1290
|
+
options: workspaceOptions,
|
|
1291
|
+
hidden: blacklist.workspaces,
|
|
1292
|
+
onToggle: (value) => toggleBlacklist("workspaces", value),
|
|
1293
|
+
onSetAll: setWorkspaceFilterAll
|
|
1294
|
+
}),
|
|
1295
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssigneePicker, {
|
|
1296
|
+
users: filterDirectory.users,
|
|
1297
|
+
value: selectedAssignee,
|
|
1298
|
+
onChange: (value) => {
|
|
1299
|
+
setSelectedAssignee(value);
|
|
1300
|
+
refresh(value);
|
|
1301
|
+
}
|
|
1302
|
+
}),
|
|
1303
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(FilterRow, {
|
|
1304
|
+
label: "类型",
|
|
1305
|
+
options: typeOptions,
|
|
1306
|
+
hidden: blacklist.types,
|
|
1307
|
+
onToggle: (value) => toggleBlacklist("types", value)
|
|
1308
|
+
}),
|
|
1309
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(FilterRow, {
|
|
1310
|
+
label: "状态",
|
|
1311
|
+
options: statusOptions,
|
|
1312
|
+
hidden: blacklist.statuses,
|
|
1313
|
+
onToggle: (value) => toggleBlacklist("statuses", value)
|
|
1314
|
+
})
|
|
1315
|
+
]
|
|
1316
|
+
})]
|
|
393
1317
|
}),
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
1318
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1319
|
+
variant: "toolbar",
|
|
1320
|
+
size: "sm",
|
|
1321
|
+
className: tomato_board_module_css_default.headerIconButton,
|
|
1322
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline16, {}),
|
|
1323
|
+
title: "刷新番茄事项",
|
|
1324
|
+
"aria-label": "刷新番茄事项",
|
|
1325
|
+
disabled: board.loading,
|
|
1326
|
+
onClick: () => {
|
|
1327
|
+
refresh(selectedAssignee);
|
|
1328
|
+
setDirectoryVersion((value) => value + 1);
|
|
1329
|
+
}
|
|
399
1330
|
})
|
|
400
|
-
]
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
title: "
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
427
|
-
variant: "toolbar",
|
|
428
|
-
size: "sm",
|
|
429
|
-
className: tomato_board_module_css_default.headerIconButton,
|
|
430
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline16, {}),
|
|
431
|
-
title: "刷新番茄事项",
|
|
432
|
-
"aria-label": "刷新番茄事项",
|
|
433
|
-
disabled: board.loading,
|
|
434
|
-
onClick: () => void refresh()
|
|
435
|
-
}),
|
|
436
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
437
|
-
variant: "toolbar",
|
|
438
|
-
size: "sm",
|
|
439
|
-
className: tomato_board_module_css_default.headerIconButton,
|
|
440
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, {}),
|
|
441
|
-
title: "关闭番茄工作台",
|
|
442
|
-
"aria-label": "关闭番茄工作台",
|
|
443
|
-
onClick: closeWorkbench
|
|
444
|
-
})
|
|
445
|
-
]
|
|
1331
|
+
] }),
|
|
1332
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1333
|
+
variant: "toolbar",
|
|
1334
|
+
size: "sm",
|
|
1335
|
+
className: tomato_board_module_css_default.headerIconButton,
|
|
1336
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, {}),
|
|
1337
|
+
title: "关闭番茄工作台",
|
|
1338
|
+
"aria-label": "关闭番茄工作台",
|
|
1339
|
+
onClick: closeWorkbench
|
|
1340
|
+
})
|
|
1341
|
+
]
|
|
1342
|
+
})]
|
|
1343
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("nav", {
|
|
1344
|
+
className: tomato_board_module_css_default.pageTabs,
|
|
1345
|
+
"aria-label": "番茄工作台页面",
|
|
1346
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1347
|
+
type: "button",
|
|
1348
|
+
"aria-current": page === "board" ? "page" : void 0,
|
|
1349
|
+
onClick: () => setPage("board"),
|
|
1350
|
+
children: "事项看板"
|
|
1351
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1352
|
+
type: "button",
|
|
1353
|
+
"aria-current": page === "points" ? "page" : void 0,
|
|
1354
|
+
onClick: () => setPage("points"),
|
|
1355
|
+
children: "迭代投入"
|
|
1356
|
+
})]
|
|
446
1357
|
})]
|
|
447
1358
|
}),
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
1359
|
+
page === "points" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StoryPoints, {
|
|
1360
|
+
toolbarTarget: setStoryToolbar,
|
|
1361
|
+
onOpenItem: openItem
|
|
1362
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1363
|
+
board.error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1364
|
+
className: tomato_board_module_css_default.error,
|
|
1365
|
+
role: "alert",
|
|
1366
|
+
children: board.error
|
|
1367
|
+
}),
|
|
1368
|
+
board.truncated && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
1369
|
+
className: tomato_board_module_css_default.notice,
|
|
1370
|
+
role: "status",
|
|
1371
|
+
children: [
|
|
1372
|
+
"事项数量已达配置上限,当前仅展示前 ",
|
|
1373
|
+
board.items.length,
|
|
1374
|
+
" 条。"
|
|
1375
|
+
]
|
|
1376
|
+
}),
|
|
1377
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1378
|
+
className: tomato_board_module_css_default.board,
|
|
1379
|
+
children: [statuses.map((status) => {
|
|
1380
|
+
const items = filteredItems.filter((item) => item.status === status);
|
|
1381
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1382
|
+
ref: (element) => {
|
|
1383
|
+
if (element) laneElements.current.set(status, element);
|
|
1384
|
+
else laneElements.current.delete(status);
|
|
1385
|
+
},
|
|
1386
|
+
className: `${tomato_board_module_css_default.lane} ${draggedLane === status ? tomato_board_module_css_default.laneDragging : ""} ${dropLane?.status === status ? dropLane.after ? tomato_board_module_css_default.laneDropAfter : tomato_board_module_css_default.laneDropBefore : ""}`,
|
|
1387
|
+
"aria-labelledby": `tomato-lane-${status}`,
|
|
1388
|
+
onDragOver: (event) => {
|
|
1389
|
+
if (!draggedLane || draggedLane === status) return;
|
|
1390
|
+
event.preventDefault();
|
|
1391
|
+
const bounds = event.currentTarget.getBoundingClientRect();
|
|
1392
|
+
setDropLane({
|
|
1393
|
+
status,
|
|
1394
|
+
after: event.clientX >= bounds.left + bounds.width / 2
|
|
1395
|
+
});
|
|
1396
|
+
},
|
|
1397
|
+
onDrop: (event) => {
|
|
1398
|
+
event.preventDefault();
|
|
1399
|
+
if (draggedLane && dropLane?.status === status) moveLane(draggedLane, status, dropLane.after);
|
|
1400
|
+
setDraggedLane(null);
|
|
1401
|
+
setDropLane(null);
|
|
1402
|
+
},
|
|
1403
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
1404
|
+
className: tomato_board_module_css_default.laneHeader,
|
|
1405
|
+
draggable: true,
|
|
1406
|
+
title: "拖拽调整泳道顺序",
|
|
1407
|
+
onDragStart: (event) => {
|
|
1408
|
+
event.dataTransfer.effectAllowed = "move";
|
|
1409
|
+
event.dataTransfer.setData("text/plain", status);
|
|
1410
|
+
const lane = event.currentTarget.parentElement;
|
|
1411
|
+
if (lane) {
|
|
1412
|
+
const bounds = lane.getBoundingClientRect();
|
|
1413
|
+
event.dataTransfer.setDragImage(lane, Math.min(Math.max(event.clientX - bounds.left, 0), bounds.width), Math.min(Math.max(event.clientY - bounds.top, 0), bounds.height));
|
|
486
1414
|
}
|
|
1415
|
+
setDraggedLane(status);
|
|
487
1416
|
},
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
1417
|
+
onDragEnd: () => {
|
|
1418
|
+
setDraggedLane(null);
|
|
1419
|
+
setDropLane(null);
|
|
1420
|
+
},
|
|
1421
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
1422
|
+
id: `tomato-lane-${status}`,
|
|
1423
|
+
children: status
|
|
1424
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: items.length })]
|
|
1425
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1426
|
+
className: tomato_board_module_css_default.cards,
|
|
1427
|
+
children: items.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
1428
|
+
className: `${tomato_board_module_css_default.card} ${mutedItems.has(item.itemKey) ? tomato_board_module_css_default.cardMuted : ""}`,
|
|
1429
|
+
tabIndex: 0,
|
|
1430
|
+
role: "button",
|
|
1431
|
+
onClick: () => openItem(item),
|
|
1432
|
+
onKeyDown: (event) => {
|
|
1433
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
1434
|
+
event.preventDefault();
|
|
1435
|
+
openItem(item);
|
|
1436
|
+
}
|
|
1437
|
+
},
|
|
1438
|
+
children: [
|
|
1439
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1440
|
+
className: tomato_board_module_css_default.cardTopline,
|
|
1441
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1442
|
+
className: tomato_board_module_css_default.key,
|
|
1443
|
+
children: item.itemKey
|
|
1444
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1445
|
+
className: tomato_board_module_css_default.cardButtons,
|
|
1446
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1447
|
+
className: tomato_board_module_css_default.muteButton,
|
|
1448
|
+
variant: "ghost",
|
|
1449
|
+
size: "sm",
|
|
1450
|
+
title: mutedItems.has(item.itemKey) ? "取消置灰" : "置灰标记",
|
|
1451
|
+
"aria-label": mutedItems.has(item.itemKey) ? `取消置灰 ${item.itemKey}` : `置灰 ${item.itemKey}`,
|
|
1452
|
+
"aria-pressed": mutedItems.has(item.itemKey),
|
|
1453
|
+
onClick: (event) => {
|
|
1454
|
+
event.stopPropagation();
|
|
1455
|
+
toggleMutedItem(item.itemKey);
|
|
1456
|
+
},
|
|
1457
|
+
onKeyDown: (event) => event.stopPropagation(),
|
|
1458
|
+
children: "●"
|
|
1459
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1460
|
+
className: tomato_board_module_css_default.tomatoLink,
|
|
1461
|
+
variant: "ghost",
|
|
1462
|
+
size: "sm",
|
|
1463
|
+
title: "在番茄中打开事项",
|
|
1464
|
+
"aria-label": `在番茄中打开 ${item.itemKey}`,
|
|
1465
|
+
onClick: (event) => {
|
|
1466
|
+
event.stopPropagation();
|
|
1467
|
+
window.open(item.tomatoUrl, "_blank", "noopener,noreferrer");
|
|
1468
|
+
},
|
|
1469
|
+
onKeyDown: (event) => event.stopPropagation(),
|
|
1470
|
+
children: "↗"
|
|
1471
|
+
})]
|
|
521
1472
|
})]
|
|
522
|
-
})
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
1473
|
+
}),
|
|
1474
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: item.title }),
|
|
1475
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1476
|
+
className: tomato_board_module_css_default.cardMeta,
|
|
1477
|
+
children: [
|
|
1478
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tag, {
|
|
1479
|
+
tone: typeTone(item.itemType),
|
|
1480
|
+
children: item.itemType
|
|
1481
|
+
}),
|
|
1482
|
+
(item.workspaceName || item.workspaceKey) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tag, {
|
|
1483
|
+
title: "空间",
|
|
1484
|
+
children: item.workspaceName && item.workspaceKey && item.workspaceName !== item.workspaceKey ? `${item.workspaceName} (${item.workspaceKey})` : item.workspaceKey || item.workspaceName
|
|
1485
|
+
}),
|
|
1486
|
+
item.priority && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tag, {
|
|
1487
|
+
title: "优先级",
|
|
1488
|
+
children: priorityLabel(item.priority)
|
|
1489
|
+
}),
|
|
1490
|
+
item.creator && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Tag, {
|
|
1491
|
+
title: "创建人",
|
|
1492
|
+
children: ["创建 ", item.creator]
|
|
1493
|
+
})
|
|
1494
|
+
]
|
|
1495
|
+
})
|
|
1496
|
+
]
|
|
1497
|
+
}, item.itemKey))
|
|
1498
|
+
})]
|
|
1499
|
+
}, status);
|
|
1500
|
+
}), !board.loading && !board.error && statuses.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1501
|
+
className: tomato_board_module_css_default.empty,
|
|
1502
|
+
children: "当前没有可显示的番茄事项"
|
|
1503
|
+
})]
|
|
1504
|
+
})
|
|
1505
|
+
] }),
|
|
542
1506
|
board.selectedItem ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CreateConversationDialog, {
|
|
543
1507
|
ctx,
|
|
544
1508
|
item: board.selectedItem
|
|
@@ -546,18 +1510,180 @@ window.__ModuleLoader__.load({
|
|
|
546
1510
|
]
|
|
547
1511
|
});
|
|
548
1512
|
}
|
|
1513
|
+
const PRIORITY_LABELS = {
|
|
1514
|
+
"69e65065-4b34-4109-bca9-0154e548554a": "P0",
|
|
1515
|
+
"8f7912a5-9176-4a79-a269-2269ac42b5a2": "P1",
|
|
1516
|
+
"ca8c3e43-3e7b-444d-8940-d0967d944921": "P2",
|
|
1517
|
+
"ec31e4c1-b55b-479d-be97-86d5f7bf38ef": "P2",
|
|
1518
|
+
"1a3e1092-7d70-42ee-ad38-0e8d953c4c23": "P3",
|
|
1519
|
+
"faae52da-28c8-46fc-96dd-db9cdb28b557": "P4"
|
|
1520
|
+
};
|
|
1521
|
+
const priorityLabel = (value) => PRIORITY_LABELS[value] ?? value;
|
|
1522
|
+
const TYPE_TONES = {
|
|
1523
|
+
Story: "#2f7d72",
|
|
1524
|
+
EnablerStory: "#2777a8",
|
|
1525
|
+
Task: "#7b61a8",
|
|
1526
|
+
Bug: "#c34f43",
|
|
1527
|
+
缺陷: "#c34f43",
|
|
1528
|
+
测试缺陷: "#d06438",
|
|
1529
|
+
Epic: "#9a6b24",
|
|
1530
|
+
Feature: "#3f68ad"
|
|
1531
|
+
};
|
|
1532
|
+
function typeTone(type) {
|
|
1533
|
+
if (TYPE_TONES[type]) return TYPE_TONES[type];
|
|
1534
|
+
const palette = [
|
|
1535
|
+
"#2f7d72",
|
|
1536
|
+
"#2777a8",
|
|
1537
|
+
"#7b61a8",
|
|
1538
|
+
"#c34f43",
|
|
1539
|
+
"#9a6b24",
|
|
1540
|
+
"#51753a",
|
|
1541
|
+
"#a14f78"
|
|
1542
|
+
];
|
|
1543
|
+
return palette[[...type].reduce((hash, char) => hash + char.charCodeAt(0), 0) % palette.length];
|
|
1544
|
+
}
|
|
549
1545
|
function FilterRow({ label, options, hidden, onToggle }) {
|
|
550
1546
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
551
1547
|
className: tomato_board_module_css_default.filterRow,
|
|
552
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
"
|
|
1548
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tag, {
|
|
1549
|
+
interactive: true,
|
|
1550
|
+
pressed: !hidden.has(option),
|
|
1551
|
+
tone: label === "类型" ? typeTone(option) : void 0,
|
|
556
1552
|
onClick: () => onToggle(option),
|
|
557
1553
|
children: option
|
|
558
1554
|
}, option)) })]
|
|
559
1555
|
});
|
|
560
1556
|
}
|
|
1557
|
+
const WORKSPACE_SELECT_ALL = "workspace:select-all";
|
|
1558
|
+
const WORKSPACE_SELECT_NONE = "workspace:select-none";
|
|
1559
|
+
/** Multi-select workspace dropdown composed on the shared Menu primitive. */
|
|
1560
|
+
function WorkspaceFilterRow({ options, hidden, onToggle, onSetAll }) {
|
|
1561
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
1562
|
+
const rootRef = (0, react.useRef)(null);
|
|
1563
|
+
const visibleValues = options.filter((option) => !hidden.has(option.value)).map((option) => option.value);
|
|
1564
|
+
const summary = options.length === 0 ? "暂无空间" : hidden.size === 0 ? `全部空间 · ${options.length}` : visibleValues.length === 0 ? "未选择空间" : `已选空间 ${visibleValues.length} / ${options.length}`;
|
|
1565
|
+
(0, react.useEffect)(() => {
|
|
1566
|
+
if (!open) return;
|
|
1567
|
+
const onKey = (event) => {
|
|
1568
|
+
if (event.key === "Escape") {
|
|
1569
|
+
event.stopPropagation();
|
|
1570
|
+
setOpen(false);
|
|
1571
|
+
}
|
|
1572
|
+
};
|
|
1573
|
+
const root = rootRef.current;
|
|
1574
|
+
root?.addEventListener("keydown", onKey, true);
|
|
1575
|
+
return () => root?.removeEventListener("keydown", onKey, true);
|
|
1576
|
+
}, [open]);
|
|
1577
|
+
const items = options.map((option) => ({
|
|
1578
|
+
id: option.value,
|
|
1579
|
+
label: option.label
|
|
1580
|
+
}));
|
|
1581
|
+
const footer = [{
|
|
1582
|
+
id: WORKSPACE_SELECT_ALL,
|
|
1583
|
+
label: "全部显示"
|
|
1584
|
+
}, {
|
|
1585
|
+
id: WORKSPACE_SELECT_NONE,
|
|
1586
|
+
label: "全部隐藏"
|
|
1587
|
+
}];
|
|
1588
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1589
|
+
className: tomato_board_module_css_default.filterRow,
|
|
1590
|
+
ref: rootRef,
|
|
1591
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "空间" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1592
|
+
className: tomato_board_module_css_default.workspaceSelect,
|
|
1593
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
1594
|
+
open,
|
|
1595
|
+
items,
|
|
1596
|
+
footer,
|
|
1597
|
+
selectedIds: visibleValues,
|
|
1598
|
+
onSelect: (id) => {
|
|
1599
|
+
if (id === WORKSPACE_SELECT_ALL) onSetAll(true);
|
|
1600
|
+
else if (id === WORKSPACE_SELECT_NONE) onSetAll(false);
|
|
1601
|
+
else onToggle(id);
|
|
1602
|
+
},
|
|
1603
|
+
onClose: () => {
|
|
1604
|
+
setOpen(false);
|
|
1605
|
+
},
|
|
1606
|
+
anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1607
|
+
type: "button",
|
|
1608
|
+
className: tomato_board_module_css_default.workspaceTrigger,
|
|
1609
|
+
"aria-expanded": open,
|
|
1610
|
+
title: summary,
|
|
1611
|
+
onClick: () => {
|
|
1612
|
+
setOpen(!open);
|
|
1613
|
+
},
|
|
1614
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: summary }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("i", {
|
|
1615
|
+
className: tomato_board_module_css_default.workspaceChevron,
|
|
1616
|
+
"aria-hidden": true,
|
|
1617
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {})
|
|
1618
|
+
})]
|
|
1619
|
+
})
|
|
1620
|
+
})
|
|
1621
|
+
})]
|
|
1622
|
+
});
|
|
1623
|
+
}
|
|
1624
|
+
function AssigneePicker({ users, value, onChange }) {
|
|
1625
|
+
const rootRef = (0, react.useRef)(null);
|
|
1626
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
1627
|
+
const [query, setQuery] = (0, react.useState)("");
|
|
1628
|
+
const options = (0, react.useMemo)(() => [{
|
|
1629
|
+
username: "currentUser()",
|
|
1630
|
+
name: "我负责的"
|
|
1631
|
+
}, ...users.filter((user) => user.username !== "currentUser()")], [users]);
|
|
1632
|
+
const selected = options.find((option) => option.username === value) ?? options[0];
|
|
1633
|
+
const needle = query.trim().toLowerCase();
|
|
1634
|
+
const filtered = needle ? options.filter((option) => `${option.name} ${option.username}`.toLowerCase().includes(needle)) : options;
|
|
1635
|
+
(0, react.useEffect)(() => {
|
|
1636
|
+
if (!open) return;
|
|
1637
|
+
const close = (event) => {
|
|
1638
|
+
if (event.target instanceof Node && !rootRef.current?.contains(event.target)) setOpen(false);
|
|
1639
|
+
};
|
|
1640
|
+
document.addEventListener("pointerdown", close, true);
|
|
1641
|
+
return () => document.removeEventListener("pointerdown", close, true);
|
|
1642
|
+
}, [open]);
|
|
1643
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1644
|
+
className: tomato_board_module_css_default.assigneeFilter,
|
|
1645
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "负责人" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1646
|
+
ref: rootRef,
|
|
1647
|
+
className: tomato_board_module_css_default.assigneePicker,
|
|
1648
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1649
|
+
variant: "outline",
|
|
1650
|
+
size: "sm",
|
|
1651
|
+
className: tomato_board_module_css_default.assigneeTrigger,
|
|
1652
|
+
"aria-haspopup": "listbox",
|
|
1653
|
+
"aria-expanded": open,
|
|
1654
|
+
onClick: () => {
|
|
1655
|
+
setOpen((current) => !current);
|
|
1656
|
+
setQuery("");
|
|
1657
|
+
},
|
|
1658
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: selected?.name ?? value }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {})]
|
|
1659
|
+
}), open ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1660
|
+
className: tomato_board_module_css_default.assigneeDropdown,
|
|
1661
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1662
|
+
autoFocus: true,
|
|
1663
|
+
type: "search",
|
|
1664
|
+
value: query,
|
|
1665
|
+
onChange: (event) => setQuery(event.target.value),
|
|
1666
|
+
placeholder: "搜索昵称或用户名…",
|
|
1667
|
+
"aria-label": "搜索负责人"
|
|
1668
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1669
|
+
role: "listbox",
|
|
1670
|
+
"aria-label": "负责人",
|
|
1671
|
+
children: [filtered.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1672
|
+
type: "button",
|
|
1673
|
+
role: "option",
|
|
1674
|
+
"aria-selected": option.username === value,
|
|
1675
|
+
onClick: () => {
|
|
1676
|
+
onChange(option.username);
|
|
1677
|
+
setOpen(false);
|
|
1678
|
+
setQuery("");
|
|
1679
|
+
},
|
|
1680
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: option.name }), option.name !== option.username && option.username !== "currentUser()" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: option.username }) : null]
|
|
1681
|
+
}, option.username)), filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: "没有匹配的负责人" }) : null]
|
|
1682
|
+
})]
|
|
1683
|
+
}) : null]
|
|
1684
|
+
})]
|
|
1685
|
+
});
|
|
1686
|
+
}
|
|
561
1687
|
function TomatoConversationShortcut({ ctx, sessionId, useSessions }) {
|
|
562
1688
|
const itemKey = useSessions((state) => {
|
|
563
1689
|
const summary = state.byId[sessionId];
|
|
@@ -719,6 +1845,14 @@ window.__ModuleLoader__.load({
|
|
|
719
1845
|
"workspaces"
|
|
720
1846
|
];
|
|
721
1847
|
function apply(ctx) {
|
|
1848
|
+
const openWorkbench = () => {
|
|
1849
|
+
if (disposeWorkbench) return;
|
|
1850
|
+
emit({ open: true });
|
|
1851
|
+
disposeWorkbench = ctx.slots.register({
|
|
1852
|
+
name: "conversation",
|
|
1853
|
+
priority: -100
|
|
1854
|
+
}, () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TomatoBoardPanel, { ctx }));
|
|
1855
|
+
};
|
|
722
1856
|
ctx.slots.inject("conversation.session.header.actions", () => ctx.slots.register({
|
|
723
1857
|
name: "conversation.session.header.actions",
|
|
724
1858
|
id: "tomato-shortcut",
|
|
@@ -732,15 +1866,13 @@ window.__ModuleLoader__.load({
|
|
|
732
1866
|
id: "tomato-board"
|
|
733
1867
|
}, (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TomatoBoardAction, {
|
|
734
1868
|
...props,
|
|
735
|
-
openWorkbench
|
|
736
|
-
if (disposeWorkbench) return;
|
|
737
|
-
emit({ open: true });
|
|
738
|
-
disposeWorkbench = ctx.slots.register({
|
|
739
|
-
name: "conversation",
|
|
740
|
-
priority: -100
|
|
741
|
-
}, () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TomatoBoardPanel, { ctx }));
|
|
742
|
-
}
|
|
1869
|
+
openWorkbench
|
|
743
1870
|
})));
|
|
1871
|
+
ctx.slots.inject("conversation.session.header.actions", () => ctx.slots.register({
|
|
1872
|
+
name: "conversation.session.header.actions",
|
|
1873
|
+
id: "tomato-board-topbar",
|
|
1874
|
+
order: 11
|
|
1875
|
+
}, () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TomatoBoardTopbarAction, { openWorkbench })));
|
|
744
1876
|
}
|
|
745
1877
|
//#endregion
|
|
746
1878
|
exports.apply = apply;
|