github-issue-tower-defence-management 1.151.6 → 1.151.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/bin/adapter/entry-points/console/ui-dist/assets/index-BjFRJoM1.js +83 -0
  3. package/bin/adapter/entry-points/console/ui-dist/assets/index-CGqYXHZV.css +2 -0
  4. package/bin/adapter/entry-points/console/ui-dist/index.html +2 -2
  5. package/package.json +1 -1
  6. package/src/adapter/entry-points/console/ui/e2e/consoleScenario.spec.ts +23 -0
  7. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleCommentComposer.stories.tsx +0 -1
  8. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleCommentComposer.test.tsx +6 -15
  9. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleCommentComposer.tsx +1 -33
  10. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleItemDetail.tsx +4 -1
  11. package/src/adapter/entry-points/console/ui/src/features/console/logic/postedComments.test.ts +44 -0
  12. package/src/adapter/entry-points/console/ui/src/features/console/logic/postedComments.ts +17 -0
  13. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.test.tsx +77 -0
  14. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.tsx +14 -3
  15. package/src/adapter/entry-points/console/ui-dist/assets/index-BjFRJoM1.js +83 -0
  16. package/src/adapter/entry-points/console/ui-dist/assets/index-CGqYXHZV.css +2 -0
  17. package/src/adapter/entry-points/console/ui-dist/index.html +2 -2
  18. package/bin/adapter/entry-points/console/ui-dist/assets/index-ChJztBsb.js +0 -83
  19. package/bin/adapter/entry-points/console/ui-dist/assets/index-wDluFyBz.css +0 -2
  20. package/src/adapter/entry-points/console/ui-dist/assets/index-ChJztBsb.js +0 -83
  21. package/src/adapter/entry-points/console/ui-dist/assets/index-wDluFyBz.css +0 -2
