@drewswiredin/backstage-plugin-assistants 0.5.5 → 0.6.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/AssistantsNavIcon.esm.js +35 -0
- package/dist/AssistantsNavIcon.esm.js.map +1 -0
- package/dist/collapsible/AssistantsList.esm.js +12 -5
- package/dist/collapsible/AssistantsList.esm.js.map +1 -1
- package/dist/collapsible/CollapsiblePage.esm.js +269 -342
- package/dist/collapsible/CollapsiblePage.esm.js.map +1 -1
- package/dist/collapsible/ConversationsPanel.esm.js +13 -7
- package/dist/collapsible/ConversationsPanel.esm.js.map +1 -1
- package/dist/collapsible/SidePane.esm.js +3 -2
- package/dist/collapsible/SidePane.esm.js.map +1 -1
- package/dist/collapsible/surface/ConversationSurface.esm.js +2 -1
- package/dist/collapsible/surface/ConversationSurface.esm.js.map +1 -1
- package/dist/collapsible/surface/parts.esm.js +66 -15
- package/dist/collapsible/surface/parts.esm.js.map +1 -1
- package/dist/collapsible/threadListAdapter.esm.js +153 -0
- package/dist/collapsible/threadListAdapter.esm.js.map +1 -0
- package/dist/collapsible/useAssistantRuntime.esm.js +66 -0
- package/dist/collapsible/useAssistantRuntime.esm.js.map +1 -0
- package/dist/collapsible/useThreadStatus.esm.js +108 -0
- package/dist/collapsible/useThreadStatus.esm.js.map +1 -0
- package/dist/index.d.ts +12 -1
- package/dist/index.esm.js +1 -0
- package/dist/index.esm.js.map +1 -1
- package/package.json +4 -2
- package/dist/collapsible/unreadStore.esm.js +0 -79
- package/dist/collapsible/unreadStore.esm.js.map +0 -1
- package/dist/collapsible/useConversations.esm.js +0 -171
- package/dist/collapsible/useConversations.esm.js.map +0 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { Badge } from '@material-ui/core';
|
|
3
|
+
import { makeStyles } from '@material-ui/core/styles';
|
|
4
|
+
import { RiRobot2Line } from '@remixicon/react';
|
|
5
|
+
import { useApi } from '@backstage/core-plugin-api';
|
|
6
|
+
import { assistantsApiRef } from './api/AssistantsApi.esm.js';
|
|
7
|
+
import { useThreadStatus } from './collapsible/useThreadStatus.esm.js';
|
|
8
|
+
|
|
9
|
+
const useStyles = makeStyles({
|
|
10
|
+
"@keyframes auiNavPulse": {
|
|
11
|
+
"0%": { transform: "scale(1)", opacity: 1 },
|
|
12
|
+
"50%": { transform: "scale(1.5)", opacity: 0.45 },
|
|
13
|
+
"100%": { transform: "scale(1)", opacity: 1 }
|
|
14
|
+
},
|
|
15
|
+
pulseDot: { animation: "$auiNavPulse 1.2s ease-in-out infinite" }
|
|
16
|
+
});
|
|
17
|
+
function AssistantsNavIcon() {
|
|
18
|
+
const classes = useStyles();
|
|
19
|
+
const api = useApi(assistantsApiRef);
|
|
20
|
+
const { overallStatus } = useThreadStatus(api, void 0);
|
|
21
|
+
return /* @__PURE__ */ jsx(
|
|
22
|
+
Badge,
|
|
23
|
+
{
|
|
24
|
+
color: overallStatus === "working" ? "primary" : "error",
|
|
25
|
+
variant: "dot",
|
|
26
|
+
overlap: "circular",
|
|
27
|
+
invisible: overallStatus === "read",
|
|
28
|
+
classes: overallStatus === "working" ? { dot: classes.pulseDot } : void 0,
|
|
29
|
+
children: /* @__PURE__ */ jsx(RiRobot2Line, {})
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export { AssistantsNavIcon };
|
|
35
|
+
//# sourceMappingURL=AssistantsNavIcon.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AssistantsNavIcon.esm.js","sources":["../src/AssistantsNavIcon.tsx"],"sourcesContent":["import { Badge } from '@material-ui/core';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { RiRobot2Line } from '@remixicon/react';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { assistantsApiRef } from './api';\nimport { useThreadStatus } from './collapsible/useThreadStatus';\n\nconst useStyles = makeStyles({\n '@keyframes auiNavPulse': {\n '0%': { transform: 'scale(1)', opacity: 1 },\n '50%': { transform: 'scale(1.5)', opacity: 0.45 },\n '100%': { transform: 'scale(1)', opacity: 1 },\n },\n pulseDot: { animation: '$auiNavPulse 1.2s ease-in-out infinite' },\n});\n\n/**\n * The Assistants nav-rail icon with a live status dot: a pulsing dot if any\n * conversation (across all assistants) is generating, else a solid red dot if\n * any is unread, else nothing — generating wins. Derived from the same\n * Signals-backed status store as the in-page indicators, so they never disagree.\n *\n * @public\n */\nexport function AssistantsNavIcon() {\n const classes = useStyles();\n const api = useApi(assistantsApiRef);\n // No focused conversation in the nav context, so pass undefined.\n const { overallStatus } = useThreadStatus(api, undefined);\n\n return (\n <Badge\n color={overallStatus === 'working' ? 'primary' : 'error'}\n variant=\"dot\"\n overlap=\"circular\"\n invisible={overallStatus === 'read'}\n classes={\n overallStatus === 'working' ? { dot: classes.pulseDot } : undefined\n }\n >\n <RiRobot2Line />\n </Badge>\n );\n}\n"],"names":[],"mappings":";;;;;;;;AAOA,MAAM,YAAY,UAAA,CAAW;AAAA,EAC3B,wBAAA,EAA0B;AAAA,IACxB,IAAA,EAAM,EAAE,SAAA,EAAW,UAAA,EAAY,SAAS,CAAA,EAAE;AAAA,IAC1C,KAAA,EAAO,EAAE,SAAA,EAAW,YAAA,EAAc,SAAS,IAAA,EAAK;AAAA,IAChD,MAAA,EAAQ,EAAE,SAAA,EAAW,UAAA,EAAY,SAAS,CAAA;AAAE,GAC9C;AAAA,EACA,QAAA,EAAU,EAAE,SAAA,EAAW,wCAAA;AACzB,CAAC,CAAA;AAUM,SAAS,iBAAA,GAAoB;AAClC,EAAA,MAAM,UAAU,SAAA,EAAU;AAC1B,EAAA,MAAM,GAAA,GAAM,OAAO,gBAAgB,CAAA;AAEnC,EAAA,MAAM,EAAE,aAAA,EAAc,GAAI,eAAA,CAAgB,KAAK,MAAS,CAAA;AAExD,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,aAAA,KAAkB,SAAA,GAAY,SAAA,GAAY,OAAA;AAAA,MACjD,OAAA,EAAQ,KAAA;AAAA,MACR,OAAA,EAAQ,UAAA;AAAA,MACR,WAAW,aAAA,KAAkB,MAAA;AAAA,MAC7B,SACE,aAAA,KAAkB,SAAA,GAAY,EAAE,GAAA,EAAK,OAAA,CAAQ,UAAS,GAAI,MAAA;AAAA,MAG5D,8BAAC,YAAA,EAAA,EAAa;AAAA;AAAA,GAChB;AAEJ;;;;"}
|
|
@@ -13,7 +13,6 @@ import Typography from '@material-ui/core/Typography';
|
|
|
13
13
|
import InfoOutlinedIcon from '@material-ui/icons/InfoOutlined';
|
|
14
14
|
import { AssistantAvatar } from './surface/AssistantAvatar.esm.js';
|
|
15
15
|
import { AssistantDetailDialog } from './AssistantDetailDialog.esm.js';
|
|
16
|
-
import { useUnreadVersion, hasUnread } from './unreadStore.esm.js';
|
|
17
16
|
|
|
18
17
|
const useStyles = makeStyles((theme) => ({
|
|
19
18
|
root: {
|
|
@@ -52,11 +51,18 @@ const useStyles = makeStyles((theme) => ({
|
|
|
52
51
|
pointerEvents: "none",
|
|
53
52
|
color: theme.palette.text.secondary,
|
|
54
53
|
transition: theme.transitions.create("opacity")
|
|
54
|
+
},
|
|
55
|
+
"@keyframes auiPulse": {
|
|
56
|
+
"0%": { transform: "scale(1)", opacity: 1 },
|
|
57
|
+
"50%": { transform: "scale(1.5)", opacity: 0.45 },
|
|
58
|
+
"100%": { transform: "scale(1)", opacity: 1 }
|
|
59
|
+
},
|
|
60
|
+
pulseDot: {
|
|
61
|
+
animation: "$auiPulse 1.2s ease-in-out infinite"
|
|
55
62
|
}
|
|
56
63
|
}));
|
|
57
|
-
const AssistantsList = ({ assistants, activeId, onSelect }) => {
|
|
64
|
+
const AssistantsList = ({ assistants, activeId, onSelect, agentStatus }) => {
|
|
58
65
|
const classes = useStyles();
|
|
59
|
-
useUnreadVersion();
|
|
60
66
|
const [detailId, setDetailId] = useState(null);
|
|
61
67
|
const openDetail = (e, id) => {
|
|
62
68
|
e.stopPropagation();
|
|
@@ -76,10 +82,11 @@ const AssistantsList = ({ assistants, activeId, onSelect }) => {
|
|
|
76
82
|
/* @__PURE__ */ jsx(ListItemIcon, { className: classes.icon, children: /* @__PURE__ */ jsx(
|
|
77
83
|
Badge,
|
|
78
84
|
{
|
|
79
|
-
color: "error",
|
|
85
|
+
color: agentStatus?.(a.id) === "working" ? "primary" : "error",
|
|
80
86
|
variant: "dot",
|
|
81
87
|
overlap: "circular",
|
|
82
|
-
invisible:
|
|
88
|
+
invisible: (agentStatus?.(a.id) ?? "read") === "read",
|
|
89
|
+
classes: agentStatus?.(a.id) === "working" ? { dot: classes.pulseDot } : void 0,
|
|
83
90
|
children: /* @__PURE__ */ jsx(AssistantAvatar, { color: a.color, size: 22 })
|
|
84
91
|
}
|
|
85
92
|
) }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantsList.esm.js","sources":["../../src/collapsible/AssistantsList.tsx"],"sourcesContent":["import { FC, MouseEvent, useState } from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport List from '@material-ui/core/List';\nimport ListItem from '@material-ui/core/ListItem';\nimport ListItemIcon from '@material-ui/core/ListItemIcon';\nimport ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';\nimport ListItemText from '@material-ui/core/ListItemText';\nimport IconButton from '@material-ui/core/IconButton';\nimport Badge from '@material-ui/core/Badge';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport Typography from '@material-ui/core/Typography';\nimport InfoOutlinedIcon from '@material-ui/icons/InfoOutlined';\nimport { AssistantSummary } from '@drewswiredin/backstage-plugin-assistants-common';\nimport { AssistantAvatar } from './surface/AssistantAvatar';\nimport { AssistantDetailDialog } from './AssistantDetailDialog';\nimport {
|
|
1
|
+
{"version":3,"file":"AssistantsList.esm.js","sources":["../../src/collapsible/AssistantsList.tsx"],"sourcesContent":["import { FC, MouseEvent, useState } from 'react';\nimport { makeStyles } from '@material-ui/core/styles';\nimport List from '@material-ui/core/List';\nimport ListItem from '@material-ui/core/ListItem';\nimport ListItemIcon from '@material-ui/core/ListItemIcon';\nimport ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';\nimport ListItemText from '@material-ui/core/ListItemText';\nimport IconButton from '@material-ui/core/IconButton';\nimport Badge from '@material-ui/core/Badge';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport Typography from '@material-ui/core/Typography';\nimport InfoOutlinedIcon from '@material-ui/icons/InfoOutlined';\nimport { AssistantSummary } from '@drewswiredin/backstage-plugin-assistants-common';\nimport { AssistantAvatar } from './surface/AssistantAvatar';\nimport { AssistantDetailDialog } from './AssistantDetailDialog';\nimport type { ConvStatus } from './useThreadStatus';\n\nconst useStyles = makeStyles(theme => ({\n root: {\n display: 'flex',\n flexDirection: 'column',\n padding: theme.spacing(1, 1.5, 0),\n },\n label: {\n color: theme.palette.text.secondary,\n fontWeight: 600,\n textTransform: 'uppercase',\n letterSpacing: 0.5,\n padding: theme.spacing(0, 0.5, 0.5),\n },\n item: {\n borderRadius: theme.shape.borderRadius,\n },\n // The hover rule lives on the container <li> (ListItem's ContainerProps), which\n // wraps BOTH the row and the secondary action. The action is a *sibling* of the\n // ListItem root, so a :hover rule on the row itself can't reach it.\n container: {\n '&:hover $infoAction': {\n opacity: 1,\n pointerEvents: 'auto',\n },\n },\n icon: {\n minWidth: 32,\n display: 'inline-flex',\n alignItems: 'center',\n },\n // Hidden until row hover (opacity + pointer-events so it's not clickable while\n // hidden); no reserved gutter so the title uses full width and truncates later.\n infoAction: {\n opacity: 0,\n pointerEvents: 'none',\n color: theme.palette.text.secondary,\n transition: theme.transitions.create('opacity'),\n },\n '@keyframes auiPulse': {\n '0%': { transform: 'scale(1)', opacity: 1 },\n '50%': { transform: 'scale(1.5)', opacity: 0.45 },\n '100%': { transform: 'scale(1)', opacity: 1 },\n },\n pulseDot: {\n animation: '$auiPulse 1.2s ease-in-out infinite',\n },\n}));\n\n/**\n * The in-page assistant switcher (top tier of the left sidebar). Lists every\n * accessible assistant; selecting one drives `?assistant=<id>` via `onSelect`,\n * which remounts the chat onto that assistant's (siloed) conversation set. The\n * active assistant is highlighted. A hover-revealed info button opens the\n * {@link AssistantDetailDialog} (description, tools, models).\n *\n * @public\n */\nexport const AssistantsList: FC<{\n assistants: AssistantSummary[];\n activeId: string;\n onSelect: (id: string) => void;\n /** Per-assistant rollup status (working/unread/read) for the rail dots. */\n agentStatus?: (assistantId: string) => ConvStatus;\n}> = ({ assistants, activeId, onSelect, agentStatus }) => {\n const classes = useStyles();\n const [detailId, setDetailId] = useState<string | null>(null);\n\n const openDetail = (e: MouseEvent<HTMLElement>, id: string) => {\n e.stopPropagation();\n setDetailId(id);\n };\n\n return (\n <div className={classes.root}>\n <Typography variant=\"caption\" className={classes.label}>\n Assistants\n </Typography>\n <List dense disablePadding>\n {assistants.map(a => (\n <ListItem\n key={a.id}\n button\n selected={a.id === activeId}\n className={classes.item}\n ContainerProps={{ className: classes.container }}\n onClick={() => onSelect(a.id)}\n >\n <ListItemIcon className={classes.icon}>\n <Badge\n color={agentStatus?.(a.id) === 'working' ? 'primary' : 'error'}\n variant=\"dot\"\n overlap=\"circular\"\n invisible={(agentStatus?.(a.id) ?? 'read') === 'read'}\n classes={\n agentStatus?.(a.id) === 'working'\n ? { dot: classes.pulseDot }\n : undefined\n }\n >\n <AssistantAvatar color={a.color} size={22} />\n </Badge>\n </ListItemIcon>\n <ListItemText\n primary={a.title}\n primaryTypographyProps={{ variant: 'body2', noWrap: true }}\n />\n <ListItemSecondaryAction className={classes.infoAction}>\n <Tooltip title=\"Details\">\n <IconButton\n edge=\"end\"\n size=\"small\"\n aria-label={`${a.title} details`}\n onClick={e => openDetail(e, a.id)}\n >\n <InfoOutlinedIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n </ListItemSecondaryAction>\n </ListItem>\n ))}\n </List>\n\n <AssistantDetailDialog\n assistant={assistants.find(a => a.id === detailId)}\n open={detailId !== null}\n onClose={() => setDetailId(null)}\n />\n </div>\n );\n};\n"],"names":[],"mappings":"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"}
|