mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Publish catalog updates on save
This commit is contained in:
@@ -98,8 +98,8 @@ type AgentDefinitionDialogProps = {
|
||||
input: CreatePersonaInput | UpdatePersonaInput,
|
||||
options: AgentDefinitionSubmitOptions,
|
||||
) => Promise<unknown>;
|
||||
/** Offers publishing alongside Save after a shared agent has been edited. */
|
||||
showPublishUpdatesOption?: boolean;
|
||||
/** Publishes saved changes when the edited agent is shared in the catalog. */
|
||||
publishCatalogUpdatesOnSave?: boolean;
|
||||
/** Rendered below the form fields in create mode only ("Where to run"). */
|
||||
createRunSection?: React.ReactNode;
|
||||
/** Extra create-mode submit gate (e.g. incomplete provider config). */
|
||||
@@ -127,7 +127,7 @@ export function AgentDefinitionDialog({
|
||||
runtimesLoading = false,
|
||||
onOpenChange,
|
||||
onSubmit,
|
||||
showPublishUpdatesOption = false,
|
||||
publishCatalogUpdatesOnSave = false,
|
||||
createRunSection,
|
||||
createSubmitBlocked = false,
|
||||
}: AgentDefinitionDialogProps) {
|
||||
@@ -166,8 +166,6 @@ export function AgentDefinitionDialog({
|
||||
const [isAvatarUploadPending, setIsAvatarUploadPending] =
|
||||
React.useState(false);
|
||||
const [hasUserChanges, setHasUserChanges] = React.useState(false);
|
||||
const [publishUpdatesChecked, setPublishUpdatesChecked] =
|
||||
React.useState(false);
|
||||
const {
|
||||
globalConfig,
|
||||
inheritedDefaults: {
|
||||
@@ -224,7 +222,6 @@ export function AgentDefinitionDialog({
|
||||
setShowAdvancedFields(false);
|
||||
setIsAvatarUploadPending(false);
|
||||
setHasUserChanges(false);
|
||||
setPublishUpdatesChecked(false);
|
||||
isRuntimeAutoSeededRef.current = false;
|
||||
hasSeededForOpenRef.current = false;
|
||||
}, [initialValues, open]);
|
||||
@@ -271,7 +268,6 @@ export function AgentDefinitionDialog({
|
||||
setShowAdvancedFields(false);
|
||||
setIsAvatarUploadPending(false);
|
||||
setHasUserChanges(false);
|
||||
setPublishUpdatesChecked(false);
|
||||
// isRuntimeAutoSeededRef and hasSeededForOpenRef are NOT reset here — the
|
||||
// [initialValues, open] effect resets both when the dialog re-opens.
|
||||
}
|
||||
@@ -329,8 +325,7 @@ export function AgentDefinitionDialog({
|
||||
...baseInput,
|
||||
},
|
||||
{
|
||||
publishCatalogUpdates:
|
||||
showPublishUpdatesOption && hasUserChanges && publishUpdatesChecked,
|
||||
publishCatalogUpdates: publishCatalogUpdatesOnSave && hasUserChanges,
|
||||
},
|
||||
);
|
||||
return;
|
||||
@@ -736,9 +731,9 @@ export function AgentDefinitionDialog({
|
||||
isAvatarUploadPending={isAvatarUploadPending}
|
||||
isPending={isPending}
|
||||
onCancel={() => handleOpenChange(false)}
|
||||
onPublishUpdatesCheckedChange={setPublishUpdatesChecked}
|
||||
publishUpdatesChecked={publishUpdatesChecked}
|
||||
showPublishUpdates={showPublishUpdatesOption && hasUserChanges}
|
||||
publishesCatalogUpdates={
|
||||
publishCatalogUpdatesOnSave && hasUserChanges
|
||||
}
|
||||
submitBlockReason={displayName.trim() ? submitBlockReason : null}
|
||||
submitLabel={submitLabel}
|
||||
/>
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import { Button } from "@/shared/ui/button";
|
||||
import { Checkbox } from "@/shared/ui/checkbox";
|
||||
|
||||
type AgentDefinitionDialogFooterProps = {
|
||||
canSubmit: boolean;
|
||||
isAvatarUploadPending: boolean;
|
||||
isPending: boolean;
|
||||
onCancel: () => void;
|
||||
onPublishUpdatesCheckedChange: (checked: boolean) => void;
|
||||
publishUpdatesChecked: boolean;
|
||||
showPublishUpdates: boolean;
|
||||
publishesCatalogUpdates: boolean;
|
||||
submitBlockReason: string | null;
|
||||
submitLabel: string;
|
||||
};
|
||||
@@ -18,9 +15,7 @@ export function AgentDefinitionDialogFooter({
|
||||
isAvatarUploadPending,
|
||||
isPending,
|
||||
onCancel,
|
||||
onPublishUpdatesCheckedChange,
|
||||
publishUpdatesChecked,
|
||||
showPublishUpdates,
|
||||
publishesCatalogUpdates,
|
||||
submitBlockReason,
|
||||
submitLabel,
|
||||
}: AgentDefinitionDialogFooterProps) {
|
||||
@@ -35,22 +30,14 @@ export function AgentDefinitionDialogFooter({
|
||||
{submitBlockReason}
|
||||
</p>
|
||||
) : null}
|
||||
{showPublishUpdates ? (
|
||||
<label
|
||||
className="flex cursor-pointer items-center gap-2 text-sm font-medium text-foreground"
|
||||
htmlFor="persona-dialog-publish-updates"
|
||||
{publishesCatalogUpdates ? (
|
||||
<p
|
||||
className="max-w-sm text-xs text-muted-foreground"
|
||||
data-testid="persona-dialog-catalog-publish-notice"
|
||||
>
|
||||
<Checkbox
|
||||
checked={publishUpdatesChecked}
|
||||
data-testid="persona-dialog-publish-updates"
|
||||
disabled={isPending || isAvatarUploadPending}
|
||||
id="persona-dialog-publish-updates"
|
||||
onCheckedChange={(checked) =>
|
||||
onPublishUpdatesCheckedChange(checked === true)
|
||||
}
|
||||
/>
|
||||
<span>Publish updates</span>
|
||||
</label>
|
||||
This agent is in the community catalog. Your changes will be
|
||||
published when you save.
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
@@ -73,7 +60,9 @@ export function AgentDefinitionDialogFooter({
|
||||
? "Saving..."
|
||||
: isAvatarUploadPending
|
||||
? "Uploading..."
|
||||
: submitLabel}
|
||||
: publishesCatalogUpdates
|
||||
? "Save and publish"
|
||||
: submitLabel}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -69,7 +69,7 @@ type AgentDialogDefinitionEditProps = {
|
||||
input: CreatePersonaInput | UpdatePersonaInput,
|
||||
options: AgentDefinitionSubmitOptions,
|
||||
) => Promise<unknown>;
|
||||
showPublishUpdatesOption?: boolean;
|
||||
publishCatalogUpdatesOnSave?: boolean;
|
||||
};
|
||||
|
||||
type AgentDialogProps =
|
||||
|
||||
@@ -332,7 +332,7 @@ export function AgentsView() {
|
||||
)
|
||||
}
|
||||
open={personas.personaDialogState !== null}
|
||||
showPublishUpdatesOption={
|
||||
publishCatalogUpdatesOnSave={
|
||||
"id" in personas.personaDialogState.initialValues &&
|
||||
personas.sharedCatalogPersonaIdSet.has(
|
||||
personas.personaDialogState.initialValues.id,
|
||||
|
||||
@@ -1399,29 +1399,48 @@ This deliberately long fenced-code example must not establish the minimum width
|
||||
await page.getByLabel("Open actions for Catalog Analyst").click();
|
||||
await page.getByRole("menuitem", { name: "Edit" }).click();
|
||||
const editDialog = page.getByTestId("persona-dialog");
|
||||
const publishUpdatesCheckbox = editDialog.getByTestId(
|
||||
"persona-dialog-publish-updates",
|
||||
const catalogPublishNotice = editDialog.getByTestId(
|
||||
"persona-dialog-catalog-publish-notice",
|
||||
);
|
||||
await expect(publishUpdatesCheckbox).toHaveCount(0);
|
||||
await expect(catalogPublishNotice).toHaveCount(0);
|
||||
await expect(
|
||||
editDialog.getByRole("button", { name: "Save and publish" }),
|
||||
).toHaveCount(0);
|
||||
await expect(
|
||||
editDialog.getByRole("button", { name: "Save changes" }),
|
||||
).toBeVisible();
|
||||
await editDialog
|
||||
.getByLabel("Agent instructions")
|
||||
.fill("Review the latest catalog changes.");
|
||||
await expect(publishUpdatesCheckbox).toBeVisible();
|
||||
await expect(publishUpdatesCheckbox).toHaveAttribute(
|
||||
"data-state",
|
||||
"unchecked",
|
||||
await expect(catalogPublishNotice).toHaveText(
|
||||
"This agent is in the community catalog. Your changes will be published when you save.",
|
||||
);
|
||||
const [cancelButtonBox, publishUpdatesCheckboxBox] = await Promise.all([
|
||||
editDialog.getByRole("button", { name: "Cancel" }).boundingBox(),
|
||||
publishUpdatesCheckbox.boundingBox(),
|
||||
]);
|
||||
expect(
|
||||
(publishUpdatesCheckboxBox?.x ?? 0) +
|
||||
(publishUpdatesCheckboxBox?.width ?? 0),
|
||||
).toBeLessThan(cancelButtonBox?.x ?? 0);
|
||||
await editDialog.getByRole("button", { name: "Save changes" }).click();
|
||||
await expect(
|
||||
editDialog.getByRole("button", { name: "Save changes" }),
|
||||
).toHaveCount(0);
|
||||
await editDialog.getByRole("button", { name: "Save and publish" }).click();
|
||||
await expect(editDialog).toHaveCount(0);
|
||||
|
||||
await page.getByLabel("Open actions for Catalog Analyst").click();
|
||||
await page.getByRole("menuitem", { name: "Share" }).click();
|
||||
await expect(catalogAccess).toHaveText("Agent only");
|
||||
await expect(publishCatalogUpdatesButton).toHaveCount(0);
|
||||
await page
|
||||
.getByTestId("persona-share-dialog")
|
||||
.getByRole("button", { name: "Close" })
|
||||
.click();
|
||||
|
||||
await page.evaluate((id) => {
|
||||
const storageKey = "buzz-persona-catalog-published-versions-v1";
|
||||
const publishedVersions = JSON.parse(
|
||||
localStorage.getItem(storageKey) ?? "{}",
|
||||
) as Record<string, string>;
|
||||
publishedVersions[id] = "stale";
|
||||
localStorage.setItem(storageKey, JSON.stringify(publishedVersions));
|
||||
}, personaId);
|
||||
await gotoApp(page);
|
||||
await page.getByTestId("open-agents-view").click();
|
||||
|
||||
await page.getByLabel("Open actions for Catalog Analyst").click();
|
||||
await page.getByRole("menuitem", { name: "Share" }).click();
|
||||
await expect(catalogAccess).toHaveText("Agent only");
|
||||
@@ -1442,17 +1461,6 @@ This deliberately long fenced-code example must not establish the minimum width
|
||||
.getByRole("button", { name: "Close" })
|
||||
.click();
|
||||
|
||||
await page.getByLabel("Open actions for Catalog Analyst").click();
|
||||
await page.getByRole("menuitem", { name: "Edit" }).click();
|
||||
await editDialog
|
||||
.getByLabel("Agent instructions")
|
||||
.fill("Review and publish the latest catalog changes.");
|
||||
await expect(publishUpdatesCheckbox).toBeVisible();
|
||||
await publishUpdatesCheckbox.click();
|
||||
await expect(publishUpdatesCheckbox).toHaveAttribute("data-state", "checked");
|
||||
await editDialog.getByRole("button", { name: "Save changes" }).click();
|
||||
await expect(editDialog).toHaveCount(0);
|
||||
|
||||
await page.getByLabel("Open actions for Catalog Analyst").click();
|
||||
await page.getByRole("menuitem", { name: "Share" }).click();
|
||||
await expect(catalogAccess).toHaveText("Agent only");
|
||||
|
||||
Reference in New Issue
Block a user