Skip to content
Merged
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
13 changes: 13 additions & 0 deletions .changeset/11865-access-panels-shared-select.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
'@object-ui/app-shell': patch
---

Studio's package record sharing overview picks each object's internal and external sharing model with the shared `Select`. That is the control Studio's object Settings tab already uses for the same two sharing models (objectui#11865, the overview's part of that card). A permission set's advanced facets keep their native selects for now: the shared `Select` adds bytes to the console's first load there, and the first-load budget has no room for them yet.

The overview's two dials were browser-native selects, so they looked and behaved differently from Studio's other dropdowns. They now use the shared Radix `Select`: the same trigger, dropdown and keyboard behaviour.

What they write is unchanged. Each option leaves the row with the same working value as before, so Save sends the same object draft, and "not set" still drops the key. Re-picking the current option changes nothing. The native selects had no label, and the new triggers have none either. A read-only package still shows each value as text, with no picker, as before.

One display change: a stored sharing model that neither dial offers now shows as itself. The native select showed "not set" instead, which is not what the object says.

**Clause-②: no.** No published face moves: `PackageOwdOverviewPanel` takes the same props, the package entry exports the same names, and no i18n key is added. What moves is the overview's own markup, described above.
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,30 @@
import '@testing-library/jest-dom/vitest';
import * as React from 'react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { act, cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
import { act, cleanup, fireEvent, render, screen, waitFor, within } from '@testing-library/react';
import { MetadataClient } from '@object-ui/data-objectstack';

vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn() } }));

import { t } from '../metadata-admin/i18n';
import { PackageOwdOverviewPanel } from './PackageOwdOverviewPanel';

const en = (key: string) => t(key, 'en-US');

/** What each dial lists an OWD value under; the dials are the shared Select (objectui#11865). */
const OWD_LABEL: Record<string, string> = {
'': en('engine.studio.settings.sharingUnset'),
private: en('engine.studio.settings.sharingPrivate'),
public_read: en('engine.studio.settings.sharingPublicRead'),
};

/** Pick a dial's option by its label, through the trigger, as a user does. */
async function pickOwd(testId: string, label: string): Promise<void> {
fireEvent.keyDown(screen.getByTestId(testId), { key: 'ArrowDown' });
const listbox = await screen.findByRole('listbox');
fireEvent.click(within(listbox).getByRole('option', { name: label }));
}

const PKG = 'com.acme.app';

interface Row {
Expand Down Expand Up @@ -162,19 +179,19 @@ describe('PackageOwdOverviewPanel — an unsaved object is not asked for /layers
const row = screen.getByTestId(`owd-row-${FRESH.name}`);
expect(row).toHaveTextContent('Fresh');
expect(row).toHaveTextContent('Unpublished draft');
expect((screen.getByTestId(`owd-internal-${FRESH.name}`) as HTMLSelectElement).value).toBe('private');
expect((screen.getByTestId(`owd-external-${FRESH.name}`) as HTMLSelectElement).value).toBe('private');
expect(screen.getByTestId(`owd-internal-${FRESH.name}`).textContent).toBe(OWD_LABEL.private);
expect(screen.getByTestId(`owd-external-${FRESH.name}`).textContent).toBe(OWD_LABEL.private);
// CONTROL: the published object's row is its baseline.
expect((screen.getByTestId(`owd-internal-${ACCOUNT.name}`) as HTMLSelectElement).value).toBe('public_read');
expect(screen.getByTestId(`owd-internal-${ACCOUNT.name}`).textContent).toBe(OWD_LABEL.public_read);
});

it('SAVE: the unsaved object is saved over its draft with no /layers; the published one is re-read once', async () => {
await openPanel();
const before = { fresh: layersAsked(FRESH.name), account: layersAsked(ACCOUNT.name) };

fireEvent.change(screen.getByTestId(`owd-internal-${FRESH.name}`), { target: { value: 'public_read' } });
fireEvent.change(screen.getByTestId(`owd-external-${FRESH.name}`), { target: { value: 'public_read' } });
fireEvent.change(screen.getByTestId(`owd-internal-${ACCOUNT.name}`), { target: { value: 'private' } });
await pickOwd(`owd-internal-${FRESH.name}`, OWD_LABEL.public_read);
await pickOwd(`owd-external-${FRESH.name}`, OWD_LABEL.public_read);
await pickOwd(`owd-internal-${ACCOUNT.name}`, OWD_LABEL.private);
fireEvent.click(screen.getByTestId('owd-save'));
await waitFor(() => expect(draftPuts(FRESH.name)).toHaveLength(1));
await waitFor(() => expect(draftPuts(ACCOUNT.name)).toHaveLength(1));
Expand All @@ -198,7 +215,7 @@ describe('PackageOwdOverviewPanel — an unsaved object is not asked for /layers
// The draft read failed, so the baseline is the only source left: read, as
// before (the framework answers 404, and the row stays on nothing, as before).
expect(layersAsked(FRESH.name)).toBe(1);
expect((screen.getByTestId(`owd-internal-${FRESH.name}`) as HTMLSelectElement).value).toBe('');
expect(screen.getByTestId(`owd-internal-${FRESH.name}`).textContent).toBe(OWD_LABEL['']);
expect(screen.getByTestId(`owd-row-${FRESH.name}`)).not.toHaveTextContent('Unpublished draft');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,23 @@

import '@testing-library/jest-dom/vitest';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
import { cleanup, fireEvent, render, screen, waitFor, within } from '@testing-library/react';
import React from 'react';
import { MetadataClient } from '@object-ui/data-objectstack';

vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn() } }));

