Open files and replace the file row menu with real actions

This commit is contained in:
ZacharyZhang-NY committed 2026-05-28 22:36:31 -04:00
1 parent d2695202b5
commit 69ae525cb7
10 files changed
+81 -10

No files matched your search

@@ -1,6 +1,7 @@
import { useMemo, useState } from "react";
import { Button, Icon, Segmented } from "../shared/ui";
import { TopbarActions } from "../shared/TopbarActions";
import type { FileObjectRecord } from "../../../shared/domain";
import type { PageProps } from "./types";
import { activeOrgId, formatBytes } from "./types";
import { FilesTree } from "./files/FilesTree";
@@ -40,6 +41,13 @@ export function FilesPage({ snapshot, actions }: PageProps) {
if (!result.ok) throw new Error(result.error.message);
});
};
const openFile = (file: FileObjectRecord) => {
void window.agentCompany.openFile({ orgId, fileId: file.id }).then((result) => {
if (!result.ok) throw new Error(result.error.message);
});
};
const togglePin = (file: FileObjectRecord) =>
void actions.run(() => window.agentCompany.setFilePinned({ orgId, fileId: file.id, pinned: !file.pinned }));
return (
<div style={{ display: "grid", gridTemplateColumns: "minmax(160px, 200px) minmax(0, 1fr)", gap: 24, height: "100%", minHeight: 0, padding: "28px 32px 0" }}>
@@ -83,7 +91,8 @@ export function FilesPage({ snapshot, actions }: PageProps) {
file={file}
ownerName={resolveOwnerName(file, employees, agents)}
grantCount={fileGrantCount(file.id, fileAccessGrants)}
onUnpin={() => void actions.run(() => window.agentCompany.setFilePinned({ orgId, fileId: file.id, pinned: false }))}
onOpen={() => openFile(file)}
onUnpin={() => togglePin(file)}
/>
))}
</div>
@@ -101,7 +110,8 @@ export function FilesPage({ snapshot, actions }: PageProps) {
grants={fileAccessGrants}
employees={employees}
agents={agents}
onTogglePin={(file) => void actions.run(() => window.agentCompany.setFilePinned({ orgId, fileId: file.id, pinned: !file.pinned }))}
onOpen={openFile}
onTogglePin={togglePin}
/>
) : (
<FilesGrid
@@ -109,7 +119,8 @@ export function FilesPage({ snapshot, actions }: PageProps) {
grants={fileAccessGrants}
employees={employees}
agents={agents}
onTogglePin={(file) => void actions.run(() => window.agentCompany.setFilePinned({ orgId, fileId: file.id, pinned: !file.pinned }))}
onOpen={openFile}
onTogglePin={togglePin}
/>
)}
</div>
@@ -14,12 +14,14 @@ export function FilesGrid({
grants,
employees,
agents,
onOpen,
onTogglePin,
}: {
files: FileObjectRecord[];
grants: FileAccessGrantRecord[];
employees: EmployeeRecord[];
agents: AgentRecord[];
onOpen: (file: FileObjectRecord) => void;
onTogglePin: (file: FileObjectRecord) => void;
}) {
return (
@@ -30,6 +32,7 @@ export function FilesGrid({
file={file}
ownerName={resolveOwnerName(file, employees, agents)}
grantCount={fileGrantCount(file.id, grants)}
onOpen={() => onOpen(file)}
onUnpin={() => onTogglePin(file)}
/>
))}
@@ -41,15 +44,23 @@ export function PinnedCard({
file,
ownerName,
grantCount,
onOpen,
onUnpin,
}: {
file: FileObjectRecord;
ownerName: string;
grantCount: number;
onOpen: () => void;
onUnpin: () => void;
}) {
const canOpen = file.scanState === "approved";
return (
<div
className={canOpen ? "clickable-card" : ""}
role={canOpen ? "button" : undefined}
tabIndex={canOpen ? 0 : undefined}
onClick={canOpen ? onOpen : undefined}
onKeyDown={canOpen ? (event) => { if (event.key === "Enter") onOpen(); } : undefined}
style={{
border: "1px solid var(--border)",
borderRadius: 10,
@@ -59,6 +70,7 @@ export function PinnedCard({
flexDirection: "column",
gap: 10,
minWidth: 0,
cursor: canOpen ? "pointer" : "default",
}}
>
<div className="row" style={{ gap: 10 }}>
@@ -66,7 +78,7 @@ export function PinnedCard({
<button
type="button"
aria-label={file.pinned ? "Unpin" : "Pin"}
onClick={onUnpin}
onClick={(event) => { event.stopPropagation(); onUnpin(); }}
style={{ marginLeft: "auto", padding: 4, border: 0, background: "transparent", color: file.pinned ? "var(--accent)" : "var(--text-4)", cursor: "pointer" }}
>
<Icon name="pin" size={14} />
@@ -1,4 +1,5 @@
import { Avatar, IconButton, Pill } from "../../shared/ui";
import { MenuRow, Popover } from "../../shared/Popover";
import type {
AgentRecord,
EmployeeRecord,
@@ -16,12 +17,14 @@ export function FilesTable({
grants,
employees,
agents,
onOpen,
onTogglePin,
}: {
files: FileObjectRecord[];
grants: FileAccessGrantRecord[];
employees: EmployeeRecord[];
agents: AgentRecord[];
onOpen: (file: FileObjectRecord) => void;
onTogglePin: (file: FileObjectRecord) => void;
}) {
return (
@@ -36,6 +39,7 @@ export function FilesTable({
owner={resolveOwnerName(file, employees, agents)}
grantCount={fileGrantCount(file.id, grants)}
last={index === files.length - 1}
onOpen={() => onOpen(file)}
onTogglePin={() => onTogglePin(file)}
/>
))}
@@ -48,17 +52,24 @@ function FileRow({
owner,
grantCount,
last,
onOpen,
onTogglePin,
}: {
file: FileObjectRecord;
owner: string;
grantCount: number;
last: boolean;
onOpen: () => void;
onTogglePin: () => void;
}) {
const canOpen = file.scanState === "approved";
return (
<div
className="table-row"
className={`table-row ${canOpen ? "clickable" : ""}`.trim()}
role={canOpen ? "button" : undefined}
tabIndex={canOpen ? 0 : undefined}
onClick={canOpen ? onOpen : undefined}
onKeyDown={canOpen ? (event) => { if (event.key === "Enter") onOpen(); } : undefined}
style={{ gridTemplateColumns: ROW_COLUMNS, borderBottom: last ? "none" : "1px solid var(--border-soft)" }}
>
<div className="row" style={{ gap: 10, minWidth: 0 }}>
@@ -77,12 +88,19 @@ function FileRow({
<span style={{ color: "var(--text-2)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{owner}</span>
</div>
<div className="row" style={{ gap: 6, minWidth: 0 }}>
<Pill tone={file.scanState === "approved" ? "green" : "red"}>{file.scanState === "approved" ? "Clean" : "Blocked"}</Pill>
<Pill tone={canOpen ? "green" : "red"}>{canOpen ? "Clean" : "Blocked"}</Pill>
<span className="mono" style={{ color: "var(--text-3)", fontSize: 11 }}>{grantCount}</span>
</div>
<div style={{ color: "var(--text-3)", fontSize: 12 }}>{formatRelative(file.updatedAt ?? file.createdAt)}</div>
<div style={{ textAlign: "right" }}>
<IconButton icon={file.pinned ? "pin" : "more"} label={file.pinned ? "Unpin" : "More"} onClick={onTogglePin} />
<div style={{ textAlign: "right" }} onClick={(event) => event.stopPropagation()}>
<Popover trigger={({ toggle }) => <IconButton icon="more" label={`Actions for ${file.name}`} onClick={toggle} />}>
{(close) => (
<>
{canOpen && <MenuRow onClick={() => { onOpen(); close(); }}>Open</MenuRow>}
<MenuRow onClick={() => { onTogglePin(); close(); }}>{file.pinned ? "Unpin" : "Pin"}</MenuRow>
</>
)}
</Popover>
</div>
</div>
);
@@ -519,6 +519,8 @@ textarea.input { min-height: 84px; resize: vertical; line-height: 1.5; }
.table-row:last-child { border-bottom: 0; }
.table-row.clickable { cursor: pointer; }
.table-row.clickable:hover { background: var(--hover); }
.clickable-card { transition: border-color 0.1s ease; }
.clickable-card:hover { border-color: var(--border-strong); }
.link-button {
border: 0;