Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/nine-waves-punch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tokens-studio/figma-plugin": patch
---

Fix read-only access UI controls for Studio sync provider
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,11 @@ export default function Footer() {
size="small"
tooltipSide="top"
tooltip={
t('pullFrom', {
provider: transformProviderName(storageType.provider),
}) as string
editProhibited
? t('readOnly')
: (t('pullFrom', {
provider: transformProviderName(storageType.provider),
}) as string)
}
/>
</DirtyStateBadgeWrapper>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import debounce from 'lodash.debounce';
import { Button, EmptyState } from '@tokens-studio/ui';
import { styled } from '@stitches/react';
import { useTranslation } from 'react-i18next';
import { activeThemeSelector, themesListSelector } from '@/selectors';
import { activeThemeSelector, editProhibitedSelector, themesListSelector } from '@/selectors';
import Modal from '../Modal';
import { Dispatch } from '@/app/store';
import Stack from '../Stack';
Expand Down Expand Up @@ -44,6 +44,7 @@ export const ManageThemesModal: React.FC<React.PropsWithChildren<React.PropsWith
const dispatch = useDispatch<Dispatch>();
const themes = useSelector(themesListSelector);
const activeTheme = useSelector(activeThemeSelector);
const editProhibited = useSelector(editProhibitedSelector);
const { confirm } = useConfirm();
const [themeEditorOpen, setThemeEditorOpen] = useState<boolean | string>(false);
const [themeListScrollPosition, setThemeListScrollPosition] = useState<number>(0);
Expand Down Expand Up @@ -202,6 +203,7 @@ export const ManageThemesModal: React.FC<React.PropsWithChildren<React.PropsWith
variant="secondary"
icon={<IconPlus />}
onClick={handleToggleOpenThemeEditor}
disabled={editProhibited}
>
{t('newTheme')}
</Button>
Expand All @@ -215,6 +217,7 @@ export const ManageThemesModal: React.FC<React.PropsWithChildren<React.PropsWith
variant="danger"
type="submit"
onClick={handleDeleteTheme}
disabled={editProhibited}
>
{t('delete')}
</Button>
Expand All @@ -233,6 +236,7 @@ export const ManageThemesModal: React.FC<React.PropsWithChildren<React.PropsWith
variant="primary"
type="submit"
form="form-create-or-edit-theme"
disabled={editProhibited}
>
{t('saveTheme')}
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { ThemeObject } from '@/types';
import IconDiveInto from '@/icons/dive-into.svg';
import { TokenSetStatus } from '@/constants/TokenSetStatus';
import { Dispatch } from '@/app/store';
import { activeThemeSelector } from '@/selectors';
import { activeThemeSelector, editProhibitedSelector } from '@/selectors';

type Props = {
theme: ThemeObject
Expand Down Expand Up @@ -43,6 +43,7 @@ export const SingleThemeEntry: React.FC<React.PropsWithChildren<React.PropsWithC
theme, isActive, groupName, onOpen,
}) => {
const activeTheme = useSelector(activeThemeSelector);
const editProhibited = useSelector(editProhibitedSelector);
const dispatch = useDispatch<Dispatch>();

const tokenSetCount = useMemo(() => (
Expand Down Expand Up @@ -123,6 +124,7 @@ export const SingleThemeEntry: React.FC<React.PropsWithChildren<React.PropsWithC
onClick={handleOpenClick}
size="small"
variant="invisible"
disabled={editProhibited}
/>

</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export function ThemeListGroupHeader({
size="small"
variant="invisible"
tooltip="Rename group"
disabled={editProhibited}
/>
</>
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ export function TokenSetListItemContent({ item }: Parameters<TreeRenderFunction>
item={item}
onCheck={handleCheckedChange}
canEdit={!editProhibited}
canDuplicate={!tokenSetMetadata[item.path]?.isDynamic}
canDuplicate={!editProhibited && !tokenSetMetadata[item.path]?.isDynamic}
canReorder={!editProhibited}
canDelete={!editProhibited || Object.keys(item.tokenSets).length > 1}
canDelete={!editProhibited && Object.keys(item.tokenSets).length > 1}
onRename={item.onRename}
onDelete={item.onDelete}
onDuplicate={item.onDuplicate}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"feedback": "Feedback",
"pullFrom": "Pull from {{provider}}",
"pushTo": "Push to {{provider}}",
"goTo": "Go to {{provider}}"
"goTo": "Go to {{provider}}",
"readOnly": "Read only"
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"feedback": "comentario",
"pullFrom": "Extraer de {{provider}}",
"pushTo": "Empuje a {{provider}}",
"goTo": "Ir a __MARCADOR__"
"goTo": "Ir a __MARCADOR__",
"readOnly": "Solo lectura"
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"feedback": "retour",
"pullFrom": "Tirer de {{provider}}",
"pushTo": "Appuyez sur {{provider}}",
"goTo": "Aller à {{provider}}"
"goTo": "Aller à {{provider}}",
"readOnly": "Lecture seule"
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"feedback": "प्रतिक्रिया",
"pullFrom": "{{provider}} से खींचें",
"pushTo": "{{provider}} पर पुश करें",
"goTo": "__प्लेसहोल्डर__ पर जाएँ"
"goTo": "__प्लेसहोल्डर__ पर जाएँ",
"readOnly": "केवल पढ़ने के लिए"
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"feedback": "feedback",
"pullFrom": "Trek uit {{provider}}",
"pushTo": "Duwen naar {{provider}}",
"goTo": "Ga naar {{provider}}"
"goTo": "Ga naar {{provider}}",
"readOnly": "Alleen-lezen"
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"feedback": "反馈",
"pullFrom": "从 {{provider}} 中提取",
"pushTo": "推至 {{provider}}",
"goTo": "跳转到{{provider}}"
"goTo": "跳转到{{provider}}",
"readOnly": "只读"
}
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,21 @@ export class TokensStudioTokenStorage extends RemoteTokenStorage<TokensStudioSav
}
}

public async canWrite(): Promise<boolean> {
// For Tokens Studio, we don't have a direct API to check write permissions
// We return true optimistically and handle permission errors when they occur
// This will be used to set editProhibited state appropriately
try {
await this.ensureClient();
// If we can initialize the client successfully, we assume write access
// If the user has read-only access, write operations will fail with permission errors
return true;
} catch (error) {
console.error('Failed to check write permissions:', error);
return false;
}
}

public async read(): Promise<RemoteTokenStorageFile[] | RemoteTokenstorageErrorMessage> {
let tokens: AnyTokenSet | null | undefined = {};
let themes: ThemeObjectsList = [];
Expand Down