import { toast } from 'sonner';
import { t } from '../metadata-admin/i18n';
import { PackageOwdOverviewPanel } from './PackageOwdOverviewPanel';

/** Pick a dial's option by its label, through the trigger, as a user does; the dials are the shared Select (objectui#11865). */
async function pickOwd(testId: string, label: string): Promise<void> {
fireEvent.keyDown(screen.getByTestId(testId), { key: 'ArrowDown' });
const listbox = await screen.findByRole('listbox');
fireEvent.click(within(listbox).getByRole('option', { name: label }));
}

type Row = Record<string, unknown>;

const PKG = 'com.example.acme';
Expand Down Expand Up @@ -123,7 +131,7 @@ afterEach(() => {
async function changeSharingAndSave(client: MetadataClient): Promise<void> {
render(<PackageOwdOverviewPanel client={client} packageId={PKG} locale="en-US" />);
await screen.findByTestId('owd-row-acme_account');
fireEvent.change(screen.getByTestId('owd-internal-acme_account'), { target: { value: 'public_read' } });
await pickOwd('owd-internal-acme_account', t('engine.studio.settings.sharingPublicRead', 'en-US'));
fireEvent.click(screen.getByTestId('owd-save'));
await waitFor(() => expect(puts).toHaveLength(1));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,21 @@

import '@testing-library/jest-dom/vitest';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
import { cleanup, fireEvent, render, screen, waitFor, within } from '@testing-library/react';
import React from 'react';

vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn() } }));

import { t } from '../metadata-admin/i18n';
import { PackageOwdOverviewPanel } from './PackageOwdOverviewPanel';

/** Pick a dial's option by its label, through the trigger, as a user does; the dials are the shared Select (objectui#11865). */
async function pickOwd(testId: string, label: string): Promise<void> {
fireEvent.keyDown(screen.getByTestId(testId), { key: 'ArrowDown' });
const listbox = await screen.findByRole('listbox');
fireEvent.click(within(listbox).getByRole('option', { name: label }));
}

/** Exactly what the framework attaches to a `?state=draft` read. */
const DECORATIONS = { _diagnostics: { valid: true, errors: [] }, _draft: true };
/** ADR-0010 carriers: declared by the schemas, must survive the strip. */
Expand Down Expand Up @@ -102,9 +110,7 @@ describe('PackageOwdOverviewPanel — read decorations never reach the save (obj
);
await screen.findByTestId('owd-row-crm_contact');

fireEvent.change(screen.getByTestId('owd-internal-crm_contact'), {
target: { value: 'public_read' },
});
await pickOwd('owd-internal-crm_contact', t('engine.studio.settings.sharingPublicRead', 'en-US'));
fireEvent.click(screen.getByTestId('owd-save'));

// CONTROL: the save really happened, and really carried the edit. Every
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,21 @@

import '@testing-library/jest-dom/vitest';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
import { cleanup, fireEvent, render, screen, waitFor, within } from '@testing-library/react';
import React from 'react';

vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn() } }));

import { t } from '../metadata-admin/i18n';
import { PackageOwdOverviewPanel } from './PackageOwdOverviewPanel';

/** Pick a dial's option by its label, through the trigger, as a user does; the dials are the shared Select (objectui#11865). */
async function pickOwd(testId: string, label: string): Promise<void> {
fireEvent.keyDown(screen.getByTestId(testId), { key: 'ArrowDown' });
const listbox = await screen.findByRole('listbox');
fireEvent.click(within(listbox).getByRole('option', { name: label }));
}

/** The published object: both OWD models set, plus a description. */
const PUBLISHED = {
name: 'crm_contact',
Expand Down Expand Up @@ -76,16 +84,18 @@ describe('PackageOwdOverviewPanel — the pending draft is read and re-saved as-
render(<PackageOwdOverviewPanel client={makeClient()} packageId="com.example.showcase" locale="en-US" />);
await screen.findByTestId('owd-row-crm_contact');

const internal = screen.getByTestId('owd-internal-crm_contact') as HTMLSelectElement;
const internal = screen.getByTestId('owd-internal-crm_contact');
// Red on base: the spread over `effective` showed `private` from the published row.
expect(internal.value).toBe('');
// The dial is the shared Select's trigger (objectui#11865), so its text is what it shows.
expect(internal.textContent).toBe(t('engine.studio.settings.sharingUnset', 'en-US'));
expect(internal).not.toHaveTextContent(t('engine.studio.settings.sharingPrivate', 'en-US'));
});

it('SAVE: an edit lands on the draft alone — the published model and description the draft deleted do not come back', async () => {
render(<PackageOwdOverviewPanel client={makeClient()} packageId="com.example.showcase" locale="en-US" />);
await screen.findByTestId('owd-row-crm_contact');

fireEvent.change(screen.getByTestId('owd-internal-crm_contact'), { target: { value: 'public_read' } });
await pickOwd('owd-internal-crm_contact', t('engine.studio.settings.sharingPublicRead', 'en-US'));
fireEvent.click(screen.getByTestId('owd-save'));

await waitFor(() => expect(saved).toHaveLength(1));
Expand Down
Loading
Loading