@tangle-network/sandbox-ui 0.10.0 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chat.js +3 -3
- package/dist/{chunk-QC4BJEG6.js → chunk-A5ALUT2B.js} +529 -3
- package/dist/{chunk-EXSOPXIY.js → chunk-QOL4ZB24.js} +205 -39
- package/dist/{chunk-JLKYXLFN.js → chunk-WKSGQVLI.js} +22 -22
- package/dist/{chunk-PLTZB5BC.js → chunk-ZNCEM5CD.js} +47 -21
- package/dist/globals.css +144 -28
- package/dist/index.d.ts +1 -1
- package/dist/index.js +10 -4
- package/dist/openui.js +1 -1
- package/dist/run.js +5 -1
- package/dist/styles.css +144 -28
- package/dist/workspace.d.ts +134 -1
- package/dist/workspace.js +10 -4
- package/package.json +1 -1
package/dist/chat.js
CHANGED
|
@@ -8,13 +8,13 @@ import {
|
|
|
8
8
|
MessageList,
|
|
9
9
|
ThinkingIndicator,
|
|
10
10
|
UserMessage
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-WKSGQVLI.js";
|
|
12
12
|
import "./chunk-54SQQMMM.js";
|
|
13
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-QOL4ZB24.js";
|
|
14
14
|
import "./chunk-HRMUF35V.js";
|
|
15
15
|
import "./chunk-MT5FJ3ZT.js";
|
|
16
16
|
import "./chunk-BX6AQMUS.js";
|
|
17
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-ZNCEM5CD.js";
|
|
18
18
|
import "./chunk-34I7UFSX.js";
|
|
19
19
|
import "./chunk-T7HMZEVO.js";
|
|
20
20
|
import "./chunk-ZMNSRDMH.js";
|
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
} from "./chunk-MA7YKRUP.js";
|
|
11
11
|
import {
|
|
12
12
|
ChatContainer
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-WKSGQVLI.js";
|
|
14
14
|
import {
|
|
15
15
|
OpenUIArtifactRenderer
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-ZNCEM5CD.js";
|
|
17
17
|
import {
|
|
18
18
|
FileArtifactPane,
|
|
19
19
|
FileTree,
|
|
@@ -1656,6 +1656,529 @@ function CheckRow({ check }) {
|
|
|
1656
1656
|
] });
|
|
1657
1657
|
}
|
|
1658
1658
|
|
|
1659
|
+
// src/workspace/task-board.tsx
|
|
1660
|
+
import { useMemo as useMemo5 } from "react";
|
|
1661
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1662
|
+
function TaskBoard({
|
|
1663
|
+
items,
|
|
1664
|
+
columns,
|
|
1665
|
+
className,
|
|
1666
|
+
onMoveItem,
|
|
1667
|
+
onClickItem,
|
|
1668
|
+
renderItemMeta,
|
|
1669
|
+
renderColumnAction,
|
|
1670
|
+
renderBadge,
|
|
1671
|
+
columnEmptyState,
|
|
1672
|
+
header
|
|
1673
|
+
}) {
|
|
1674
|
+
const grouped = useMemo5(() => {
|
|
1675
|
+
const map = /* @__PURE__ */ new Map();
|
|
1676
|
+
for (const col of columns) map.set(col.id, []);
|
|
1677
|
+
for (const item of items) {
|
|
1678
|
+
const list = map.get(item.status);
|
|
1679
|
+
if (list) list.push(item);
|
|
1680
|
+
else map.get(columns[columns.length - 1]?.id)?.push(item);
|
|
1681
|
+
}
|
|
1682
|
+
return map;
|
|
1683
|
+
}, [items, columns]);
|
|
1684
|
+
return /* @__PURE__ */ jsxs11("div", { className: cn("flex flex-1 flex-col overflow-hidden", className), children: [
|
|
1685
|
+
header,
|
|
1686
|
+
/* @__PURE__ */ jsx11("div", { className: "flex flex-1 gap-3 overflow-x-auto p-4", children: columns.map((col) => {
|
|
1687
|
+
const colItems = grouped.get(col.id) ?? [];
|
|
1688
|
+
return /* @__PURE__ */ jsxs11(
|
|
1689
|
+
"div",
|
|
1690
|
+
{
|
|
1691
|
+
className: cn(
|
|
1692
|
+
"flex w-72 shrink-0 flex-col rounded-xl border border-border bg-card/50 border-t-2",
|
|
1693
|
+
col.accent ?? "border-t-muted-foreground/30"
|
|
1694
|
+
),
|
|
1695
|
+
children: [
|
|
1696
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between px-4 py-3", children: [
|
|
1697
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2", children: [
|
|
1698
|
+
/* @__PURE__ */ jsx11("h3", { className: "text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: col.label }),
|
|
1699
|
+
/* @__PURE__ */ jsx11("span", { className: "inline-flex h-5 min-w-[20px] items-center justify-center rounded-full border border-border px-1.5 text-[10px] font-medium text-muted-foreground", children: colItems.length })
|
|
1700
|
+
] }),
|
|
1701
|
+
renderColumnAction?.(col)
|
|
1702
|
+
] }),
|
|
1703
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex flex-1 flex-col gap-2 overflow-y-auto px-2 pb-2 min-h-[80px]", children: [
|
|
1704
|
+
colItems.length === 0 && columnEmptyState,
|
|
1705
|
+
colItems.map((item) => /* @__PURE__ */ jsxs11(
|
|
1706
|
+
"button",
|
|
1707
|
+
{
|
|
1708
|
+
type: "button",
|
|
1709
|
+
onClick: () => onClickItem?.(item),
|
|
1710
|
+
className: "group w-full rounded-lg border border-border bg-card p-3 text-left transition-colors hover:border-accent/50",
|
|
1711
|
+
children: [
|
|
1712
|
+
/* @__PURE__ */ jsx11("p", { className: "text-sm font-medium text-foreground", children: item.title }),
|
|
1713
|
+
item.description && /* @__PURE__ */ jsx11("p", { className: "mt-1 text-xs text-muted-foreground line-clamp-2", children: item.description }),
|
|
1714
|
+
(item.priority || item.tags?.length) && /* @__PURE__ */ jsxs11("div", { className: "mt-2 flex flex-wrap gap-1.5", children: [
|
|
1715
|
+
item.priority && (renderBadge ? renderBadge(item.priority, "priority") : /* @__PURE__ */ jsx11("span", { className: "rounded-full border border-border px-2 py-0.5 text-[10px] font-medium text-muted-foreground", children: item.priority })),
|
|
1716
|
+
item.tags?.map(
|
|
1717
|
+
(tag) => renderBadge ? /* @__PURE__ */ jsx11("span", { children: renderBadge(tag, "tag") }, tag) : /* @__PURE__ */ jsx11(
|
|
1718
|
+
"span",
|
|
1719
|
+
{
|
|
1720
|
+
className: "rounded-full border border-border px-2 py-0.5 text-[10px] text-muted-foreground",
|
|
1721
|
+
children: tag
|
|
1722
|
+
},
|
|
1723
|
+
tag
|
|
1724
|
+
)
|
|
1725
|
+
)
|
|
1726
|
+
] }),
|
|
1727
|
+
renderItemMeta?.(item)
|
|
1728
|
+
]
|
|
1729
|
+
},
|
|
1730
|
+
item.id
|
|
1731
|
+
))
|
|
1732
|
+
] })
|
|
1733
|
+
]
|
|
1734
|
+
},
|
|
1735
|
+
col.id
|
|
1736
|
+
);
|
|
1737
|
+
}) })
|
|
1738
|
+
] });
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
// src/workspace/calendar-view.tsx
|
|
1742
|
+
import { useState as useState6, useMemo as useMemo6 } from "react";
|
|
1743
|
+
import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1744
|
+
function toDateKey(d) {
|
|
1745
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
1746
|
+
}
|
|
1747
|
+
function getMonthDays(year, month) {
|
|
1748
|
+
const first = new Date(year, month, 1);
|
|
1749
|
+
const startDay = first.getDay();
|
|
1750
|
+
const days = [];
|
|
1751
|
+
for (let i = startDay - 1; i >= 0; i--) {
|
|
1752
|
+
const d = new Date(year, month, -i);
|
|
1753
|
+
days.push({ date: d, key: toDateKey(d), inMonth: false });
|
|
1754
|
+
}
|
|
1755
|
+
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
|
1756
|
+
for (let i = 1; i <= daysInMonth; i++) {
|
|
1757
|
+
const d = new Date(year, month, i);
|
|
1758
|
+
days.push({ date: d, key: toDateKey(d), inMonth: true });
|
|
1759
|
+
}
|
|
1760
|
+
const remaining = 7 - days.length % 7;
|
|
1761
|
+
if (remaining < 7) {
|
|
1762
|
+
for (let i = 1; i <= remaining; i++) {
|
|
1763
|
+
const d = new Date(year, month + 1, i);
|
|
1764
|
+
days.push({ date: d, key: toDateKey(d), inMonth: false });
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
return days;
|
|
1768
|
+
}
|
|
1769
|
+
function CalendarView({
|
|
1770
|
+
events,
|
|
1771
|
+
className,
|
|
1772
|
+
month: controlledMonth,
|
|
1773
|
+
year: controlledYear,
|
|
1774
|
+
onMonthChange,
|
|
1775
|
+
selectedDay: controlledSelectedDay,
|
|
1776
|
+
onSelectDay,
|
|
1777
|
+
onDoubleClickDay,
|
|
1778
|
+
renderEventChip,
|
|
1779
|
+
renderDayDetail,
|
|
1780
|
+
headerLeft,
|
|
1781
|
+
headerRight,
|
|
1782
|
+
showDayPanel = true
|
|
1783
|
+
}) {
|
|
1784
|
+
const today = /* @__PURE__ */ new Date();
|
|
1785
|
+
const todayKey = toDateKey(today);
|
|
1786
|
+
const [internalMonth, setInternalMonth] = useState6({
|
|
1787
|
+
year: today.getFullYear(),
|
|
1788
|
+
month: today.getMonth()
|
|
1789
|
+
});
|
|
1790
|
+
const [internalSelectedDay, setInternalSelectedDay] = useState6(
|
|
1791
|
+
todayKey
|
|
1792
|
+
);
|
|
1793
|
+
const viewYear = controlledYear ?? internalMonth.year;
|
|
1794
|
+
const viewMonth = controlledMonth ?? internalMonth.month;
|
|
1795
|
+
const selectedDay = controlledSelectedDay ?? internalSelectedDay;
|
|
1796
|
+
function setMonth(y, m) {
|
|
1797
|
+
if (onMonthChange) onMonthChange(y, m);
|
|
1798
|
+
else setInternalMonth({ year: y, month: m });
|
|
1799
|
+
}
|
|
1800
|
+
function selectDay(key) {
|
|
1801
|
+
if (onSelectDay) onSelectDay(key);
|
|
1802
|
+
else setInternalSelectedDay(key);
|
|
1803
|
+
}
|
|
1804
|
+
function prevMonth() {
|
|
1805
|
+
const m = viewMonth === 0 ? 11 : viewMonth - 1;
|
|
1806
|
+
const y = viewMonth === 0 ? viewYear - 1 : viewYear;
|
|
1807
|
+
setMonth(y, m);
|
|
1808
|
+
}
|
|
1809
|
+
function nextMonth() {
|
|
1810
|
+
const m = viewMonth === 11 ? 0 : viewMonth + 1;
|
|
1811
|
+
const y = viewMonth === 11 ? viewYear + 1 : viewYear;
|
|
1812
|
+
setMonth(y, m);
|
|
1813
|
+
}
|
|
1814
|
+
const eventsByDate = useMemo6(() => {
|
|
1815
|
+
const map = {};
|
|
1816
|
+
for (const evt of events) {
|
|
1817
|
+
const d = typeof evt.startAt === "string" ? evt.startAt.slice(0, 10) : toDateKey(evt.startAt);
|
|
1818
|
+
if (!map[d]) map[d] = [];
|
|
1819
|
+
map[d].push(evt);
|
|
1820
|
+
}
|
|
1821
|
+
return map;
|
|
1822
|
+
}, [events]);
|
|
1823
|
+
const monthDays = useMemo6(
|
|
1824
|
+
() => getMonthDays(viewYear, viewMonth),
|
|
1825
|
+
[viewYear, viewMonth]
|
|
1826
|
+
);
|
|
1827
|
+
const monthLabel = new Date(viewYear, viewMonth).toLocaleString("en-US", {
|
|
1828
|
+
month: "long",
|
|
1829
|
+
year: "numeric"
|
|
1830
|
+
});
|
|
1831
|
+
const selectedDayEvents = selectedDay ? eventsByDate[selectedDay] ?? [] : [];
|
|
1832
|
+
return /* @__PURE__ */ jsxs12("div", { className: cn("flex flex-1 min-h-0 overflow-hidden", className), children: [
|
|
1833
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex-1 flex flex-col overflow-hidden border-r border-border", children: [
|
|
1834
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-between border-b border-border px-4 py-2.5 shrink-0", children: [
|
|
1835
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2", children: [
|
|
1836
|
+
headerLeft,
|
|
1837
|
+
/* @__PURE__ */ jsx12(
|
|
1838
|
+
"button",
|
|
1839
|
+
{
|
|
1840
|
+
type: "button",
|
|
1841
|
+
onClick: prevMonth,
|
|
1842
|
+
className: "h-7 w-7 rounded-md hover:bg-muted flex items-center justify-center text-muted-foreground",
|
|
1843
|
+
children: /* @__PURE__ */ jsx12("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx12("path", { d: "m15 18-6-6 6-6" }) })
|
|
1844
|
+
}
|
|
1845
|
+
),
|
|
1846
|
+
/* @__PURE__ */ jsx12("span", { className: "text-sm font-semibold text-foreground min-w-[160px] text-center", children: monthLabel }),
|
|
1847
|
+
/* @__PURE__ */ jsx12(
|
|
1848
|
+
"button",
|
|
1849
|
+
{
|
|
1850
|
+
type: "button",
|
|
1851
|
+
onClick: nextMonth,
|
|
1852
|
+
className: "h-7 w-7 rounded-md hover:bg-muted flex items-center justify-center text-muted-foreground",
|
|
1853
|
+
children: /* @__PURE__ */ jsx12("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx12("path", { d: "m9 18 6-6-6-6" }) })
|
|
1854
|
+
}
|
|
1855
|
+
),
|
|
1856
|
+
/* @__PURE__ */ jsx12(
|
|
1857
|
+
"button",
|
|
1858
|
+
{
|
|
1859
|
+
type: "button",
|
|
1860
|
+
onClick: () => {
|
|
1861
|
+
setMonth(today.getFullYear(), today.getMonth());
|
|
1862
|
+
selectDay(todayKey);
|
|
1863
|
+
},
|
|
1864
|
+
className: "h-7 px-2 rounded-md border border-border text-xs font-medium text-muted-foreground hover:text-foreground",
|
|
1865
|
+
children: "Today"
|
|
1866
|
+
}
|
|
1867
|
+
)
|
|
1868
|
+
] }),
|
|
1869
|
+
headerRight
|
|
1870
|
+
] }),
|
|
1871
|
+
/* @__PURE__ */ jsx12("div", { className: "grid grid-cols-7 border-b border-border shrink-0", children: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"].map((d) => /* @__PURE__ */ jsx12(
|
|
1872
|
+
"div",
|
|
1873
|
+
{
|
|
1874
|
+
className: "px-2 py-1.5 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground text-center",
|
|
1875
|
+
children: d
|
|
1876
|
+
},
|
|
1877
|
+
d
|
|
1878
|
+
)) }),
|
|
1879
|
+
/* @__PURE__ */ jsx12("div", { className: "flex-1 grid grid-cols-7 auto-rows-fr overflow-y-auto", children: monthDays.map(({ date, key, inMonth }) => {
|
|
1880
|
+
const dayEvents = eventsByDate[key] ?? [];
|
|
1881
|
+
const isToday = key === todayKey;
|
|
1882
|
+
const isSelected = key === selectedDay;
|
|
1883
|
+
return /* @__PURE__ */ jsxs12(
|
|
1884
|
+
"button",
|
|
1885
|
+
{
|
|
1886
|
+
type: "button",
|
|
1887
|
+
onClick: () => selectDay(key),
|
|
1888
|
+
onDoubleClick: () => onDoubleClickDay?.(key),
|
|
1889
|
+
className: cn(
|
|
1890
|
+
"flex flex-col items-start p-1.5 border-b border-r border-border text-left transition-colors min-h-[72px]",
|
|
1891
|
+
!inMonth && "bg-muted/30",
|
|
1892
|
+
isSelected && "bg-primary/5 ring-1 ring-inset ring-primary/20",
|
|
1893
|
+
!isSelected && "hover:bg-muted/50"
|
|
1894
|
+
),
|
|
1895
|
+
children: [
|
|
1896
|
+
/* @__PURE__ */ jsx12(
|
|
1897
|
+
"span",
|
|
1898
|
+
{
|
|
1899
|
+
className: cn(
|
|
1900
|
+
"text-xs font-medium w-6 h-6 flex items-center justify-center rounded-full mb-0.5",
|
|
1901
|
+
isToday && "bg-primary text-primary-foreground",
|
|
1902
|
+
!isToday && !inMonth && "text-muted-foreground/50",
|
|
1903
|
+
!isToday && inMonth && "text-foreground"
|
|
1904
|
+
),
|
|
1905
|
+
children: date.getDate()
|
|
1906
|
+
}
|
|
1907
|
+
),
|
|
1908
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap gap-0.5 w-full", children: [
|
|
1909
|
+
dayEvents.slice(0, 3).map(
|
|
1910
|
+
(evt) => renderEventChip ? /* @__PURE__ */ jsx12("span", { children: renderEventChip(evt) }, evt.id) : /* @__PURE__ */ jsx12(
|
|
1911
|
+
"div",
|
|
1912
|
+
{
|
|
1913
|
+
className: "w-full truncate text-[9px] px-1 py-0.5 rounded bg-primary/10 text-primary",
|
|
1914
|
+
title: evt.title,
|
|
1915
|
+
children: evt.title
|
|
1916
|
+
},
|
|
1917
|
+
evt.id
|
|
1918
|
+
)
|
|
1919
|
+
),
|
|
1920
|
+
dayEvents.length > 3 && /* @__PURE__ */ jsxs12("span", { className: "text-[9px] text-muted-foreground px-1", children: [
|
|
1921
|
+
"+",
|
|
1922
|
+
dayEvents.length - 3,
|
|
1923
|
+
" more"
|
|
1924
|
+
] })
|
|
1925
|
+
] })
|
|
1926
|
+
]
|
|
1927
|
+
},
|
|
1928
|
+
key
|
|
1929
|
+
);
|
|
1930
|
+
}) })
|
|
1931
|
+
] }),
|
|
1932
|
+
showDayPanel && /* @__PURE__ */ jsx12("div", { className: "w-80 shrink-0 flex flex-col overflow-hidden", children: renderDayDetail ? renderDayDetail(selectedDay ?? todayKey, selectedDayEvents) : /* @__PURE__ */ jsxs12(Fragment2, { children: [
|
|
1933
|
+
/* @__PURE__ */ jsxs12("div", { className: "px-4 py-3 border-b border-border shrink-0", children: [
|
|
1934
|
+
/* @__PURE__ */ jsx12("h3", { className: "text-sm font-semibold text-foreground", children: selectedDay === todayKey ? "Today" : selectedDay ? (/* @__PURE__ */ new Date(selectedDay + "T00:00:00")).toLocaleDateString(
|
|
1935
|
+
"en-US",
|
|
1936
|
+
{ weekday: "long", month: "long", day: "numeric" }
|
|
1937
|
+
) : "Select a day" }),
|
|
1938
|
+
/* @__PURE__ */ jsxs12("p", { className: "text-xs text-muted-foreground", children: [
|
|
1939
|
+
selectedDayEvents.length,
|
|
1940
|
+
" event",
|
|
1941
|
+
selectedDayEvents.length !== 1 ? "s" : ""
|
|
1942
|
+
] })
|
|
1943
|
+
] }),
|
|
1944
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex-1 overflow-y-auto p-2 space-y-2", children: [
|
|
1945
|
+
selectedDayEvents.length === 0 && /* @__PURE__ */ jsx12("div", { className: "px-2 py-8 text-center", children: /* @__PURE__ */ jsx12("p", { className: "text-xs text-muted-foreground", children: "No events this day" }) }),
|
|
1946
|
+
selectedDayEvents.map((evt) => /* @__PURE__ */ jsxs12(
|
|
1947
|
+
"div",
|
|
1948
|
+
{
|
|
1949
|
+
className: "rounded-lg border border-border bg-card p-3",
|
|
1950
|
+
children: [
|
|
1951
|
+
/* @__PURE__ */ jsx12("p", { className: "text-sm font-medium text-foreground", children: evt.title }),
|
|
1952
|
+
evt.type && /* @__PURE__ */ jsx12("span", { className: "mt-1 inline-block rounded-full border border-border px-2 py-0.5 text-[10px] text-muted-foreground", children: evt.type })
|
|
1953
|
+
]
|
|
1954
|
+
},
|
|
1955
|
+
evt.id
|
|
1956
|
+
))
|
|
1957
|
+
] })
|
|
1958
|
+
] }) })
|
|
1959
|
+
] });
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
// src/workspace/approval-queue.tsx
|
|
1963
|
+
import { useState as useState7, useMemo as useMemo7 } from "react";
|
|
1964
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1965
|
+
function ApprovalQueue({
|
|
1966
|
+
items,
|
|
1967
|
+
className,
|
|
1968
|
+
onApprove,
|
|
1969
|
+
onReject,
|
|
1970
|
+
renderItemDetail,
|
|
1971
|
+
renderTypeBadge,
|
|
1972
|
+
renderStats,
|
|
1973
|
+
canResolve = true,
|
|
1974
|
+
header,
|
|
1975
|
+
emptyState,
|
|
1976
|
+
showResolved: controlledShowResolved
|
|
1977
|
+
}) {
|
|
1978
|
+
const [rejectingId, setRejectingId] = useState7(null);
|
|
1979
|
+
const [rejectReason, setRejectReason] = useState7("");
|
|
1980
|
+
const [showResolved, setShowResolved] = useState7(controlledShowResolved ?? false);
|
|
1981
|
+
const pending = useMemo7(
|
|
1982
|
+
() => items.filter((a) => a.status === "pending"),
|
|
1983
|
+
[items]
|
|
1984
|
+
);
|
|
1985
|
+
const resolved = useMemo7(
|
|
1986
|
+
() => items.filter((a) => a.status !== "pending"),
|
|
1987
|
+
[items]
|
|
1988
|
+
);
|
|
1989
|
+
const stats = useMemo7(() => {
|
|
1990
|
+
const map = {};
|
|
1991
|
+
for (const item of items) {
|
|
1992
|
+
if (!map[item.type])
|
|
1993
|
+
map[item.type] = { type: item.type, approved: 0, rejected: 0, total: 0, rate: 0 };
|
|
1994
|
+
map[item.type].total++;
|
|
1995
|
+
if (item.status === "approved" || item.status === "executed")
|
|
1996
|
+
map[item.type].approved++;
|
|
1997
|
+
if (item.status === "rejected") map[item.type].rejected++;
|
|
1998
|
+
}
|
|
1999
|
+
for (const s of Object.values(map)) {
|
|
2000
|
+
s.rate = s.total > 0 ? Math.round(s.approved / s.total * 100) : 0;
|
|
2001
|
+
}
|
|
2002
|
+
return Object.values(map);
|
|
2003
|
+
}, [items]);
|
|
2004
|
+
if (items.length === 0) {
|
|
2005
|
+
return /* @__PURE__ */ jsx13("div", { className: cn("flex-1 flex items-center justify-center", className), children: emptyState ?? /* @__PURE__ */ jsx13("div", { className: "text-center py-20", children: /* @__PURE__ */ jsx13("p", { className: "text-sm text-muted-foreground", children: "No proposals yet" }) }) });
|
|
2006
|
+
}
|
|
2007
|
+
return /* @__PURE__ */ jsx13("div", { className: cn("flex-1 overflow-y-auto", className), children: /* @__PURE__ */ jsxs13("div", { className: "max-w-3xl mx-auto p-6", children: [
|
|
2008
|
+
header,
|
|
2009
|
+
stats.length > 0 && /* @__PURE__ */ jsx13("div", { className: "flex gap-3 mb-6 flex-wrap", children: renderStats ? renderStats(stats) : stats.map((s) => /* @__PURE__ */ jsxs13(
|
|
2010
|
+
"div",
|
|
2011
|
+
{
|
|
2012
|
+
className: "flex-1 min-w-[120px] rounded-lg border border-border bg-card p-3",
|
|
2013
|
+
children: [
|
|
2014
|
+
/* @__PURE__ */ jsx13("div", { className: "flex items-center gap-2 mb-1", children: renderTypeBadge ? renderTypeBadge(s.type) : /* @__PURE__ */ jsx13("span", { className: "rounded-full border border-border px-2 py-0.5 text-[10px] font-medium text-muted-foreground", children: s.type }) }),
|
|
2015
|
+
/* @__PURE__ */ jsx13("div", { className: "flex items-baseline gap-1", children: /* @__PURE__ */ jsxs13("span", { className: "text-xl font-semibold text-foreground", children: [
|
|
2016
|
+
s.rate,
|
|
2017
|
+
"%"
|
|
2018
|
+
] }) }),
|
|
2019
|
+
/* @__PURE__ */ jsxs13("p", { className: "text-[10px] text-muted-foreground", children: [
|
|
2020
|
+
s.approved,
|
|
2021
|
+
"/",
|
|
2022
|
+
s.total,
|
|
2023
|
+
" approved"
|
|
2024
|
+
] })
|
|
2025
|
+
]
|
|
2026
|
+
},
|
|
2027
|
+
s.type
|
|
2028
|
+
)) }),
|
|
2029
|
+
pending.length > 0 && /* @__PURE__ */ jsxs13("section", { className: "mb-8", children: [
|
|
2030
|
+
/* @__PURE__ */ jsxs13("h3", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wider mb-3", children: [
|
|
2031
|
+
"Pending (",
|
|
2032
|
+
pending.length,
|
|
2033
|
+
")"
|
|
2034
|
+
] }),
|
|
2035
|
+
/* @__PURE__ */ jsx13("div", { className: "space-y-3", children: pending.map((item) => /* @__PURE__ */ jsxs13(
|
|
2036
|
+
"div",
|
|
2037
|
+
{
|
|
2038
|
+
className: "rounded-lg border border-primary/20 bg-card p-4",
|
|
2039
|
+
children: [
|
|
2040
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex items-start gap-3", children: [
|
|
2041
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex-1 min-w-0", children: [
|
|
2042
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2 mb-1", children: [
|
|
2043
|
+
/* @__PURE__ */ jsx13("h4", { className: "text-sm font-medium text-foreground", children: item.title }),
|
|
2044
|
+
renderTypeBadge ? renderTypeBadge(item.type) : /* @__PURE__ */ jsx13("span", { className: "rounded-full border border-border px-2 py-0.5 text-[10px] text-muted-foreground", children: item.type })
|
|
2045
|
+
] }),
|
|
2046
|
+
item.description && /* @__PURE__ */ jsx13("p", { className: "text-xs text-muted-foreground line-clamp-2", children: item.description }),
|
|
2047
|
+
renderItemDetail?.(item)
|
|
2048
|
+
] }),
|
|
2049
|
+
canResolve && /* @__PURE__ */ jsxs13("div", { className: "flex gap-1.5 shrink-0", children: [
|
|
2050
|
+
/* @__PURE__ */ jsx13(
|
|
2051
|
+
"button",
|
|
2052
|
+
{
|
|
2053
|
+
type: "button",
|
|
2054
|
+
onClick: () => onApprove?.(item),
|
|
2055
|
+
className: "h-8 px-3 rounded-md border border-border text-xs font-medium text-emerald-500 hover:bg-emerald-500/10 hover:border-emerald-500/30 transition-colors",
|
|
2056
|
+
children: "Approve"
|
|
2057
|
+
}
|
|
2058
|
+
),
|
|
2059
|
+
/* @__PURE__ */ jsx13(
|
|
2060
|
+
"button",
|
|
2061
|
+
{
|
|
2062
|
+
type: "button",
|
|
2063
|
+
onClick: () => {
|
|
2064
|
+
setRejectingId(
|
|
2065
|
+
rejectingId === item.id ? null : item.id
|
|
2066
|
+
);
|
|
2067
|
+
setRejectReason("");
|
|
2068
|
+
},
|
|
2069
|
+
className: "h-8 px-3 rounded-md border border-border text-xs font-medium text-destructive hover:bg-destructive/10 hover:border-destructive/30 transition-colors",
|
|
2070
|
+
children: "Reject"
|
|
2071
|
+
}
|
|
2072
|
+
)
|
|
2073
|
+
] })
|
|
2074
|
+
] }),
|
|
2075
|
+
rejectingId === item.id && /* @__PURE__ */ jsxs13("div", { className: "mt-3 border-t border-border pt-3", children: [
|
|
2076
|
+
/* @__PURE__ */ jsx13(
|
|
2077
|
+
"textarea",
|
|
2078
|
+
{
|
|
2079
|
+
placeholder: "Why are you rejecting this?",
|
|
2080
|
+
value: rejectReason,
|
|
2081
|
+
onChange: (e) => setRejectReason(e.target.value),
|
|
2082
|
+
className: "w-full rounded-md border border-border bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-primary/40 mb-2",
|
|
2083
|
+
rows: 2
|
|
2084
|
+
}
|
|
2085
|
+
),
|
|
2086
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex gap-2 justify-end", children: [
|
|
2087
|
+
/* @__PURE__ */ jsx13(
|
|
2088
|
+
"button",
|
|
2089
|
+
{
|
|
2090
|
+
type: "button",
|
|
2091
|
+
onClick: () => {
|
|
2092
|
+
setRejectingId(null);
|
|
2093
|
+
setRejectReason("");
|
|
2094
|
+
},
|
|
2095
|
+
className: "h-7 px-3 rounded-md text-xs text-muted-foreground hover:text-foreground",
|
|
2096
|
+
children: "Cancel"
|
|
2097
|
+
}
|
|
2098
|
+
),
|
|
2099
|
+
/* @__PURE__ */ jsx13(
|
|
2100
|
+
"button",
|
|
2101
|
+
{
|
|
2102
|
+
type: "button",
|
|
2103
|
+
onClick: () => {
|
|
2104
|
+
onReject?.(item, rejectReason.trim() || void 0);
|
|
2105
|
+
setRejectingId(null);
|
|
2106
|
+
setRejectReason("");
|
|
2107
|
+
},
|
|
2108
|
+
className: "h-7 px-3 rounded-md bg-destructive text-destructive-foreground text-xs font-medium",
|
|
2109
|
+
children: "Submit Rejection"
|
|
2110
|
+
}
|
|
2111
|
+
)
|
|
2112
|
+
] })
|
|
2113
|
+
] })
|
|
2114
|
+
]
|
|
2115
|
+
},
|
|
2116
|
+
item.id
|
|
2117
|
+
)) })
|
|
2118
|
+
] }),
|
|
2119
|
+
resolved.length > 0 && /* @__PURE__ */ jsxs13("section", { children: [
|
|
2120
|
+
/* @__PURE__ */ jsxs13(
|
|
2121
|
+
"button",
|
|
2122
|
+
{
|
|
2123
|
+
type: "button",
|
|
2124
|
+
onClick: () => setShowResolved(!showResolved),
|
|
2125
|
+
className: "flex items-center gap-2 text-xs font-medium text-muted-foreground uppercase tracking-wider mb-3 hover:text-foreground transition-colors",
|
|
2126
|
+
children: [
|
|
2127
|
+
/* @__PURE__ */ jsx13(
|
|
2128
|
+
"svg",
|
|
2129
|
+
{
|
|
2130
|
+
width: "12",
|
|
2131
|
+
height: "12",
|
|
2132
|
+
viewBox: "0 0 24 24",
|
|
2133
|
+
fill: "none",
|
|
2134
|
+
stroke: "currentColor",
|
|
2135
|
+
strokeWidth: "2",
|
|
2136
|
+
className: cn(
|
|
2137
|
+
"transition-transform",
|
|
2138
|
+
showResolved && "rotate-180"
|
|
2139
|
+
),
|
|
2140
|
+
children: /* @__PURE__ */ jsx13("path", { d: "m6 9 6 6 6-6" })
|
|
2141
|
+
}
|
|
2142
|
+
),
|
|
2143
|
+
"Resolved (",
|
|
2144
|
+
resolved.length,
|
|
2145
|
+
")"
|
|
2146
|
+
]
|
|
2147
|
+
}
|
|
2148
|
+
),
|
|
2149
|
+
showResolved && /* @__PURE__ */ jsx13("div", { className: "space-y-2", children: resolved.map((item) => /* @__PURE__ */ jsxs13(
|
|
2150
|
+
"div",
|
|
2151
|
+
{
|
|
2152
|
+
className: "rounded-lg border border-border bg-card p-4 opacity-60",
|
|
2153
|
+
children: [
|
|
2154
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2 mb-1", children: [
|
|
2155
|
+
/* @__PURE__ */ jsx13("h4", { className: "text-sm font-medium text-foreground", children: item.title }),
|
|
2156
|
+
renderTypeBadge?.(item.type),
|
|
2157
|
+
/* @__PURE__ */ jsx13(
|
|
2158
|
+
"span",
|
|
2159
|
+
{
|
|
2160
|
+
className: cn(
|
|
2161
|
+
"rounded-full px-2 py-0.5 text-[10px] font-medium",
|
|
2162
|
+
item.status === "approved" && "bg-emerald-500/10 text-emerald-500",
|
|
2163
|
+
item.status === "rejected" && "bg-destructive/10 text-destructive",
|
|
2164
|
+
item.status === "executed" && "bg-primary/10 text-primary"
|
|
2165
|
+
),
|
|
2166
|
+
children: item.status
|
|
2167
|
+
}
|
|
2168
|
+
)
|
|
2169
|
+
] }),
|
|
2170
|
+
item.meta?.rejectionReason != null && /* @__PURE__ */ jsxs13("p", { className: "mt-1 text-xs text-destructive", children: [
|
|
2171
|
+
"Reason: ",
|
|
2172
|
+
String(item.meta.rejectionReason)
|
|
2173
|
+
] })
|
|
2174
|
+
]
|
|
2175
|
+
},
|
|
2176
|
+
item.id
|
|
2177
|
+
)) })
|
|
2178
|
+
] })
|
|
2179
|
+
] }) });
|
|
2180
|
+
}
|
|
2181
|
+
|
|
1659
2182
|
export {
|
|
1660
2183
|
WorkspaceLayout,
|
|
1661
2184
|
DirectoryPane,
|
|
@@ -1667,5 +2190,8 @@ export {
|
|
|
1667
2190
|
SessionActivityMonitor,
|
|
1668
2191
|
SandboxWorkbench,
|
|
1669
2192
|
AgentWorkbench,
|
|
1670
|
-
AuditResults
|
|
2193
|
+
AuditResults,
|
|
2194
|
+
TaskBoard,
|
|
2195
|
+
CalendarView,
|
|
2196
|
+
ApprovalQueue
|
|
1671
2197
|
};
|