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
3 changes: 3 additions & 0 deletions canvas/src/components/AuditTrailPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ export function AuditTrailPanel({ workspaceId }: Props) {
<div className="px-4 py-2.5 border-b border-zinc-800/40 flex items-center gap-1 overflow-x-auto shrink-0">
{FILTERS.map((f) => (
<button
type="button"
key={f.id}
onClick={() => setFilter(f.id)}
aria-pressed={filter === f.id}
Expand All @@ -152,6 +153,7 @@ export function AuditTrailPanel({ workspaceId }: Props) {
))}
<div className="flex-1" />
<button
type="button"
onClick={loadEntries}
className="px-2 py-1 text-[10px] bg-zinc-800 hover:bg-zinc-700 text-zinc-400 rounded transition-colors shrink-0"
aria-label="Refresh audit trail"
Expand Down Expand Up @@ -190,6 +192,7 @@ export function AuditTrailPanel({ workspaceId }: Props) {
{cursor && (
<div className="mt-4 flex justify-center">
<button
type="button"
onClick={loadMore}
disabled={loadingMore}
className="px-4 py-2 text-[11px] bg-zinc-800 hover:bg-zinc-700 disabled:opacity-50 disabled:cursor-not-allowed text-zinc-300 rounded-lg transition-colors"
Expand Down
4 changes: 4 additions & 0 deletions canvas/src/components/BatchActionBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export function BatchActionBar() {

{/* Action buttons */}
<button
type="button"
disabled={busy}
onClick={() => setPending("restart")}
className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-[12px] font-medium text-sky-300 bg-sky-900/30 hover:bg-sky-800/50 border border-sky-700/30 hover:border-sky-600/50 transition-colors disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sky-500/70"
Expand All @@ -100,6 +101,7 @@ export function BatchActionBar() {
</button>

<button
type="button"
disabled={busy}
onClick={() => setPending("pause")}
className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-[12px] font-medium text-amber-300 bg-amber-900/30 hover:bg-amber-800/50 border border-amber-700/30 hover:border-amber-600/50 transition-colors disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-amber-500/70"
Expand All @@ -109,6 +111,7 @@ export function BatchActionBar() {
</button>

<button
type="button"
disabled={busy}
onClick={() => setPending("delete")}
className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-[12px] font-medium text-red-300 bg-red-900/30 hover:bg-red-800/50 border border-red-700/30 hover:border-red-600/50 transition-colors disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-500/70"
Expand All @@ -121,6 +124,7 @@ export function BatchActionBar() {

{/* Deselect */}
<button
type="button"
disabled={busy}
onClick={clearSelection}
aria-label="Clear selection"
Expand Down
1 change: 1 addition & 0 deletions canvas/src/components/BundleDropZone.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ export function BundleDropZone() {
{/* Keyboard-accessible import button — visible on focus or hover so
keyboard / AT users can trigger bundle import without drag-and-drop (WCAG 2.1.1) */}
<button
type="button"
onClick={() => fileInputRef.current?.click()}
aria-label="Import bundle file"
aria-controls="bundle-file-input"
Expand Down
2 changes: 2 additions & 0 deletions canvas/src/components/CommunicationOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export function CommunicationOverlay() {
if (!visible || comms.length === 0) {
return (
<button
type="button"
onClick={() => setVisible(true)}
aria-label="Show communications panel"
className="fixed top-16 right-4 z-30 px-3 py-1.5 bg-zinc-900/90 border border-zinc-700/50 rounded-lg text-[10px] text-zinc-400 hover:text-zinc-200 transition-colors"
Expand All @@ -115,6 +116,7 @@ export function CommunicationOverlay() {
<span aria-hidden="true">↗↙ </span>Communications ({comms.length})
</div>
<button
type="button"
onClick={() => setVisible(false)}
aria-label="Close communications panel"
className="text-zinc-500 hover:text-zinc-300 text-xs"
Expand Down
2 changes: 2 additions & 0 deletions canvas/src/components/ConfirmDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,15 @@ export function ConfirmDialog({
<div className="flex items-center justify-end gap-2 px-5 py-3 border-t border-zinc-800 bg-zinc-950/50">
{!singleButton && (
<button
type="button"
onClick={onCancel}
className="px-3.5 py-1.5 text-[13px] text-zinc-400 hover:text-zinc-200 bg-zinc-800 hover:bg-zinc-700 border border-zinc-700 rounded-lg transition-colors"
>
Cancel
</button>
)}
<button
type="button"
onClick={onConfirm}
className={`px-3.5 py-1.5 text-[13px] rounded-lg transition-colors ${confirmColors}`}
>
Expand Down
3 changes: 3 additions & 0 deletions canvas/src/components/ConsoleModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export function ConsoleModal({ workspaceId, workspaceName, open, onClose }: Prop
)}
</div>
<button
type="button"
ref={closeButtonRef}
onClick={onClose}
aria-label="Close"
Expand Down Expand Up @@ -146,6 +147,7 @@ export function ConsoleModal({ workspaceId, workspaceName, open, onClose }: Prop
<div className="flex items-center justify-end gap-2 px-4 py-3 border-t border-zinc-800 bg-zinc-900/40">
{output && (
<button
type="button"
onClick={() => {
if (navigator.clipboard) {
navigator.clipboard.writeText(output);
Expand All @@ -159,6 +161,7 @@ export function ConsoleModal({ workspaceId, workspaceName, open, onClose }: Prop
</button>
)}
<button
type="button"
onClick={onClose}
className="px-3 py-1.5 text-[11px] text-zinc-300 bg-zinc-800 hover:bg-zinc-700 border border-zinc-700 rounded-lg transition-colors"
>
Expand Down
1 change: 1 addition & 0 deletions canvas/src/components/ContextMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ export function ContextMenu() {
}
return (
<button
type="button"
key={i}
role="menuitem"
onClick={item.action}
Expand Down
2 changes: 2 additions & 0 deletions canvas/src/components/ConversationTraceModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ export function ConversationTraceModal({ open, workspaceId: _workspaceId, onClos
</div>
<Dialog.Close asChild>
<button
type="button"
aria-label="Close conversation trace"
className="text-zinc-500 hover:text-zinc-300 text-lg px-2"
>
Expand Down Expand Up @@ -283,6 +284,7 @@ export function ConversationTraceModal({ open, workspaceId: _workspaceId, onClos
<div className="px-5 py-3 border-t border-zinc-800 bg-zinc-950/50 flex justify-end">
<Dialog.Close asChild>
<button
type="button"
className="px-4 py-1.5 text-[12px] bg-zinc-800 hover:bg-zinc-700 text-zinc-300 rounded-lg transition-colors"
>
Close
Expand Down
6 changes: 4 additions & 2 deletions canvas/src/components/CreateWorkspaceDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ export function CreateWorkspaceButton() {
return (
<Dialog.Root open={open} onOpenChange={setOpen}>
<Dialog.Trigger asChild>
<button className="fixed bottom-6 right-6 z-40 px-5 py-2.5 bg-blue-600 hover:bg-blue-500 active:bg-blue-700 text-sm font-medium rounded-xl text-white shadow-lg shadow-blue-600/20 hover:shadow-xl hover:shadow-blue-500/30 transition-all duration-200 flex items-center gap-2">
<button type="button" className="fixed bottom-6 right-6 z-40 px-5 py-2.5 bg-blue-600 hover:bg-blue-500 active:bg-blue-700 text-sm font-medium rounded-xl text-white shadow-lg shadow-blue-600/20 hover:shadow-xl hover:shadow-blue-500/30 transition-all duration-200 flex items-center gap-2">
<svg
width="14"
height="14"
Expand Down Expand Up @@ -284,6 +284,7 @@ export function CreateWorkspaceButton() {
</div>
{TIERS.map((t, idx) => (
<button
type="button"
key={t.value}
ref={(el) => { radioRefs.current[idx] = el; }}
role="radio"
Expand Down Expand Up @@ -432,11 +433,12 @@ export function CreateWorkspaceButton() {

<div className="flex justify-end gap-2.5 mt-6">
<Dialog.Close asChild>
<button className="px-4 py-2 bg-zinc-800 hover:bg-zinc-700 text-sm rounded-lg text-zinc-300 transition-colors">
<button type="button" className="px-4 py-2 bg-zinc-800 hover:bg-zinc-700 text-sm rounded-lg text-zinc-300 transition-colors">
Cancel
</button>
</Dialog.Close>
<button
type="button"
onClick={handleCreate}
disabled={creating}
className="px-5 py-2 bg-blue-600 hover:bg-blue-500 active:bg-blue-700 text-sm rounded-lg text-white disabled:opacity-50 transition-colors"
Expand Down
2 changes: 2 additions & 0 deletions canvas/src/components/DeleteCascadeConfirmDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,14 @@ export function DeleteCascadeConfirmDialog({

<div className="flex items-center justify-end gap-2 px-5 py-3 border-t border-zinc-800 bg-zinc-950/50">
<button
type="button"
onClick={onCancel}
className="px-3.5 py-1.5 text-[13px] text-zinc-400 hover:text-zinc-200 bg-zinc-800 hover:bg-zinc-700 border border-zinc-700 rounded-lg transition-colors"
>
Cancel
</button>
<button
type="button"
onClick={onConfirm}
disabled={!checked}
className={`px-3.5 py-1.5 text-[13px] rounded-lg transition-colors
Expand Down
2 changes: 2 additions & 0 deletions canvas/src/components/EmptyState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export function EmptyState() {
const tierColor = TIER_CONFIG[t.tier]?.border || TIER_CONFIG[1].border;
return (
<button
type="button"
key={t.id}
onClick={() => deploy(t)}
disabled={!!deploying}
Expand Down Expand Up @@ -140,6 +141,7 @@ export function EmptyState() {

{/* Create blank */}
<button
type="button"
onClick={createBlank}
disabled={!!deploying}
className="w-full rounded-xl border border-dashed border-zinc-700/60 bg-zinc-900/30 px-4 py-3 text-sm text-zinc-400 hover:text-zinc-200 hover:border-zinc-600 hover:bg-zinc-900/50 transition-all disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:text-zinc-400 disabled:hover:border-zinc-700/60 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500/70"
Expand Down
2 changes: 2 additions & 0 deletions canvas/src/components/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export class ErrorBoundary extends React.Component<
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<circle cx="12" cy="12" r="10" />
<line x1="12" y1="8" x2="12" y2="12" />
Expand All @@ -80,6 +81,7 @@ export class ErrorBoundary extends React.Component<
</p>
<div className="flex items-center justify-center gap-3">
<button
type="button"
onClick={this.handleReload}
className="rounded-lg bg-blue-600 hover:bg-blue-500 px-5 py-2 text-sm font-medium text-white transition-colors"
>
Expand Down
6 changes: 6 additions & 0 deletions canvas/src/components/MemoryInspectorPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ export function MemoryInspectorPanel({ workspaceId }: Props) {
<div className="flex items-center gap-1">
{SCOPES.map((scope) => (
<button
type="button"
key={scope}
onClick={() => setActiveScope(scope)}
aria-pressed={activeScope === scope}
Expand Down Expand Up @@ -201,6 +202,7 @@ export function MemoryInspectorPanel({ workspaceId }: Props) {
/>
{searchQuery && (
<button
type="button"
onClick={() => {
setSearchQuery("");
setDebouncedQuery("");
Expand Down Expand Up @@ -240,6 +242,7 @@ export function MemoryInspectorPanel({ workspaceId }: Props) {
: `${entries.length} memories`}
</span>
<button
type="button"
onClick={loadEntries}
className="px-2 py-1 text-[11px] bg-zinc-800 hover:bg-zinc-700 text-zinc-300 rounded transition-colors"
aria-label="Refresh memories"
Expand Down Expand Up @@ -273,6 +276,7 @@ export function MemoryInspectorPanel({ workspaceId }: Props) {
<p className="text-[11px] text-zinc-600 max-w-[200px] leading-relaxed">
Try a different query or{" "}
<button
type="button"
onClick={() => {
setSearchQuery("");
setDebouncedQuery("");
Expand Down Expand Up @@ -339,6 +343,7 @@ function MemoryEntryRow({ entry, onDelete }: MemoryEntryRowProps) {
<div className="rounded-lg border border-zinc-800/60 bg-zinc-900/50 overflow-hidden">
{/* Header row */}
<button
type="button"
className="w-full flex items-center gap-2 px-3 py-2.5 text-left hover:bg-zinc-800/30 transition-colors"
onClick={() => setExpanded((prev) => !prev)}
aria-expanded={expanded}
Expand Down Expand Up @@ -409,6 +414,7 @@ function MemoryEntryRow({ entry, onDelete }: MemoryEntryRowProps) {
Created: {new Date(entry.created_at).toLocaleString()}
</span>
<button
type="button"
onClick={(e) => {
e.stopPropagation();
onDelete();
Expand Down
4 changes: 4 additions & 0 deletions canvas/src/components/MissingKeysModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,7 @@ function AllKeysModal({
className="flex-1 bg-zinc-900 border border-zinc-600 rounded px-2 py-1.5 text-[11px] text-zinc-100 font-mono focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500/20 transition-colors"
/>
<button
type="button"
onClick={() => handleSaveKey(index)}
disabled={!entry.value.trim() || entry.saving}
className="px-3 py-1.5 bg-blue-600 hover:bg-blue-500 text-[11px] rounded text-white disabled:opacity-30 transition-colors shrink-0"
Expand All @@ -580,6 +581,7 @@ function AllKeysModal({
<div>
{onOpenSettings && (
<button
type="button"
onClick={onOpenSettings}
className="text-[11px] text-blue-400 hover:text-blue-300 transition-colors"
>
Expand All @@ -589,12 +591,14 @@ function AllKeysModal({
</div>
<div className="flex items-center gap-2">
<button
type="button"
onClick={onCancel}
className="px-3.5 py-1.5 text-[12px] text-zinc-400 hover:text-zinc-200 bg-zinc-800 hover:bg-zinc-700 border border-zinc-700 rounded-lg transition-colors"
>
Cancel Deploy
</button>
<button
type="button"
onClick={handleAddKeysAndDeploy}
disabled={!allSaved || anySaving}
className="px-3.5 py-1.5 text-[12px] bg-blue-600 hover:bg-blue-500 text-white rounded-lg transition-colors disabled:opacity-40"
Expand Down
3 changes: 3 additions & 0 deletions canvas/src/components/OnboardingWizard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ export function OnboardingWizard() {
Step {currentStepIdx + 1} of {STEPS.length}
</span>
<button
type="button"
onClick={dismiss}
aria-label="Skip onboarding guide"
className="text-[10px] text-zinc-400 hover:text-zinc-200 transition-colors"
Expand All @@ -178,6 +179,7 @@ export function OnboardingWizard() {
{/* Action button */}
<div className="flex gap-2">
<button
type="button"
onClick={handleAction}
className="flex-1 px-3 py-1.5 bg-blue-600/90 hover:bg-blue-500 rounded-lg text-[11px] font-medium text-white transition-colors"
>
Expand All @@ -191,6 +193,7 @@ export function OnboardingWizard() {
</button>
{step !== "done" && (
<button
type="button"
onClick={() => {
const next = STEPS[currentStepIdx + 1];
if (next) setStep(next.id);
Expand Down
5 changes: 5 additions & 0 deletions canvas/src/components/ProvisioningTimeout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -284,20 +284,23 @@ export function ProvisioningTimeout({
{/* Action buttons */}
<div className="flex items-center gap-2 mt-2.5">
<button
type="button"
onClick={() => handleRetry(entry.workspaceId)}
disabled={isRetrying || isCancelling || retryCooldown.has(entry.workspaceId)}
className="px-3 py-1.5 bg-amber-600 hover:bg-amber-500 text-[11px] font-medium rounded-lg text-white disabled:opacity-40 transition-colors"
>
{isRetrying ? "Retrying..." : retryCooldown.has(entry.workspaceId) ? "Wait..." : "Retry"}
</button>
<button
type="button"
onClick={() => handleCancelRequest(entry.workspaceId)}
disabled={isRetrying || isCancelling}
className="px-3 py-1.5 bg-zinc-800 hover:bg-zinc-700 text-[11px] text-zinc-300 rounded-lg border border-zinc-600 disabled:opacity-40 transition-colors"
>
{isCancelling ? "Cancelling..." : "Cancel"}
</button>
<button
type="button"
onClick={() => handleViewLogs(entry.workspaceId)}
className="px-3 py-1.5 text-[11px] text-amber-400 hover:text-amber-300 transition-colors"
>
Expand All @@ -323,12 +326,14 @@ export function ProvisioningTimeout({
</p>
<div className="flex justify-end gap-2">
<button
type="button"
onClick={() => setConfirmingCancel(null)}
className="px-3.5 py-1.5 text-[12px] text-zinc-400 hover:text-zinc-200 bg-zinc-800 hover:bg-zinc-700 border border-zinc-700 rounded-lg transition-colors"
>
Keep
</button>
<button
type="button"
onClick={handleCancelConfirm}
className="px-3.5 py-1.5 text-[12px] bg-red-600 hover:bg-red-500 text-white rounded-lg transition-colors"
>
Expand Down
1 change: 1 addition & 0 deletions canvas/src/components/SearchDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ export function SearchDialog() {
) : (
filtered.map((node, index) => (
<button
type="button"
key={node.id}
id={`search-result-${node.id}`}
role="option"
Expand Down
3 changes: 3 additions & 0 deletions canvas/src/components/SidePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ export function SidePanel() {
</div>
</div>
<button
type="button"
onClick={() => selectNode(null)}
aria-label="Close workspace panel"
className="w-7 h-7 flex items-center justify-center rounded-lg text-zinc-500 hover:text-zinc-200 hover:bg-zinc-800/60 transition-colors"
Expand Down Expand Up @@ -221,6 +222,7 @@ export function SidePanel() {
>
{TABS.map((tab) => (
<button
type="button"
key={tab.id}
id={`tab-${tab.id}`}
role="tab"
Expand All @@ -246,6 +248,7 @@ export function SidePanel() {
<div className="px-4 py-2 bg-sky-950/20 border-b border-sky-800/20 flex items-center justify-between">
<span className="text-[10px] text-sky-300/90">Config changed — restart to apply</span>
<button
type="button"
onClick={() => {
useCanvasStore.getState().restartWorkspace(selectedNodeId).catch(() => showToast("Restart failed", "error"));
}}
Expand Down
Loading
Loading