@@ -0,0 +1,2 @@
1
+ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-font-weight:initial;--tw-outline-style:solid;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-medium:500;--font-weight-semibold:600;--radius-md:.375rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-input:#e5e5e5;--color-ring:#0a0a0a;--color-background:#fff;--color-foreground:#0a0a0a;--color-primary:#171717;--color-primary-foreground:#fafafa;--color-secondary:#f5f5f5;--color-secondary-foreground:#171717;--color-accent:#f5f5f5;--color-accent-foreground:#171717}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.block{display:block}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.grow{flex-grow:1}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:calc(var(--spacing) * 2)}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-input{border-color:var(--color-input)}.border-transparent{border-color:#0000}.bg-background{background-color:var(--color-background)}.bg-primary{background-color:var(--color-primary)}.bg-secondary{background-color:var(--color-secondary)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-2{padding-block:calc(var(--spacing) * 2)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.whitespace-nowrap{white-space:nowrap}.text-foreground{color:var(--color-foreground)}.text-primary-foreground{color:var(--color-primary-foreground)}.text-secondary-foreground{color:var(--color-secondary-foreground)}.lowercase{text-transform:lowercase}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media (hover:hover){.hover\:bg-accent:hover{background-color:var(--color-accent)}.hover\:bg-primary\/90:hover{background-color:#171717e6}@supports (color:color-mix(in lab, red, red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab, var(--color-primary) 90%, transparent)}}.hover\:bg-secondary\/80:hover{background-color:#f5f5f5cc}@supports (color:color-mix(in lab, red, red)){.hover\:bg-secondary\/80:hover{background-color:color-mix(in oklab, var(--color-secondary) 80%, transparent)}}.hover\:text-accent-foreground:hover{color:var(--color-accent-foreground)}}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color:var(--color-ring)}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:opacity-50:disabled{opacity:.5}}html{font-size:clamp(15px,2.1vw,26px)}body{color:#e6edf3;background-color:#0d1117;margin:0;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif}.console-app{flex-direction:column;width:100%;min-height:100dvh;display:flex}.console-tabbar{-webkit-overflow-scrolling:touch;background:#161b22;border-bottom:2px solid #30363d;flex-wrap:nowrap;align-items:stretch;gap:0;min-height:42px;padding:0 8px;display:flex;overflow-x:auto}.console-tab{color:#8b949e;white-space:nowrap;cursor:pointer;background:0 0;border:none;border-bottom:2px solid #0000;align-items:center;gap:6px;margin-bottom:-2px;padding:10px 14px;font-size:.8125rem;font-weight:500;line-height:1.2;text-decoration:none;display:inline-flex}.console-tab:hover{color:#e6edf3}.console-tab[data-active=true]{color:#e6edf3;border-bottom-color:#2f81f7;font-weight:700}.console-tab-badge{text-align:center;color:#e6edf3;background:#484f58;border-radius:20px;min-width:20px;padding:1px 7px;font-size:.6875rem;font-weight:700;line-height:1.5}.console-tab-badge[data-zero=true]{color:#8b949e;background:#30363d}.console-tab-pjname{color:#8b949e;align-self:center;margin-left:auto;padding:0 8px;font-size:.7188rem}.console-tab-geninfo{color:#8b949e;align-self:center;padding:0 4px;font-size:.6875rem}.console-list{margin:0;padding:12px 18px 18px;list-style:none}.console-list-group{list-style:none}.console-item-row .console-item-icon{flex:none;margin-top:3px}.console-group-header{background:#0b0f14;border-bottom:1px solid #21262d;justify-content:space-between;align-items:center;padding:6px 12px;display:flex}.console-storytag{align-items:center;gap:8px;font-size:.8125rem;font-weight:700;display:inline-flex}.console-story-dot{border-radius:999px;width:10px;height:10px;display:inline-block}.console-group-count{color:#8b949e;font-size:.75rem}.console-item-row{color:#e6edf3;text-align:left;cursor:pointer;background:#161b22;border:1px solid #30363d;border-radius:8px;align-items:flex-start;gap:14px;width:100%;margin-bottom:10px;padding:12px 16px;display:flex}.console-item-row:hover{background:#1a2029;border-color:#484f58}.console-item-row[data-active=true]{background:#1a2029;border-color:#4493f8}.console-item-meta{flex:1;min-width:0}.console-item-title{font-size:.9063rem;font-weight:600;display:block}.console-item-sub{color:#8b949e;margin-top:3px;font-size:.7813rem;display:block}.console-item-pill{color:#8b949e;border:1px solid #30363d;border-radius:20px;margin-right:6px;padding:1px 8px;font-size:.6875rem;display:inline-block}.console-item-createdat{color:#8b949e;cursor:help}.console-item-fields{color:#adbac7;flex-wrap:wrap;gap:4px 10px;margin-top:4px;font-size:.7188rem;display:flex}.console-item-field{word-break:break-all;align-items:baseline;gap:4px;min-width:0;display:inline-flex}.console-item-field-label{color:#6e7681;text-transform:uppercase;letter-spacing:.03em;font-size:.625rem}.console-list-message{color:#8b949e;padding:16px;font-size:.875rem}.console-list-empty{text-align:center;color:#8b949e;padding:40px;font-size:.875rem}.console-list-error,.console-comment-error,.console-files-error,.console-commits-error,.console-detail-fetch-error,.console-detail-body-error{color:#f85149}.console-detail{flex-direction:column;flex:1 0 auto;gap:12px;padding:16px 16px 0;display:flex}.console-detail-topline{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.console-detail-title{align-items:center;gap:8px;margin:0;font-size:1.25rem;display:flex}.console-detail-title-text{flex:1}.console-detail-number{color:#8b949e;font-weight:400}.console-detail-closed-label{color:#a371f7;font-size:.8125rem}.console-detail-subbar{align-items:center;gap:12px;font-size:.8125rem;display:flex}.console-detail-link{color:#4493f8}.console-detail-repo{color:#8b949e;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.console-copy-url-button{color:#c9d1d9;border:1px solid #30363d;border-radius:6px;height:24px;padding:0 8px;font-size:.75rem}.console-copy-url-button:hover{color:#e6edf3;background-color:#21262d}.console-detail-pill,.console-label-chip,.console-detail-status-chip{border:1px solid #30363d;border-radius:999px;padding:2px 8px;font-size:.75rem;display:inline-block}.console-detail-pr-status{flex-wrap:wrap;align-items:center;gap:6px;display:inline-flex}.console-detail-ci-missing{opacity:.85;font-weight:400}.console-detail-mergeable-chip{font-weight:600}.console-detail-mergeable-chip-unknown{opacity:.7;font-weight:400}.console-detail-labels{flex-wrap:wrap;gap:6px;display:flex}.console-detail-createdat{color:#8b949e;font-size:.75rem}.console-panel{border:1px solid #30363d;border-radius:8px;overflow:hidden}.console-panel-header{background:#161b22;justify-content:space-between;align-items:center;display:flex}.console-panel-toggle{color:#e6edf3;text-align:left;cursor:pointer;background:0 0;border:none;flex:1;align-items:center;gap:8px;padding:6px 12px;font-size:.875rem;font-weight:600;display:flex}.console-panel-toggle:hover{background:#1a2029}.console-panel-action{padding:6px 12px}.console-panel-body{padding:12px}.console-markdown{word-break:break-word;font-size:.875rem;line-height:1.5}.console-markdown ul{margin:.5em 0;padding-left:1.5em;list-style:outside}.console-markdown ol{margin:.5em 0;padding-left:1.5em;list-style:decimal}.console-markdown li{margin:.25em 0}.console-markdown table{border-collapse:collapse;margin:.5em 0}.console-markdown th,.console-markdown td{border:1px solid #30363d;padding:4px 8px}.console-markdown th{background:#161b22}.console-markdown h1,.console-markdown h2,.console-markdown h3,.console-markdown h4,.console-markdown h5,.console-markdown h6{margin:1em 0 .5em;font-weight:700;line-height:1.25}.console-markdown h1{font-size:1.6em}.console-markdown h2{font-size:1.4em}.console-markdown h3{font-size:1.2em}.console-markdown h4{font-size:1.05em}.console-markdown h5{font-size:.95em}.console-markdown h6{color:#8b949e;font-size:.9em}.console-markdown pre{background:#161b22;border:1px solid #30363d;border-radius:6px;margin:.5em 0;padding:12px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.8125rem;line-height:1.45;overflow-x:auto}.console-markdown code{background:#6e768166;border-radius:4px;padding:.15em .4em;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.9em}.console-markdown pre code{font-size:inherit;background:0 0;border-radius:0;padding:0}.console-markdown-code-block{flex-direction:column;margin:.5em 0;display:flex}.console-markdown-code-block pre{margin:0}.console-markdown-code-copy-host{justify-content:flex-end;margin-bottom:4px;display:flex}.console-copy-code-button{color:#c9d1d9;background-color:#161b22;border:1px solid #30363d;border-radius:6px;height:24px;padding:0 8px;font-size:.75rem}.console-copy-code-button:hover{color:#e6edf3;background-color:#21262d}.console-markdown blockquote{color:#8b949e;border-left:3px solid #30363d;margin:.5em 0;padding:0 1em}.console-markdown a{color:#4493f8;text-decoration:none}.console-markdown a:hover{text-decoration:underline}.console-markdown-reference-host{display:inline}.console-markdown-reference{vertical-align:baseline;align-items:center;gap:.25em;display:inline-flex}.console-markdown-reference .console-item-icon{flex-shrink:0}.console-markdown-reference-title{text-decoration:none}.console-markdown-reference:hover .console-markdown-reference-title{text-decoration:underline}.console-markdown hr{border:none;border-top:1px solid #30363d;margin:1em 0}.console-mermaid-error{color:#f85149;font-size:.8125rem}.console-comment{background:#161b22;border:1px solid #30363d;border-radius:8px;margin-bottom:10px;padding:12px 16px}.console-comment-header{color:#8b949e;gap:8px;font-size:.75rem;display:flex}.console-comment-show-all{color:#e6edf3;cursor:pointer;background:#21262d;border:1px solid #30363d;border-radius:6px;margin-bottom:10px;padding:6px 12px;font-size:.75rem;font-weight:600}.console-comment-show-all:hover{background-color:#262c34;border-color:#484f58}.console-comment-author{color:#e6edf3;font-weight:600}.console-files,.console-commits{margin:0;padding:0;list-style:none}.console-commit{align-items:center;gap:8px;padding:4px 0;font-size:.8125rem;display:flex}.console-file{flex-direction:column;font-size:.8125rem;display:flex}.console-file-tree,.console-file-tree-children{margin:0;padding:0;list-style:none}.console-file-tree-dir{flex-direction:column;display:flex}.console-file-tree-dir-name{color:#8b949e;align-items:center;gap:6px;padding:4px 0;font-weight:600;display:flex}.console-file-tree-dir-icon{flex:none}.console-file-badge{text-align:center;border:1px solid;border-radius:4px;width:18px;font-size:.6875rem}.console-file-path,.console-commit-message{flex:1;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.console-file-add,.console-pr-add{color:#3fb950}.console-file-del,.console-pr-del{color:#f85149}.console-commit-sha{color:#8b949e;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.console-detail-dock{z-index:100;background:#161b22;border-top:2px solid #30363d;margin-top:auto;position:sticky;bottom:0}.console-detail-dock-composer{max-height:50vh;padding:8px 16px 0;overflow-y:auto}.console-actionbar{padding:10px 16px;padding-bottom:calc(10px + env(safe-area-inset-bottom));background:#161b22}.console-operation-bar{flex-direction:column;gap:8px;width:100%;display:flex}.console-op-group{flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:8px;display:flex}.console-op-group-review{gap:10px}.console-op-group-stories{max-height:33vh;overflow-y:auto}.console-op-button{color:#e6edf3;white-space:nowrap;cursor:pointer;background:#21262d;border:1px solid #30363d;border-radius:6px;padding:9px 16px;font-size:.8125rem;font-weight:600}.console-op-button:hover{border-color:#484f58}.console-op-button:disabled{opacity:.4;cursor:not-allowed}.console-op-requirement{text-align:right;color:#8b949e;width:100%;margin:0;font-size:.75rem}.console-op-button-approve{color:#fff;background:#238636;border-color:#2ea043}.console-op-button-reject{color:#ffd166;background:#7d5000;border-color:#a06800}.console-op-button-wrong{color:#f85149;background:#3a1518;border-color:#f85149}.console-op-button-unneeded{color:#aab0b8;background:#2a2d31;border-color:#6e7681}.console-op-button-snooze{color:#79c0ff;background:#1c2b4a;border-color:#4493f8}.console-pr-section{border:1px solid #30363d;border-radius:8px;flex-direction:column;gap:10px;padding:12px;display:flex}.console-pr-statbar{color:#8b949e;gap:12px;font-size:.75rem;display:flex}.console-detail-screen{flex-direction:column;flex:1 0 auto;display:flex}.console-panel-open-link{color:#4493f8;font-size:.8125rem;font-weight:400}.console-composer{margin-top:4px}.console-composer-toggle{color:#8b949e;cursor:pointer;background:0 0;border:none;margin-left:auto;padding:2px 0;font-size:.7813rem;display:block}.console-composer-toggle:hover{color:#e6edf3}.console-composer-posted{flex-direction:column;gap:8px;margin-top:8px;display:flex}.console-composer-form{margin-top:8px}.console-composer-input{box-sizing:border-box;color:#e6edf3;width:100%;font:inherit;resize:vertical;background:#21262d;border:1px solid #30363d;border-radius:6px;padding:8px;font-size:.875rem}.console-composer-attach{align-items:center;gap:8px;padding:0 10px;display:flex}.console-composer-file-input{display:none}.console-composer-attach-button{color:#c9d1d9;cursor:pointer;background:#21262d;border:1px solid #30363d;border-radius:4px;padding:4px 8px;font-size:.75rem}.console-composer-attach-button:disabled{opacity:.6;cursor:default}.console-composer-row{justify-content:flex-end;align-items:center;gap:8px;margin-top:6px;display:flex}.console-composer-submit{color:#fff;cursor:pointer;background:#238636;border:1px solid #2ea043;border-radius:6px;padding:7px 16px;font-size:.8125rem;font-weight:600}.console-composer-submit:disabled{opacity:.6;cursor:default}.console-composer-status{color:#8b949e;font-size:.75rem}.console-composer-error{color:#f85149}.console-undo-toast{z-index:9998;white-space:nowrap;border-radius:10px;align-items:center;gap:12px;max-width:92vw;padding:12px 18px;font-size:.8438rem;display:flex;position:fixed;top:12px;left:50%;transform:translate(-50%);box-shadow:0 4px 20px #0009}.console-undo-toast-green{color:#3fb950;background:#0d3320;border:1px solid #2ea043}.console-undo-toast-amber{color:#ffd166;background:#3a2800;border:1px solid #a06800}.console-undo-toast-red{color:#f85149;background:#3a1518;border:1px solid #da3633}.console-undo-toast-gray{color:#aab0b8;background:#2a2d31;border:1px solid #6e7681}.console-undo-toast-blue{color:#79c0ff;background:#0d1f40;border:1px solid #4493f8}.console-undo-toast-error{color:#f85149;background:#3a1518;border:1px solid #f85149}.console-undo-toast-message{text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.console-undo-toast-undo{cursor:pointer;color:inherit;background:#ffffff1f;border:none;border-radius:6px;flex:none;padding:4px 12px;font-size:.8125rem;font-weight:700}.console-undo-toast-undo:hover{background:#ffffff38}.console-undo-toast-countdown{opacity:.7;flex:none;font-size:.6875rem}.console-undo-toast-bar{opacity:.5;background:currentColor;border-radius:0 0 10px 10px;height:3px;transition:width .1s linear;position:absolute;bottom:0;left:0}.console-file-row{width:100%;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;align-items:center;gap:8px;padding:4px 0;font-size:.8125rem;display:flex}.console-file-row:hover{background:#1a2029}.console-file-caret{color:#8b949e;flex:none;width:1em}.console-file-diff{border-collapse:collapse;width:100%;margin:4px 0 8px;font:.8125rem/1.6 ui-monospace,SFMono-Regular,Menlo,monospace}.console-file-diff td{white-space:pre-wrap;word-break:break-word;vertical-align:top;padding:0 10px}.console-diff-ln{text-align:right;color:#6e7681;-webkit-user-select:none;user-select:none;white-space:nowrap;border-right:1px solid #30363d;width:1%;padding:0 8px}.console-file-diff td.console-diff-ln{white-space:nowrap;word-break:normal;overflow-wrap:normal}.console-diff-add td{background:#2ea04326}.console-diff-add .console-diff-code{color:#aff5b4}.console-diff-del td{background:#f8514926}.console-diff-del .console-diff-code{color:#ffdcd7}.console-diff-hunk td{color:#79c0ff;background:#161b22}.console-diff-ctx .console-diff-code{color:#c9d1d9}.console-file-diff-empty{color:#8b949e;padding:8px 14px;font-size:.75rem}.console-file-diff-image{padding:8px 14px}.console-file-diff-image-content{object-fit:contain;object-position:left top;border:1px solid #30363d;border-radius:4px;max-width:100%;max-height:420px}.console-diff-comment-cell{text-align:center;-webkit-user-select:none;user-select:none;width:1%;padding:0 2px}.console-diff-comment-button{color:#6e7681;cursor:pointer;opacity:.6;background:0 0;border:1px solid #30363d;border-radius:4px;width:18px;height:18px;padding:0;font-size:.875rem;line-height:16px}.console-diff-row:hover .console-diff-comment-button,.console-diff-comment-button:focus-visible,.console-diff-comment-button[aria-expanded=true]{opacity:1;color:#fff;background:#1f6feb;border-color:#2f81f7}.console-diff-composer-row td{background:#0d1117;padding:6px 10px}.console-diff-composer{background:#161b22;border:1px solid #30363d;border-radius:6px;flex-direction:column;gap:6px;padding:8px;display:flex}.console-diff-composer-anchor{color:#8b949e;font-size:.6875rem}.console-diff-composer-input{resize:vertical;color:#c9d1d9;width:100%;font:inherit;background:#0d1117;border:1px solid #30363d;border-radius:6px;padding:6px 8px}.console-diff-composer-controls{align-items:center;gap:8px;display:flex}.console-diff-composer-submit{color:#fff;cursor:pointer;background:#238636;border:1px solid #238636;border-radius:6px;padding:4px 12px}.console-diff-composer-submit:disabled{opacity:.6;cursor:default}.console-diff-composer-cancel{color:#c9d1d9;cursor:pointer;background:0 0;border:1px solid #30363d;border-radius:6px;padding:4px 12px}.console-diff-composer-status{color:#8b949e;font-size:.75rem}.console-diff-composer-error{color:#ff7b72}.console-diff-composer-posted{color:#3fb950;margin:0;font-size:.75rem}.console-pr-header{flex-wrap:wrap;align-items:center;gap:10px;padding-top:4px;display:flex}.console-pr-section-title{color:#e6edf3;font-size:.9375rem;font-weight:600}.console-pr-section-state{color:#8b949e;border:1px solid #6e7681;border-radius:999px;padding:1px 8px;font-size:.6875rem}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>TDPM Console</title>
7
- <script type="module" crossorigin src="/assets/index-ChJztBsb.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-wDluFyBz.css">
7
+ <script type="module" crossorigin src="/assets/index-BjFRJoM1.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-CGqYXHZV.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "github-issue-tower-defence-management",
3
- "version": "1.151.6",
3
+ "version": "1.151.7",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "scripts": {
@@ -312,4 +312,27 @@ test('opens the comment input with the item detail, keeps it on screen while the
312
312
 
313
313
  await composerToggle.click();
314
314
  await expect(page.locator('.console-composer-input')).toBeInViewport();
315
+
316
+ const dockHeightBeforePosting = (
317
+ await page.locator('.console-detail-dock').boundingBox()
318
+ )?.height;
319
+ await page
320
+ .locator('.console-composer-input')
321
+ .fill('The dock must not grow with every comment.');
322
+ await page.locator('.console-composer-submit').click();
323
+
324
+ const postedComment = page.locator('.console-comment', {
325
+ hasText: 'The dock must not grow with every comment.',
326
+ });
327
+ await expect(postedComment).toHaveCount(1);
328
+ await expect(
329
+ page.locator('.console-detail-dock .console-comment'),
330
+ ).toHaveCount(0);
331
+ await expect(page.locator('.console-comment-list')).toContainText(
332
+ 'The dock must not grow with every comment.',
333
+ );
334
+ const dockHeightAfterPosting = (
335
+ await page.locator('.console-detail-dock').boundingBox()
336
+ )?.height;
337
+ expect(dockHeightAfterPosting).toBe(dockHeightBeforePosting);
315
338
  });
