b62db917de
Client UI for agent comment suggestions. - IComment gains suggestedText / suggestionAppliedAt / suggestionAppliedById. - comment-list-item shows a "было → стало" block (old selection struck/red, new suggestedText green) for a top-level comment with a suggestion, plus an Apply button — gated by canShowApply(comment, canEdit): edit permission AND a suggestion AND not applied AND not resolved AND top-level. Once applied, an "Applied" badge replaces the button. - canEdit comes from page.permissions.canEdit (real edit permission, NOT the looser canComment) and is threaded through CommentListItem and nested ChildComments; fail-closed when undefined. - useApplySuggestionMutation posts to /comments/apply-suggestion; on success it writes the applied + server auto-resolve fields into the react-query cache (UI flips to Applied + resolved without a refetch); on 409 it shows a specific message with the server's currentText, else a generic error. - i18n keys added in en-US + ru-RU. Tests (comment-list-item.test.tsx + canShowApply unit suite): Apply visibility across canEdit/applied/resolved/reply, click dispatches the mutation, diff rendering. 34 passed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
99 lines
2.6 KiB
CSS
99 lines
2.6 KiB
CSS
.focused-thread {
|
|
border: 2px solid #8d7249;
|
|
}
|
|
|
|
.textSelection {
|
|
/* Breathing room below the comment header (author + timestamp) so the
|
|
quote does not stick to the timestamp when it is the first block. */
|
|
margin-top: 8px;
|
|
/* Align the quote's left bar with the comment body text left edge
|
|
(the comment editor insets its text by 6px). */
|
|
margin-left: 6px;
|
|
border-left: 2px solid var(--mantine-color-gray-6);
|
|
padding: 6px;
|
|
background: var(--mantine-color-gray-light);
|
|
cursor: pointer;
|
|
overflow-wrap: break-word;
|
|
word-wrap: break-word;
|
|
word-break: break-word;
|
|
-ms-word-break: break-word;
|
|
max-width: 100%;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
/* Suggested-edit (#315) "было → стало" diff block. */
|
|
.suggestionBlock {
|
|
margin-top: 8px;
|
|
margin-left: 6px;
|
|
padding: 6px;
|
|
border-radius: var(--mantine-radius-sm);
|
|
border: 1px solid var(--mantine-color-default-border);
|
|
overflow-wrap: break-word;
|
|
word-break: break-word;
|
|
max-width: 100%;
|
|
box-sizing: border-box;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
}
|
|
|
|
.suggestionOld {
|
|
text-decoration: line-through;
|
|
color: var(--mantine-color-red-7);
|
|
background: var(--mantine-color-red-light);
|
|
border-radius: 2px;
|
|
padding: 1px 3px;
|
|
}
|
|
|
|
.suggestionNew {
|
|
color: var(--mantine-color-green-9);
|
|
background: var(--mantine-color-green-light);
|
|
border-radius: 2px;
|
|
padding: 1px 3px;
|
|
margin-top: 4px;
|
|
}
|
|
|
|
.commentEditor {
|
|
|
|
&[data-editable][data-surface="muted"] .ProseMirror:not(.focused) {
|
|
border-radius: var(--mantine-radius-sm);
|
|
box-shadow: 0 0 0 1px light-dark(var(--mantine-color-gray-5), var(--mantine-color-dark-4));
|
|
}
|
|
|
|
.focused {
|
|
border-radius: var(--mantine-radius-sm);
|
|
box-shadow: 0 0 0 2px var(--mantine-color-blue-3);
|
|
}
|
|
|
|
/* Denser comments: override the global 16px ProseMirror body size with 14px
|
|
and tighten the rhythm vs. the comment header. Scoped to the comment
|
|
editor only - the page editor is unaffected. */
|
|
.ProseMirror :global(.ProseMirror){
|
|
border-radius: var(--mantine-radius-sm);
|
|
max-width: 100%;
|
|
white-space: pre-wrap;
|
|
word-break: break-word;
|
|
padding-left: 6px;
|
|
padding-right: 6px;
|
|
font-size: var(--mantine-font-size-sm);
|
|
line-height: 1.4;
|
|
margin-top: 4px;
|
|
margin-bottom: 2px;
|
|
}
|
|
|
|
&[data-editable] .ProseMirror :global(.ProseMirror){
|
|
max-height: 50vh;
|
|
overflow: hidden auto;
|
|
}
|
|
|
|
.ProseMirror p {
|
|
margin-block-start: 0;
|
|
margin-block-end: 0;
|
|
}
|
|
|
|
.actions {
|
|
|
|
}
|
|
}
|
|
|