fix(ui): remove stored-file browsing entry points
Defer cached-file debugging and live sandbox inspection as separate features. Keep the saved-file browser only as an unshipped Storybook prototype. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
parent
bd4b566f96
commit
71774a29ca
|
|
@ -132,11 +132,16 @@ directories are not supported by this checkpoint format.
|
|||
|
||||
## API and UI
|
||||
|
||||
The task, agent, project, and current-user pages expose a Files dialog using the
|
||||
shared file tree and viewer. It supports uploads, folder creation, previews,
|
||||
downloads, deletion, trash restore/purge, and sync state with the last agent save
|
||||
time. Direct file-operation timestamps are labeled separately as “Files updated”;
|
||||
a delete, restore, or idempotent receipt is not presented as an agent checkpoint.
|
||||
The task, agent, project, and current-user pages do not expose stored-file
|
||||
browsing. The 2026-09-08 design review removed these entry points: durable copies
|
||||
can lag behind a running sandbox and do not represent its complete filesystem.
|
||||
The persistence and synchronization APIs remain available to the runtime.
|
||||
|
||||
Two separate features are deferred: debug inspection of persisted collections,
|
||||
and authorized inspection of the live sandbox filesystem across its task,
|
||||
agent, user, project, and repository context. The stored-file browser remains
|
||||
only as an unshipped Storybook prototype. It must not be presented as a live
|
||||
sandbox view. Page stories show the current pages without Files buttons.
|
||||
|
||||
All routes start at
|
||||
`/api/companies/:companyId/work-folders/:scope/:ownerId`:
|
||||
|
|
@ -166,7 +171,9 @@ new pinned staging stack with the branch's Cloud image and matching migrator.
|
|||
The deployed harness must target that tenant URL without launching a local
|
||||
server. Enumerate every sandbox-capable adapter/engine and native profile
|
||||
exposed by the stack; missing credentials or skipped required profiles block
|
||||
acceptance. Record real browser operations, two actual 180-second intervals,
|
||||
acceptance. Verify that the removed stored-file entry points are absent from
|
||||
the UI; browser-based file-management acceptance is deferred with the separate
|
||||
inspection features. Record API/runner operations, two actual 180-second intervals,
|
||||
short-run flushes, independent task checkouts, identity/privacy boundaries,
|
||||
interrupted saves, and recovery without the original sandbox or app volume.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useId, useMemo, useRef, useState } from "react";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { Download, FolderOpen, FolderPlus, RefreshCw, RotateCcw, Trash2, Upload } from "lucide-react";
|
||||
import { Download, FolderPlus, RefreshCw, RotateCcw, Trash2, Upload } from "lucide-react";
|
||||
import type { WorkFile, WorkFolderOwner } from "@paperclipai/shared";
|
||||
import { workFoldersApi } from "@/api/work-folders";
|
||||
import { FileTree, type FileTreeNode } from "@/components/FileTree";
|
||||
|
|
@ -9,7 +9,6 @@ import { Button } from "@/components/ui/button";
|
|||
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
|
||||
|
||||
function tree(files: WorkFile[]) {
|
||||
const root: FileTreeNode = { name: "", path: "", kind: "dir", children: [] };
|
||||
|
|
@ -30,16 +29,6 @@ function tree(files: WorkFile[]) {
|
|||
sort(root.children); return root.children;
|
||||
}
|
||||
|
||||
export function WorkFolderButton({ owner, label = "Files" }: { owner: WorkFolderOwner; label?: string }) {
|
||||
return <Dialog><DialogTrigger asChild><Button variant="outline" size="sm"><FolderOpen aria-hidden />{label}</Button></DialogTrigger>
|
||||
<DialogContent className="flex max-h-screen flex-col sm:max-w-5xl">
|
||||
<DialogHeader><DialogTitle>{label}</DialogTitle><DialogDescription>
|
||||
{owner.scope === "user" ? "Your private Paperclip files in this company." : `Files shared with this ${owner.scope}'s sandbox runs.`} Changes from running agents are saved every three minutes and when a run ends.
|
||||
</DialogDescription></DialogHeader>
|
||||
<WorkFolderBrowser key={`${owner.companyId}:${owner.scope}:${owner.ownerId}`} owner={owner} />
|
||||
</DialogContent></Dialog>;
|
||||
}
|
||||
|
||||
export function WorkFolderBrowser({ owner, exampleFiles }: { owner: WorkFolderOwner; exampleFiles?: WorkFile[] }) {
|
||||
const queryClient = useQueryClient();
|
||||
const [trash, setTrash] = useState(false);
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ import { cn } from "../lib/utils";
|
|||
import { describeRunRetryState } from "../lib/runRetryState";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Tabs } from "@/components/ui/tabs";
|
||||
import { WorkFolderButton } from "@/components/WorkFolderBrowser";
|
||||
import { PageTabBar } from "../components/PageTabBar";
|
||||
import { AuditFeed } from "./audit/AuditFeed";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
|
|
@ -1374,8 +1373,6 @@ export function AgentDetail() {
|
|||
</Tabs>
|
||||
) : null}
|
||||
|
||||
<WorkFolderButton owner={{ companyId: agent.companyId, scope: "agent", ownerId: agent.id }} label="Agent files" />
|
||||
|
||||
{actionError && <p className="text-sm text-destructive">{actionError}</p>}
|
||||
{isPendingApproval && (
|
||||
<div className="flex flex-wrap items-center gap-3 rounded-md border border-amber-300/60 bg-amber-50 px-3 py-2 text-sm text-amber-900 dark:border-amber-400/40 dark:bg-amber-950/30 dark:text-amber-200">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { useState } from "react";
|
||||
import { WorkFolderBrowser } from "@/components/WorkFolderBrowser";
|
||||
import { ServicesList } from "./apps/app-detail/ServicesPanel";
|
||||
import { ComposioProvenanceChip } from "./apps/ComposioProvenanceChip";
|
||||
import type { ComposioServiceRow } from "./apps/composio-services";
|
||||
|
|
@ -483,14 +482,6 @@ export function DesignGuide() {
|
|||
{/* ============================================================ */}
|
||||
{/* COVERAGE */}
|
||||
{/* ============================================================ */}
|
||||
<Section title="Work folders">
|
||||
<WorkFolderBrowser owner={{ companyId: "example", scope: "task", ownerId: "example" }} exampleFiles={[
|
||||
{ id: "notes", path: "notes", kind: "directory", byteSize: 0, sha256: null, executable: false, contentType: "application/octet-stream", deletedAt: null, updatedAt: "2026-09-07T00:00:00Z" },
|
||||
{ id: "readme", path: "notes/README.md", kind: "file", byteSize: 24, sha256: null, executable: false, contentType: "text/markdown", deletedAt: null, updatedAt: "2026-09-07T00:00:00Z" },
|
||||
]} />
|
||||
<WorkFolderBrowser owner={{ companyId: "example", scope: "user", ownerId: "example" }} exampleFiles={[]} />
|
||||
</Section>
|
||||
|
||||
<Section title="Component Coverage">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
This page should be updated when new UI primitives or app-level patterns ship.
|
||||
|
|
|
|||
|
|
@ -171,7 +171,6 @@ import { useStreamlinedUiEnabled } from "../hooks/useStreamlinedUiEnabled";
|
|||
import { workModeMetaFor } from "../lib/work-mode-meta";
|
||||
import { IssueContinuationHandoff } from "../components/IssueContinuationHandoff";
|
||||
import { IssueAttachmentsSection } from "../components/IssueAttachmentsSection";
|
||||
import { WorkFolderButton } from "@/components/WorkFolderBrowser";
|
||||
import { IssueDocumentsSection } from "../components/IssueDocumentsSection";
|
||||
import { IssuePlanDecompositionsSection } from "../components/IssuePlanDecompositionsSection";
|
||||
import { IssueOutputSection } from "../components/issue-output/IssueOutputSection";
|
||||
|
|
@ -7470,8 +7469,6 @@ export function IssueDetail() {
|
|||
/>
|
||||
)}
|
||||
|
||||
<WorkFolderButton owner={{ companyId: issue.companyId, scope: "task", ownerId: issue.id }} label="Task files" />
|
||||
|
||||
{taskChatShellEnabled ? null : (
|
||||
<IssueOutputSection
|
||||
workProducts={workProducts}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import { Card } from "@/components/ui/card";
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { WorkFolderButton } from "@/components/WorkFolderBrowser";
|
||||
|
||||
function deriveInitials(name: string) {
|
||||
const parts = name.trim().split(/\s+/).filter(Boolean);
|
||||
|
|
@ -272,7 +271,6 @@ export function ProfileSettings() {
|
|||
</form>
|
||||
|
||||
<InboxAgentPolicyControl companyId={selectedCompanyId} />
|
||||
{selectedCompanyId && <WorkFolderButton owner={{ companyId: selectedCompanyId, scope: "user", ownerId: sessionQuery.data.user.id }} label="My files" />}
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ import { Input } from "@/components/ui/input";
|
|||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Tabs } from "@/components/ui/tabs";
|
||||
import { WorkFolderButton } from "@/components/WorkFolderBrowser";
|
||||
import { PluginLauncherOutlet } from "@/plugins/launchers";
|
||||
import { PluginSlotMount, PluginSlotOutlet, usePluginSlots } from "@/plugins/slots";
|
||||
import {
|
||||
|
|
@ -822,7 +821,6 @@ export function ProjectDetail() {
|
|||
) : null}
|
||||
</div>
|
||||
<div className="ml-auto flex items-center gap-2">
|
||||
<WorkFolderButton owner={{ companyId: project.companyId, scope: "project", ownerId: project.id }} label="Project files" />
|
||||
<StarToggle
|
||||
size="button"
|
||||
starred={projectStarred}
|
||||
|
|
|
|||
|
|
@ -3,53 +3,48 @@
|
|||
Run `pnpm storybook` from the repository root. Open the **Work folders** group.
|
||||
The default URL is `http://localhost:6006`.
|
||||
|
||||
## Components
|
||||
## Current pages
|
||||
|
||||
`Work folders / Components` renders the production `WorkFolderBrowser` and
|
||||
`WorkFolderButton`. It includes the browser, its trigger and dialog, Markdown,
|
||||
code, image and empty-file previews, unsupported/large-file messages, loading,
|
||||
empty, saving, failed-save, unavailable-storage, failed-upload, trash, and
|
||||
permanent-deletion confirmation states. `Upload Delete Restore` exercises the
|
||||
full recovery interaction and leaves the restored file available for review.
|
||||
The 2026-09-08 design decision removes stored-file entry points from task, agent,
|
||||
project, and profile pages. Saved copies can lag behind the running sandbox and
|
||||
are not a complete view of what the agent sees on disk. No replacement Files
|
||||
link is added to the properties pane.
|
||||
|
||||
**Work folders / Pages** mounts the actual pages inside `Layout`: Task Page,
|
||||
Agent Page, Project Page, Profile Settings Page, and Mobile Task Page. These show
|
||||
the current UI without the removed buttons. The previous open-dialog stories
|
||||
have been removed.
|
||||
|
||||
## Deferred inspection features
|
||||
|
||||
Debug inspection of persisted files and live sandbox filesystem browsing need
|
||||
separate designs. Persistence, checkpointing, and the runtime APIs remain in
|
||||
place; this UI change does not remove saved data or alter synchronization.
|
||||
|
||||
**Work folders / Stored-file prototype** retains the reusable browser for design
|
||||
reference only. It is explicitly labeled as unshipped and has no entry point in
|
||||
the application or Design Guide. It includes Markdown, code, image and empty-file
|
||||
previews, unsupported/large-file messages, loading, empty, saving, failed-save,
|
||||
unavailable-storage, failed-upload, trash, and permanent-deletion states.
|
||||
|
||||
Use **Controls** to change task/agent/project/user scope or the fixture state.
|
||||
Use Storybook's theme and viewport toolbar controls for light/dark and mobile
|
||||
review. The fixtures reset when you reload the story or change its controls.
|
||||
|
||||
## Pages
|
||||
|
||||
`Work folders / Pages` mounts the actual route pages inside `Layout`:
|
||||
|
||||
| Page | Current entry point | Stories |
|
||||
| ---------------- | ---------------------------------------------------- | ------------------------------------------------------ |
|
||||
| Task detail | Task files above the task thread | Task Page, Task Files Open, Task Save Failed |
|
||||
| Agent detail | Agent files in the detail header | Agent Page, Agent Files Open |
|
||||
| Project detail | Project files in the project header | Project Page, Project Files Open, Project Empty Folder |
|
||||
| Profile settings | My files below the profile and inbox policy settings | Profile Settings Page, My Files Open |
|
||||
|
||||
The page stories preserve existing placement, copy, and spacing. They are a
|
||||
review surface for the current implementation, not proposed redesigns. The
|
||||
Open stories activate the page's real button automatically. Close the dialog
|
||||
to review its surrounding page.
|
||||
The toolbar supports light/dark and mobile review. Fixtures reset when you reload
|
||||
the story or change its controls.
|
||||
|
||||
## Fixture boundaries
|
||||
|
||||
Uploads, previews, downloads, folder creation, deletion, restoration, purge,
|
||||
and refresh use a fresh in-memory API per story. They do not contact a tenant,
|
||||
launch agents, or persist files. Downloads contain fixture data only. Other
|
||||
page mutations display an explicit unsupported-demo message. The story restores
|
||||
its fetch handler and clears its isolated query cache on unmount. The loading
|
||||
scenario intentionally remains pending until you leave that story.
|
||||
Prototype uploads, previews, downloads, folder creation, deletion, restoration,
|
||||
purge, and refresh use fresh in-memory data. They do not contact a tenant, launch
|
||||
agents, or persist files. Other page mutations display an unsupported-demo
|
||||
message. The story restores its fetch handler and clears its query cache on
|
||||
unmount. The loading example remains pending until you leave the story.
|
||||
|
||||
Saving and failed states are fixed examples for visual review. Refresh shows the
|
||||
real acknowledgement, but does not launch a sandbox. These stories do not replace
|
||||
the deployed persistence and runner acceptance matrix.
|
||||
Saving and failed states are fixed visual examples. Refresh shows the real
|
||||
acknowledgement but does not launch a sandbox. These prototypes do not replace
|
||||
runtime persistence testing or implement either deferred inspection feature.
|
||||
|
||||
## Supporting UI
|
||||
|
||||
The feature stack also changes the native runner's Pi ACPX selector and
|
||||
Cloud-aware CLI authorization. **Work folders / Supporting UI** shows the real
|
||||
runtime fields and the request, approved, sign-in-required, and expired CLI
|
||||
pages. These use fictional challenges and cannot grant access or create keys.
|
||||
The file viewer's shared rendering is covered by the component preview stories;
|
||||
the design-guide examples use the same browser component.
|
||||
**Work folders / Supporting UI** shows the native Pi ACPX selector and the
|
||||
request, approved, sign-in-required, and expired CLI authorization pages. The
|
||||
fictional challenges cannot grant access or create keys.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { useEffect } from "react";
|
||||
import type { Meta, StoryObj } from "@storybook/react-vite";
|
||||
import { expect, userEvent, within } from "storybook/test";
|
||||
import { Route, Routes, useLocation, useNavigate } from "react-router-dom";
|
||||
import { PluginLauncherProvider } from "@/plugins/launchers";
|
||||
import { Layout } from "@/components/Layout";
|
||||
|
|
@ -15,11 +14,7 @@ import {
|
|||
workFolderProject,
|
||||
workFolderTask,
|
||||
} from "../fixtures/WorkFolderStoryProvider";
|
||||
import {
|
||||
WORK_FOLDER_COMPANY,
|
||||
workFolderLabels,
|
||||
type WorkFolderScenario,
|
||||
} from "../fixtures/workFolders";
|
||||
import { WORK_FOLDER_COMPANY } from "../fixtures/workFolders";
|
||||
import type { WorkFolderScope } from "@paperclipai/shared";
|
||||
|
||||
const paths = {
|
||||
|
|
@ -64,77 +59,25 @@ const meta = {
|
|||
docs: {
|
||||
description: {
|
||||
component:
|
||||
"Real production pages inside the application Layout, including sidebar, breadcrumb, and original file-button placement. These are current designs, not redesigned mockups. Task files are in the task thread, Agent files and Project files are in their detail pages, and My files is at the bottom of Profile settings. The Open stories click the actual entry point. Work-folder actions use disposable in-memory data; other page edits are not simulated.",
|
||||
"Current production pages after removing the stored-file entry points. Persisted copies do not represent the live sandbox filesystem. Debug inspection of saved files and live sandbox browsing are deferred features. Page mutations are not simulated.",
|
||||
},
|
||||
},
|
||||
},
|
||||
args: { scope: "task", scenario: "saved" },
|
||||
argTypes: {
|
||||
scope: { control: false },
|
||||
scenario: {
|
||||
control: "select",
|
||||
options: ["saved", "saving", "failed", "empty", "unavailable"],
|
||||
},
|
||||
},
|
||||
render: ({
|
||||
scope,
|
||||
scenario,
|
||||
}: {
|
||||
scope: WorkFolderScope;
|
||||
scenario: WorkFolderScenario;
|
||||
}) => (
|
||||
<WorkFolderStoryProvider key={`${scope}:${scenario}`} scenario={scenario}>
|
||||
args: { scope: "task" },
|
||||
argTypes: { scope: { control: false } },
|
||||
render: ({ scope }: { scope: WorkFolderScope }) => (
|
||||
<WorkFolderStoryProvider key={scope}>
|
||||
<Page scope={scope} />
|
||||
</WorkFolderStoryProvider>
|
||||
),
|
||||
} satisfies Meta<{ scope: WorkFolderScope; scenario: WorkFolderScenario }>;
|
||||
} satisfies Meta<{ scope: WorkFolderScope }>;
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
const openFiles: NonNullable<Story["play"]> = async ({
|
||||
canvasElement,
|
||||
args,
|
||||
}) => {
|
||||
const label = workFolderLabels[args.scope];
|
||||
await userEvent.click(
|
||||
await within(canvasElement).findByRole(
|
||||
"button",
|
||||
{ name: label },
|
||||
{ timeout: 15000 },
|
||||
),
|
||||
);
|
||||
await expect(
|
||||
await within(canvasElement.ownerDocument.body).findByRole("dialog", {
|
||||
name: label,
|
||||
}),
|
||||
).toBeVisible();
|
||||
};
|
||||
export const TaskPage: Story = { args: { scope: "task" } };
|
||||
export const TaskFilesOpen: Story = {
|
||||
args: { scope: "task" },
|
||||
play: openFiles,
|
||||
};
|
||||
export const AgentPage: Story = { args: { scope: "agent" } };
|
||||
export const AgentFilesOpen: Story = {
|
||||
args: { scope: "agent" },
|
||||
play: openFiles,
|
||||
};
|
||||
export const ProjectPage: Story = { args: { scope: "project" } };
|
||||
export const ProjectFilesOpen: Story = {
|
||||
args: { scope: "project" },
|
||||
play: openFiles,
|
||||
};
|
||||
export const ProfileSettingsPage: Story = { args: { scope: "user" } };
|
||||
export const MyFilesOpen: Story = { args: { scope: "user" }, play: openFiles };
|
||||
export const TaskSaveFailed: Story = {
|
||||
args: { scope: "task", scenario: "failed" },
|
||||
play: openFiles,
|
||||
};
|
||||
export const ProjectEmptyFolder: Story = {
|
||||
args: { scope: "project", scenario: "empty" },
|
||||
play: openFiles,
|
||||
};
|
||||
export const MobileTaskFilesOpen: Story = {
|
||||
export const MobileTaskPage: Story = {
|
||||
args: { scope: "task" },
|
||||
globals: { viewport: { value: "mobile" } },
|
||||
play: openFiles,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,12 +1,8 @@
|
|||
import type { Meta, StoryObj } from "@storybook/react-vite";
|
||||
import { expect, userEvent, within } from "storybook/test";
|
||||
import {
|
||||
WorkFolderBrowser,
|
||||
WorkFolderButton,
|
||||
} from "@/components/WorkFolderBrowser";
|
||||
import { WorkFolderBrowser } from "@/components/WorkFolderBrowser";
|
||||
import { WorkFolderStoryProvider } from "../fixtures/WorkFolderStoryProvider";
|
||||
import {
|
||||
workFolderLabels,
|
||||
workFolderOwners,
|
||||
type WorkFolderScenario,
|
||||
} from "../fixtures/workFolders";
|
||||
|
|
@ -15,20 +11,19 @@ import type { WorkFolderScope } from "@paperclipai/shared";
|
|||
type Args = {
|
||||
scope: WorkFolderScope;
|
||||
scenario: WorkFolderScenario;
|
||||
presentation: "browser" | "button";
|
||||
};
|
||||
const meta = {
|
||||
title: "Work folders/Components",
|
||||
title: "Work folders/Stored-file prototype",
|
||||
parameters: {
|
||||
layout: "padded",
|
||||
docs: {
|
||||
description: {
|
||||
component:
|
||||
"The actual reusable WorkFolderBrowser and WorkFolderButton. All file operations are in-memory fixtures: upload, create folder, delete, restore, purge, refresh, and download are safe to try. Change scope in Controls; use the toolbar for dark/light and mobile review. Reload a story to reset its files.",
|
||||
"Unshipped stored-file browser prototype. Application entry points were removed because saved copies are not the live sandbox filesystem. This Storybook-only review surface uses disposable in-memory data; debug inspection and live sandbox browsing need separate designs.",
|
||||
},
|
||||
},
|
||||
},
|
||||
args: { scope: "task", scenario: "saved", presentation: "browser" },
|
||||
args: { scope: "task", scenario: "saved" },
|
||||
argTypes: {
|
||||
scope: { control: "select", options: ["task", "agent", "project", "user"] },
|
||||
scenario: {
|
||||
|
|
@ -43,22 +38,15 @@ const meta = {
|
|||
"uploadFailed",
|
||||
],
|
||||
},
|
||||
presentation: { control: "radio", options: ["browser", "button"] },
|
||||
},
|
||||
render: ({ scope, scenario, presentation }) => (
|
||||
<WorkFolderStoryProvider
|
||||
key={`${scope}:${scenario}:${presentation}`}
|
||||
scenario={scenario}
|
||||
>
|
||||
render: ({ scope, scenario }) => (
|
||||
<WorkFolderStoryProvider key={`${scope}:${scenario}`} scenario={scenario}>
|
||||
<div className="mx-auto max-w-5xl">
|
||||
{presentation === "button" ? (
|
||||
<WorkFolderButton
|
||||
owner={workFolderOwners[scope]}
|
||||
label={workFolderLabels[scope]}
|
||||
/>
|
||||
) : (
|
||||
<WorkFolderBrowser owner={workFolderOwners[scope]} />
|
||||
)}
|
||||
<p className="mb-4 text-sm text-muted-foreground">
|
||||
Stored-file prototype — not exposed in the app. These are saved
|
||||
copies, not the live sandbox filesystem.
|
||||
</p>
|
||||
<WorkFolderBrowser owner={workFolderOwners[scope]} />
|
||||
</div>
|
||||
</WorkFolderStoryProvider>
|
||||
),
|
||||
|
|
@ -67,15 +55,6 @@ export default meta;
|
|||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const BrowseAndManage: Story = {};
|
||||
export const FileButton: Story = { args: { presentation: "button" } };
|
||||
export const OpenDialog: Story = {
|
||||
args: { presentation: "button" },
|
||||
play: async ({ canvasElement }) => {
|
||||
await userEvent.click(
|
||||
await within(canvasElement).findByRole("button", { name: "Task files" }),
|
||||
);
|
||||
},
|
||||
};
|
||||
export const MarkdownPreview: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
await userEvent.click(await within(canvasElement).findByText("README.md"));
|
||||
|
|
|
|||
Loading…
Reference in New Issue