@@ -12,7 +12,6 @@ const meta: Meta<typeof ConsoleCommentComposer> = {
12
12
  title: 'Console/ConsoleCommentComposer',
13
13
  component: ConsoleCommentComposer,
14
14
  args: {
15
- now: Date.parse('2026-06-19T12:00:00.000Z'),
16
15
  onSubmit: acceptComment,
17
16
  },
18
17
  };
@@ -9,14 +9,11 @@ jest.mock('../../lib/mermaidLoader', () => ({
9
9
  renderMermaidToSvg: jest.fn(async () => '<svg></svg>'),
10
10
  }));
11
11
 
12
- const now = Date.parse('2026-06-19T12:00:00.000Z');
13
-
14
12
  describe('ConsoleCommentComposer', () => {
15
13
  it('shows the form when it starts open', () => {
16
14
  const { getByPlaceholderText } = render(
17
15
  <ConsoleCommentComposer
18
16
  initiallyOpen
19
- now={now}
20
17
  onSubmit={async (body) => ({
21
18
  author: 'HiromiShikata',
22
19
  body,
@@ -31,7 +28,6 @@ describe('ConsoleCommentComposer', () => {
31
28
  const { queryByPlaceholderText, getByText } = render(
32
29
  <ConsoleCommentComposer
33
30
  initiallyOpen={false}
34
- now={now}
35
31
  onSubmit={async (body) => ({
36
32
  author: 'HiromiShikata',
37
33
  body,
@@ -47,7 +43,6 @@ describe('ConsoleCommentComposer', () => {
47
43
  const { getByText, getByPlaceholderText, queryByPlaceholderText } = render(
48
44
  <ConsoleCommentComposer
49
45
  initiallyOpen={false}
50
- now={now}
51
46
  onSubmit={async (body) => ({
52
47
  author: 'HiromiShikata',
53
48
  body,
@@ -61,7 +56,7 @@ describe('ConsoleCommentComposer', () => {
61
56
  expect(queryByPlaceholderText('Leave a comment…')).toBeNull();
62
57
  });
63
58
 
64
- it('submits the comment and shows the posted comment', async () => {
59
+ it('submits the comment, empties the draft and renders no comment of its own', async () => {
65
60
  const onSubmit = jest.fn(
66
61
  async (body: string): Promise<ConsoleComment> => ({
67
62
  author: 'HiromiShikata',
@@ -69,24 +64,25 @@ describe('ConsoleCommentComposer', () => {
69
64
  createdAt: '2026-06-19T11:58:00.000Z',
70
65
  }),
71
66
  );
72
- const { getByPlaceholderText, getByText } = render(
73
- <ConsoleCommentComposer initiallyOpen now={now} onSubmit={onSubmit} />,
67
+ const { container, getByPlaceholderText, getByText, queryByText } = render(
68
+ <ConsoleCommentComposer initiallyOpen onSubmit={onSubmit} />,
74
69
  );
75
70
  fireEvent.change(getByPlaceholderText('Leave a comment…'), {
76
71
  target: { value: 'Looks good after the rebase.' },
77
72
  });
78
73
  fireEvent.click(getByText('Comment'));
79
74
  await waitFor(() => {
80
- expect(getByText('Looks good after the rebase.')).toBeInTheDocument();
75
+ expect(getByPlaceholderText('Leave a comment…')).toHaveValue('');
81
76
  });
82
77
  expect(onSubmit).toHaveBeenCalledWith('Looks good after the rebase.');
78
+ expect(queryByText('Looks good after the rebase.')).toBeNull();
79
+ expect(container.querySelectorAll('.console-comment').length).toBe(0);
83
80
  });
84
81
 
85
82
  it('shows a failure message when the submission rejects', async () => {
86
83
  const { getByPlaceholderText, getByText, findByRole } = render(
87
84
  <ConsoleCommentComposer
88
85
  initiallyOpen
89
- now={now}
90
86
  onSubmit={async () => {
91
87
  throw new Error('HTTP 500');
92
88
  }}
@@ -104,7 +100,6 @@ describe('ConsoleCommentComposer', () => {
104
100
  const { queryByText } = render(
105
101
  <ConsoleCommentComposer
106
102
  initiallyOpen
107
- now={now}
108
103
  onSubmit={async (body) => ({
109
104
  author: 'HiromiShikata',
110
105
  body,
@@ -122,7 +117,6 @@ describe('ConsoleCommentComposer', () => {
122
117
  const { getByPlaceholderText, getByLabelText } = render(
123
118
  <ConsoleCommentComposer
124
119
  initiallyOpen
125
- now={now}
126
120
  onSubmit={async (body) => ({
127
121
  author: 'HiromiShikata',
128
122
  body,
@@ -154,7 +148,6 @@ describe('ConsoleCommentComposer', () => {
154
148
  const { getByPlaceholderText } = render(
155
149
  <ConsoleCommentComposer
156
150
  initiallyOpen
157
- now={now}
158
151
  onSubmit={async (body) => ({
159
152
  author: 'HiromiShikata',
160
153
  body,
@@ -183,7 +176,6 @@ describe('ConsoleCommentComposer', () => {
183
176
  const { getByPlaceholderText } = render(
184
177
  <ConsoleCommentComposer
185
178
  initiallyOpen
186
- now={now}
187
179
  onSubmit={async (body) => ({
188
180
  author: 'HiromiShikata',
189
181
  body,
@@ -209,7 +201,6 @@ describe('ConsoleCommentComposer', () => {
209
201
  const { getByLabelText, findByRole } = render(
210
202
  <ConsoleCommentComposer
211
203
  initiallyOpen
212
- now={now}
213
204
  onSubmit={async (body) => ({
214
205
  author: 'HiromiShikata',
215
206
  body,
@@ -1,14 +1,8 @@
1
1
  import { useRef, useState } from 'react';
2
- import {
3
- formatFullTimestamp,
4
- formatRelativeTime,
5
- } from '../../logic/relativeTime';
6
2
  import type { ConsoleComment } from '../../logic/types';
7
- import { ConsoleMarkdownContent } from '../content/ConsoleMarkdownContent';
8
3
 
9
4
  export type ConsoleCommentComposerProps = {
10
5
  initiallyOpen: boolean;
11
- now: number;
12
6
  onSubmit: (body: string) => Promise<ConsoleComment>;
13
7
  onUploadFile?: (file: File) => Promise<string>;
14
8
  };
@@ -38,7 +32,6 @@ export const appendAttachmentMarkdown = (
38
32
 
39
33
  export const ConsoleCommentComposer = ({
40
34
  initiallyOpen,
41
- now,
42
35
  onSubmit,
43
36
  onUploadFile,
44
37
  }: ConsoleCommentComposerProps) => {
@@ -48,7 +41,6 @@ export const ConsoleCommentComposer = ({
48
41
  const [uploadStatus, setUploadStatus] = useState<UploadStatus>({
49
42
  kind: 'idle',
50
43
  });
51
- const [posted, setPosted] = useState<ConsoleComment[]>([]);
52
44
  const fileInputRef = useRef<HTMLInputElement | null>(null);
53
45
 
54
46
  const submit = async (): Promise<void> => {
@@ -58,8 +50,7 @@ export const ConsoleCommentComposer = ({
58
50
  }
59
51
  setStatus({ kind: 'posting' });
60
52
  try {
61
- const comment = await onSubmit(body);
62
- setPosted((previous) => [...previous, comment]);
53
+ await onSubmit(body);
63
54
  setDraft('');
64
55
  setStatus({ kind: 'idle' });
65
56
  } catch (error) {
@@ -101,29 +92,6 @@ export const ConsoleCommentComposer = ({
101
92
  >
102
93
  {open ? '✕ Close' : '💬 Add a comment'}
103
94
  </button>
104
- {posted.length > 0 && (
105
- <div className="console-composer-posted">
106
- {posted.map((comment) => (
107
- <article
108
- key={`${comment.author}:${comment.createdAt}:${comment.body}`}
109
- className="console-comment"
110
- >
111
- <header
112
- className="console-comment-header"
113
- title={formatFullTimestamp(comment.createdAt)}
114
- >
115
- <span className="console-comment-author">
116
- {comment.author === '' ? 'you' : comment.author}
117
- </span>
118
- <span className="console-comment-time">
119
- {formatRelativeTime(comment.createdAt, now)}
120
- </span>
121
- </header>
122
- <ConsoleMarkdownContent body={comment.body} />
123
- </article>
124
- ))}
125
- </div>
126
- )}
127
95
  {open && (
128
96
  <div className="console-composer-form">
129
97
  <textarea
@@ -51,6 +51,7 @@ export type ConsoleItemDetailProps = {
51
51
  bodyIsLoading: boolean;
52
52
  bodyError: string | null;
53
53
  comments: ConsoleComment[];
54
+ hasPostedComment?: boolean;
54
55
  commentsAreLoading: boolean;
55
56
  commentsError: string | null;
56
57
  files: ConsoleChangedFile[];
@@ -82,6 +83,7 @@ export const ConsoleItemDetail = ({
82
83
  bodyIsLoading,
83
84
  bodyError,
84
85
  comments,
86
+ hasPostedComment = false,
85
87
  commentsAreLoading,
86
88
  commentsError,
87
89
  files,
@@ -275,9 +277,10 @@ export const ConsoleItemDetail = ({
275
277
  )}
276
278
 
277
279
  <ConsolePanel
280
+ key={hasPostedComment ? 'comments-with-posted' : 'comments'}
278
281
  title="Comments"
279
282
  count={commentsCount}
280
- defaultCollapsed={item.isPr}
283
+ defaultCollapsed={item.isPr && !hasPostedComment}
281
284
  >
282
285
  <ConsoleCommentList
283
286
  comments={comments}
@@ -0,0 +1,44 @@
1
+ import { mergePostedComments } from './postedComments';
2
+ import type { ConsoleComment } from './types';
3
+
4
+ const loadedComment: ConsoleComment = {
5
+ author: 'HiromiShikata',
6
+ body: 'Loaded from GitHub.',
7
+ createdAt: '2026-06-19T10:00:00.000Z',
8
+ };
9
+
10
+ const postedComment: ConsoleComment = {
11
+ author: 'HiromiShikata',
12
+ body: 'Posted from the console.',
13
+ createdAt: '2026-06-19T11:58:00.000Z',
14
+ };
15
+
16
+ describe('mergePostedComments', () => {
17
+ it('appends a posted comment after the loaded comments', () => {
18
+ expect(mergePostedComments([loadedComment], [postedComment])).toEqual([
19
+ loadedComment,
20
+ postedComment,
21
+ ]);
22
+ });
23
+
24
+ it('drops a posted comment that the reloaded comments already carry', () => {
25
+ expect(
26
+ mergePostedComments([loadedComment, postedComment], [postedComment]),
27
+ ).toEqual([loadedComment, postedComment]);
28
+ });
29
+
30
+ it('keeps a posted comment whose body differs from an otherwise identical loaded comment', () => {
31
+ const editedComment: ConsoleComment = {
32
+ ...postedComment,
33
+ body: 'Posted from the console, then edited.',
34
+ };
35
+ expect(mergePostedComments([postedComment], [editedComment])).toEqual([
36
+ postedComment,
37
+ editedComment,
38
+ ]);
39
+ });
40
+
41
+ it('returns the loaded comments unchanged when nothing was posted', () => {
42
+ expect(mergePostedComments([loadedComment], [])).toEqual([loadedComment]);
43
+ });
44
+ });
@@ -0,0 +1,17 @@
1
+ import type { ConsoleComment } from './types';
2
+
3
+ const commentIdentity = (comment: ConsoleComment): string =>
4
+ JSON.stringify([comment.author, comment.createdAt, comment.body]);
5
+
6
+ export const mergePostedComments = (
7
+ loadedComments: ConsoleComment[],
8
+ postedComments: ConsoleComment[],
9
+ ): ConsoleComment[] => {
10
+ const loadedIdentities = new Set(loadedComments.map(commentIdentity));
11
+ return [
12
+ ...loadedComments,
13
+ ...postedComments.filter(
14
+ (comment) => !loadedIdentities.has(commentIdentity(comment)),
15
+ ),
16
+ ];
17
+ };
@@ -140,6 +140,83 @@ describe('ConsoleItemDetailContainer', () => {
140
140
  expect(getByPlaceholderText('Leave a comment…')).toBeInTheDocument();
141
141
  });
142
142
 
143
+ it('puts a posted comment in the scrolling comment list and leaves the sticky dock holding only the input', async () => {
144
+ const operations = buildOperations();
145
+ operations.addComment = jest.fn(async (_item, body) => ({
146
+ author: 'HiromiShikata',
147
+ body,
148
+ createdAt: '2026-06-19T11:58:00.000Z',
149
+ }));
150
+ const { container, getByPlaceholderText, getByText } = render(
151
+ <ConsoleItemDetailContainer
152
+ tab="unread"
153
+ item={issueItem}
154
+ caches={buildCaches()}
155
+ operations={operations}
156
+ statusOptions={consoleStatusOptionsFixture}
157
+ storyOptions={consoleStoryOptionsFixture}
158
+ storyColors={consoleStoryColorsFixture}
159
+ storyName="TDPM Console port"
160
+ overlayStatus={null}
161
+ now={Date.parse('2026-06-19T12:00:00.000Z')}
162
+ onQueueAction={jest.fn()}
163
+ />,
164
+ );
165
+
166
+ fireEvent.change(getByPlaceholderText('Leave a comment…'), {
167
+ target: { value: 'The dock must not grow with every comment.' },
168
+ });
169
+ fireEvent.click(getByText('Comment'));
170
+
171
+ await waitFor(() => {
172
+ expect(
173
+ container.querySelector('.console-comment-list')?.textContent,
174
+ ).toContain('The dock must not grow with every comment.');
175
+ });
176
+ expect(
177
+ container.querySelector('.console-detail-dock')?.textContent,
178
+ ).not.toContain('The dock must not grow with every comment.');
179
+ expect(
180
+ container.querySelectorAll('.console-detail-dock .console-comment')
181
+ .length,
182
+ ).toBe(0);
183
+ });
184
+
185
+ it('opens the comments panel of a pull request item so the posted comment is on screen', async () => {
186
+ const operations = buildOperations();
187
+ operations.addComment = jest.fn(async (_item, body) => ({
188
+ author: 'HiromiShikata',
189
+ body,
190
+ createdAt: '2026-06-19T11:58:00.000Z',
191
+ }));
192
+ const { container, getByPlaceholderText, getByText } = render(
193
+ <ConsoleItemDetailContainer
194
+ tab="prs"
195
+ item={prItem}
196
+ caches={buildCaches()}
197
+ operations={operations}
198
+ statusOptions={consoleStatusOptionsFixture}
199
+ storyOptions={consoleStoryOptionsFixture}
200
+ storyColors={consoleStoryColorsFixture}
201
+ storyName="TDPM Console port"
202
+ overlayStatus={null}
203
+ now={Date.parse('2026-06-19T12:00:00.000Z')}
204
+ onQueueAction={jest.fn()}
205
+ />,
206
+ );
207
+
208
+ fireEvent.change(getByPlaceholderText('Leave a comment…'), {
209
+ target: { value: 'Posted from the pull request item.' },
210
+ });
211
+ fireEvent.click(getByText('Comment'));
212
+
213
+ await waitFor(() => {
214
+ expect(
215
+ container.querySelector('.console-comment-list')?.textContent,
216
+ ).toContain('Posted from the pull request item.');
217
+ });
218
+ });
219
+
143
220
  it('shows Approve for an issue item from the generated related open pull request urls before the related pull requests are fetched', () => {
144
221
  const operations = buildOperations();
145
222
  const onQueueAction = jest.fn();
@@ -13,8 +13,10 @@ import type {
13
13
  ConsoleOperationHandlers,
14
14
  ConsolePendingReviewComment,
15
15
  } from '../logic/operations';
16
+ import { mergePostedComments } from '../logic/postedComments';
16
17
  import type {
17
18
  ConsoleColor,
19
+ ConsoleComment,
18
20
  ConsoleFieldOption,
19
21
  ConsoleListItem,
20
22
  ConsoleOverlayStatus,
@@ -87,6 +89,15 @@ export const ConsoleItemDetailContainer = ({
87
89
  },
88
90
  [],
89
91
  );
92
+ const [postedComments, setPostedComments] = useState<ConsoleComment[]>([]);
93
+ const addComment = useCallback(
94
+ async (body: string): Promise<ConsoleComment> => {
95
+ const comment = await operations.addComment(item, body);
96
+ setPostedComments((previous) => [...previous, comment]);
97
+ return comment;
98
+ },
99
+ [item, operations],
100
+ );
90
101
 
91
102
  const handlers: ConsoleOperationHandlers = {
92
103
  onReview: (action) => {
@@ -159,7 +170,8 @@ export const ConsoleItemDetailContainer = ({
159
170
  body={detail.body}
160
171
  bodyIsLoading={detail.bodyIsLoading}
161
172
  bodyError={detail.bodyError}
162
- comments={detail.comments}
173
+ comments={mergePostedComments(detail.comments, postedComments)}
174
+ hasPostedComment={postedComments.length > 0}
163
175
  commentsAreLoading={detail.commentsAreLoading}
164
176
  commentsError={detail.commentsError}
165
177
  files={detail.files}
@@ -179,8 +191,7 @@ export const ConsoleItemDetailContainer = ({
179
191
  commentComposer={
180
192
  <ConsoleCommentComposer
181
193
  initiallyOpen
182
- now={now}
183
- onSubmit={(body) => operations.addComment(item, body)}
194
+ onSubmit={addComment}
184
195
  onUploadFile={(file) => operations.uploadAttachment(item, file)}
185
196
  />
186
197
  }