fix(client): gate every full access picker

This commit is contained in:
ZiyaZhang
2026-07-30 05:48:21 -07:00
parent 2ed4d982e7
commit 6d416b06c5
36 changed files with 624 additions and 195 deletions

View File

@@ -41,73 +41,3 @@
flex: 0 0 auto;
color: var(--dsw-alias-label-caption);
}
.confirmation {
width: min(440px, 100%);
max-height: calc(100vh - 48px);
overflow: hidden;
}
.confirmationContent {
min-height: 0;
overflow-y: auto;
overscroll-behavior: contain;
}
@supports (height: 100dvh) {
.confirmation {
max-height: calc(100dvh - 48px);
}
}
.warning {
display: flex;
align-items: flex-start;
gap: 10px;
color: var(--dsw-alias-label-secondary);
font-size: 14px;
line-height: 22px;
}
.warning p {
margin: 0;
}
.warningIcon {
flex: none;
margin-top: 2px;
color: var(--dsw-alias-state-error-primary);
}
.acknowledgement {
display: flex;
align-items: flex-start;
gap: 10px;
margin-top: 20px;
color: var(--dsw-alias-label-primary);
font-size: 14px;
line-height: 22px;
cursor: pointer;
}
.acknowledgement input {
flex: none;
width: 16px;
height: 16px;
margin: 3px 0 0;
accent-color: var(--dsw-alias-button-primary-fill);
cursor: pointer;
}
.acknowledgement input:focus-visible {
outline: 2px solid var(--dsw-alias-border-l4);
outline-offset: 2px;
}
.modalAction {
min-width: 72px;
}
.confirmAction {
min-width: 136px;
}

View File

@@ -1,6 +1,6 @@
import { useState } from 'react'
import { useEffect, useState } from 'react'
import type { PermissionSelect as PermissionSelectValue } from '@deepseek-ai/dsh-permission/client'
import { Button, IconWarningOutline16, Menu, Modal } from '@deepseek-ai/dsh-client-ui-primitives'
import { Menu, RiskConfirmation } from '@deepseek-ai/dsh-client-ui-primitives'
import type { MenuEntry } from '@deepseek-ai/dsh-client-ui-primitives'
import css from './PermissionSelect.module.css'
@@ -9,8 +9,9 @@ const FULL_ACCESS = 'danger-full-access'
/**
* Display transform: kebab-case machine names render as title-case labels
* (`workspace-write` → `Workspace Write`); non-kebab host-configured names
* pass through. Twin of the /permission popup's (client ui-permission) — the
* two permission surfaces must show the same text.
* pass through. Full access intentionally overrides the machine-name
* transform so both permission surfaces use the product label `Full access`;
* the warning body remains locale-aware.
*/
function displayName(name: string): string {
if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(name)) return name
@@ -34,6 +35,13 @@ export function PermissionSelect({ value, locked, command, t }: PermissionSelect
const [confirmation, setConfirmation] = useState<string | null>(null)
const [acknowledged, setAcknowledged] = useState(false)
useEffect(() => {
if (!locked && value !== undefined) return
setOpen(false)
setAcknowledged(false)
setConfirmation(null)
}, [locked, value])
if (value === undefined) return null
const currentValue = pick ?? value.currentValue
@@ -68,7 +76,7 @@ export function PermissionSelect({ value, locked, command, t }: PermissionSelect
}
const confirmFullAccess = (): void => {
if (!acknowledged || confirmation === null) return
if (locked || !acknowledged || confirmation === null) return
const id = confirmation
closeConfirmation()
submit(id)
@@ -99,42 +107,19 @@ export function PermissionSelect({ value, locked, command, t }: PermissionSelect
</button>
}
/>
<Modal
<RiskConfirmation
open={confirmation !== null}
onClose={closeConfirmation}
title={t('confirm.title')}
className={css.confirmation ?? ''}
contentClassName={css.confirmationContent ?? ''}
footer={(
<>
<Button variant="outline" className={css.modalAction} onClick={closeConfirmation}>
{t('confirm.cancel')}
</Button>
<Button
variant="primary"
className={css.confirmAction}
disabled={!acknowledged}
onClick={confirmFullAccess}
>
{t('confirm.enable')}
</Button>
</>
)}
>
<div className={css.warning}>
<IconWarningOutline16 size={18} className={css.warningIcon} />
<p>{t('confirm.description')}</p>
</div>
<label className={css.acknowledgement}>
<input
type="checkbox"
checked={acknowledged}
autoFocus
onChange={(event) => { setAcknowledged(event.currentTarget.checked) }}
/>
<span>{t('confirm.acknowledge')}</span>
</label>
</Modal>
description={t('confirm.description')}
acknowledgeLabel={t('confirm.acknowledge')}
cancelLabel={t('confirm.cancel')}
confirmLabel={t('confirm.enable')}
acknowledged={acknowledged}
disabled={locked}
onAcknowledgedChange={setAcknowledged}
onCancel={closeConfirmation}
onConfirm={confirmFullAccess}
/>
</>
)
}