Merge branch 'fix/schema-draft-author-display-and-withdraw-gate' into 'main'
fix(schema-draft): author display + gate Отозвать только maker'у See merge request 2-6/2-6-4/terravault/ordinis!158
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useAuth } from 'react-oidc-context'
|
||||
import axios from 'axios'
|
||||
import { Badge, Button, Drawer, LoadingBlock, QueryErrorState, TextArea, toast } from '@/ui'
|
||||
import {
|
||||
@@ -241,6 +242,7 @@ export function SchemaDraftDrawer({
|
||||
inline т.к. Drawer sheet flow-based. */}
|
||||
<DraftActions
|
||||
status={draft.status}
|
||||
makerId={draft.makerId}
|
||||
onSubmitReview={onSubmitReview}
|
||||
onDecide={onDecide}
|
||||
onPublish={onPublish}
|
||||
@@ -319,10 +321,33 @@ function StatusBadge({ status }: { status: SchemaDraftStatus }) {
|
||||
|
||||
function DraftMeta({ draft }: { draft: SchemaDraft }) {
|
||||
const { t } = useTranslation()
|
||||
const auth = useAuth()
|
||||
// Resolve author display: если maker = current user, показываем имя текущего
|
||||
// юзера ("Я • <username>"). Иначе — short UUID (первые 8 chars) с full
|
||||
// tooltip. Полное UUID показывать бессмысленно — это Keycloak sub claim,
|
||||
// нечитаемый для оператора.
|
||||
//
|
||||
// TODO Phase 1d: backend endpoint /admin/users/{sub}/display чтобы для
|
||||
// не-current-user тоже показывать username. Пока — best-effort: current
|
||||
// user resolved через JWT profile claim, другие — UUID prefix.
|
||||
const currentSub = auth.user?.profile?.sub
|
||||
const isMe = currentSub && currentSub === draft.makerId
|
||||
const myDisplay =
|
||||
auth.user?.profile?.preferred_username ||
|
||||
auth.user?.profile?.name ||
|
||||
auth.user?.profile?.email
|
||||
const authorDisplay = isMe
|
||||
? `Я${myDisplay ? ` • ${myDisplay}` : ''}`
|
||||
: draft.makerId.substring(0, 8)
|
||||
return (
|
||||
<dl className="grid grid-cols-[120px_1fr] gap-y-1 gap-x-3 text-cell">
|
||||
<Row label={t('workflow.schemaDraft.maker', { defaultValue: 'Автор' })}>
|
||||
<span className="font-mono">{draft.makerId}</span>
|
||||
<span
|
||||
className={isMe ? 'text-ink' : 'font-mono text-mute'}
|
||||
title={draft.makerId}
|
||||
>
|
||||
{authorDisplay}
|
||||
</span>
|
||||
</Row>
|
||||
<Row label={t('workflow.schemaDraft.from', { defaultValue: 'От версии' })}>
|
||||
v{draft.branchedFromVersion}
|
||||
@@ -396,6 +421,7 @@ function DraftActions({
|
||||
onEdit,
|
||||
disabled,
|
||||
hasCurrentVersion,
|
||||
makerId,
|
||||
}: {
|
||||
status: SchemaDraftStatus
|
||||
onSubmitReview: () => void
|
||||
@@ -405,13 +431,21 @@ function DraftActions({
|
||||
onEdit?: () => void
|
||||
disabled: boolean
|
||||
hasCurrentVersion: boolean
|
||||
/** UUID maker'а draft'а — для gate "Отозвать" (только сам автор может). */
|
||||
makerId: string
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
const auth = useAuth()
|
||||
// Phase 1c RBAC stub: для review_pending reviewer-only действия скрываем
|
||||
// если нет approve role. Publish — отдельная role. Backend всё равно
|
||||
// защищает. Phase 1d intergrate'нет Keycloak realm_access.roles.
|
||||
const canReview = useCanReviewSchema()
|
||||
const canPublish = useCanPublishSchema()
|
||||
// "Отозвать" — maker-only action (withdraw own draft). Backend всё равно
|
||||
// 403'нет non-maker call, но скрытие на UI level убирает confusion:
|
||||
// reviewer видел кнопку которая всегда fail'ила. Сравниваем JWT sub с makerId.
|
||||
const currentSub = auth.user?.profile?.sub
|
||||
const isMaker = Boolean(currentSub) && currentSub === makerId
|
||||
|
||||
if (!isActiveSchemaDraft(status)) {
|
||||
return (
|
||||
@@ -501,6 +535,7 @@ function DraftActions({
|
||||
{t('workflow.schemaDraft.actions.publish', { defaultValue: 'Опубликовать' })}
|
||||
</Button>
|
||||
)}
|
||||
{isMaker && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
@@ -511,6 +546,7 @@ function DraftActions({
|
||||
>
|
||||
{t('workflow.schemaDraft.actions.withdraw', { defaultValue: 'Отозвать' })}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user