spry-apps-dropdown 1.0.0
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/README.md +249 -0
- package/dist/AppsDropdown.d.ts +2 -0
- package/dist/index.cjs +7 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +564 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +42 -0
- package/dist/useAppsData.d.ts +2 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# @spry/apps-dropdown
|
|
2
|
+
|
|
3
|
+
A React component for displaying Spry apps in a dropdown menu with dynamic API integration.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🎨 Beautiful Material-UI design with smooth animations
|
|
8
|
+
- 🔄 Automatic data fetching from API
|
|
9
|
+
- 💾 Built-in caching and refetching
|
|
10
|
+
- âš¡ Loading and error states
|
|
11
|
+
- 📱 Responsive layout
|
|
12
|
+
- 🎯 TypeScript support
|
|
13
|
+
- 🔌 Easy integration
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @spry/apps-dropdown
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Peer Dependencies
|
|
22
|
+
|
|
23
|
+
Make sure you have these installed:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install react react-dom @mui/material framer-motion @emotion/react @emotion/styled
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
### Basic Usage (Recommended)
|
|
32
|
+
|
|
33
|
+
Import `AppsDropdownConnected` for automatic API integration:
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { useState, useRef } from 'react'
|
|
37
|
+
import { IconButton } from '@mui/material'
|
|
38
|
+
import { Apps } from '@mui/icons-material'
|
|
39
|
+
import { AppsDropdownConnected } from '@spry/apps-dropdown'
|
|
40
|
+
|
|
41
|
+
function MyComponent() {
|
|
42
|
+
const [appsMenuOpen, setAppsMenuOpen] = useState(false)
|
|
43
|
+
const appsButtonRef = useRef<HTMLButtonElement>(null)
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<>
|
|
47
|
+
<IconButton
|
|
48
|
+
ref={appsButtonRef}
|
|
49
|
+
onClick={() => setAppsMenuOpen(!appsMenuOpen)}
|
|
50
|
+
>
|
|
51
|
+
<Apps />
|
|
52
|
+
</IconButton>
|
|
53
|
+
|
|
54
|
+
<AppsDropdownConnected
|
|
55
|
+
apiUrl="http://localhost:3002"
|
|
56
|
+
open={appsMenuOpen}
|
|
57
|
+
onClose={() => setAppsMenuOpen(false)}
|
|
58
|
+
buttonRef={appsButtonRef}
|
|
59
|
+
/>
|
|
60
|
+
</>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Advanced Usage
|
|
66
|
+
|
|
67
|
+
Use `AppsDropdown` directly with custom data source:
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
import { AppsDropdown, useAppsData } from '@spry/apps-dropdown'
|
|
71
|
+
|
|
72
|
+
function MyComponent() {
|
|
73
|
+
const [appsMenuOpen, setAppsMenuOpen] = useState(false)
|
|
74
|
+
const appsButtonRef = useRef<HTMLButtonElement>(null)
|
|
75
|
+
|
|
76
|
+
// Use the hook for more control
|
|
77
|
+
const { apps, isLoading, error, refetch } = useAppsData('http://localhost:3002', {
|
|
78
|
+
refetchInterval: 10 * 60 * 1000, // 10 minutes
|
|
79
|
+
cacheTime: 10 * 60 * 1000 // 10 minutes
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<>
|
|
84
|
+
<IconButton ref={appsButtonRef} onClick={() => setAppsMenuOpen(!appsMenuOpen)}>
|
|
85
|
+
<Apps />
|
|
86
|
+
</IconButton>
|
|
87
|
+
|
|
88
|
+
<AppsDropdown
|
|
89
|
+
apps={apps}
|
|
90
|
+
open={appsMenuOpen}
|
|
91
|
+
onClose={() => setAppsMenuOpen(false)}
|
|
92
|
+
buttonRef={appsButtonRef}
|
|
93
|
+
isLoading={isLoading}
|
|
94
|
+
error={error}
|
|
95
|
+
onRetry={refetch}
|
|
96
|
+
/>
|
|
97
|
+
</>
|
|
98
|
+
)
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## API Reference
|
|
103
|
+
|
|
104
|
+
### `AppsDropdownConnected`
|
|
105
|
+
|
|
106
|
+
The main component with automatic API integration.
|
|
107
|
+
|
|
108
|
+
#### Props
|
|
109
|
+
|
|
110
|
+
| Prop | Type | Required | Default | Description |
|
|
111
|
+
|------|------|----------|---------|-------------|
|
|
112
|
+
| `apiUrl` | `string` | Yes | - | Base URL of the Spry Apps API |
|
|
113
|
+
| `open` | `boolean` | Yes | - | Whether the dropdown is open |
|
|
114
|
+
| `onClose` | `() => void` | Yes | - | Callback when dropdown closes |
|
|
115
|
+
| `buttonRef` | `React.RefObject<HTMLButtonElement>` | No | - | Ref for positioning |
|
|
116
|
+
| `refetchInterval` | `number` | No | `300000` (5 min) | Auto-refetch interval in ms |
|
|
117
|
+
| `cacheTime` | `number` | No | `300000` (5 min) | Cache duration in ms |
|
|
118
|
+
|
|
119
|
+
### `AppsDropdown`
|
|
120
|
+
|
|
121
|
+
The presentational component for custom implementations.
|
|
122
|
+
|
|
123
|
+
#### Props
|
|
124
|
+
|
|
125
|
+
| Prop | Type | Required | Default | Description |
|
|
126
|
+
|------|------|----------|---------|-------------|
|
|
127
|
+
| `apps` | `App[]` | Yes | - | Array of apps to display |
|
|
128
|
+
| `open` | `boolean` | Yes | - | Whether the dropdown is open |
|
|
129
|
+
| `onClose` | `() => void` | Yes | - | Callback when dropdown closes |
|
|
130
|
+
| `buttonRef` | `React.RefObject<HTMLButtonElement>` | No | - | Ref for positioning |
|
|
131
|
+
| `isLoading` | `boolean` | No | `false` | Loading state |
|
|
132
|
+
| `error` | `string \| null` | No | `null` | Error message |
|
|
133
|
+
| `onRetry` | `() => void` | No | - | Retry callback |
|
|
134
|
+
|
|
135
|
+
### `useAppsData`
|
|
136
|
+
|
|
137
|
+
Hook for fetching apps data.
|
|
138
|
+
|
|
139
|
+
#### Parameters
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
useAppsData(apiUrl: string, options?: {
|
|
143
|
+
refetchInterval?: number // Default: 300000 (5 minutes)
|
|
144
|
+
cacheTime?: number // Default: 300000 (5 minutes)
|
|
145
|
+
})
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
#### Returns
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
{
|
|
152
|
+
apps: App[] // Array of apps
|
|
153
|
+
isLoading: boolean // Loading state
|
|
154
|
+
error: string | null // Error message if any
|
|
155
|
+
refetch: () => Promise<void> // Manual refetch function
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Types
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
interface App {
|
|
163
|
+
id: string
|
|
164
|
+
name: string
|
|
165
|
+
description: string
|
|
166
|
+
url: string
|
|
167
|
+
iconUrl: string
|
|
168
|
+
color: string
|
|
169
|
+
order: number
|
|
170
|
+
createdAt: string
|
|
171
|
+
updatedAt: string
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Backend API Requirements
|
|
176
|
+
|
|
177
|
+
The component expects the following API endpoint structure:
|
|
178
|
+
|
|
179
|
+
### `GET /api/apps`
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
```json
|
|
183
|
+
{
|
|
184
|
+
"apps": [
|
|
185
|
+
{
|
|
186
|
+
"id": "abc123",
|
|
187
|
+
"name": "SpryBoard",
|
|
188
|
+
"description": "Collaborative whiteboard",
|
|
189
|
+
"url": "https://board.spry.com",
|
|
190
|
+
"iconUrl": "https://example.com/icon.png",
|
|
191
|
+
"color": "#4285f4",
|
|
192
|
+
"order": 1,
|
|
193
|
+
"createdAt": "2026-02-13T10:00:00.000Z",
|
|
194
|
+
"updatedAt": "2026-02-13T10:00:00.000Z"
|
|
195
|
+
}
|
|
196
|
+
],
|
|
197
|
+
"lastUpdated": "2026-02-13T10:00:00.000Z"
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
See [spry-apps-server](https://github.com/your-org/spry-apps-server) for the reference backend implementation.
|
|
202
|
+
|
|
203
|
+
## Styling
|
|
204
|
+
|
|
205
|
+
The component uses Material-UI components. You can customize the appearance using the MUI theme:
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
import { ThemeProvider, createTheme } from '@mui/material/styles'
|
|
209
|
+
|
|
210
|
+
const theme = createTheme({
|
|
211
|
+
// Your custom theme
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
function App() {
|
|
215
|
+
return (
|
|
216
|
+
<ThemeProvider theme={theme}>
|
|
217
|
+
<AppsDropdownConnected {...props} />
|
|
218
|
+
</ThemeProvider>
|
|
219
|
+
)
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Caching
|
|
224
|
+
|
|
225
|
+
The component automatically caches apps data in `localStorage` to provide instant loading on subsequent visits. The cache respects the `cacheTime` option.
|
|
226
|
+
|
|
227
|
+
## Error Handling
|
|
228
|
+
|
|
229
|
+
- Network errors are caught and displayed with a retry button
|
|
230
|
+
- Cached data is used as fallback when API is unavailable
|
|
231
|
+
- Loading spinner shown during initial fetch
|
|
232
|
+
|
|
233
|
+
## Browser Support
|
|
234
|
+
|
|
235
|
+
- Modern browsers with ES2020 support
|
|
236
|
+
- Requires localStorage API
|
|
237
|
+
|
|
238
|
+
## License
|
|
239
|
+
|
|
240
|
+
MIT
|
|
241
|
+
|
|
242
|
+
## Contributing
|
|
243
|
+
|
|
244
|
+
Contributions are welcome! Please open an issue or submit a pull request.
|
|
245
|
+
|
|
246
|
+
## Related
|
|
247
|
+
|
|
248
|
+
- [Spry Apps Server](https://github.com/your-org/spry-apps-server) - Backend API server
|
|
249
|
+
- [Spry Account](https://github.com/your-org/spry-account) - Reference implementation
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const x=require("react"),g=require("@mui/material"),W=require("framer-motion");var O={exports:{}},k={};var q;function ce(){if(q)return k;q=1;var c=Symbol.for("react.transitional.element"),E=Symbol.for("react.fragment");function f(l,u,i){var h=null;if(i!==void 0&&(h=""+i),u.key!==void 0&&(h=""+u.key),"key"in u){i={};for(var d in u)d!=="key"&&(i[d]=u[d])}else i=u;return u=i.ref,{$$typeof:c,type:l,key:h,ref:u!==void 0?u:null,props:i}}return k.Fragment=E,k.jsx=f,k.jsxs=f,k}var j={};var H;function ie(){return H||(H=1,process.env.NODE_ENV!=="production"&&(function(){function c(e){if(e==null)return null;if(typeof e=="function")return e.$$typeof===oe?null:e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case p:return"Fragment";case G:return"Profiler";case w:return"StrictMode";case ee:return"Suspense";case re:return"SuspenseList";case ne:return"Activity"}if(typeof e=="object")switch(typeof e.tag=="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),e.$$typeof){case o:return"Portal";case Q:return e.displayName||"Context";case Z:return(e._context.displayName||"Context")+".Consumer";case K:var r=e.render;return e=e.displayName,e||(e=r.displayName||r.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case te:return r=e.displayName||null,r!==null?r:c(e.type)||"Memo";case C:r=e._payload,e=e._init;try{return c(e(r))}catch{}}return null}function E(e){return""+e}function f(e){try{E(e);var r=!1}catch{r=!0}if(r){r=console;var n=r.error,a=typeof Symbol=="function"&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return n.call(r,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",a),E(e)}}function l(e){if(e===p)return"<>";if(typeof e=="object"&&e!==null&&e.$$typeof===C)return"<...>";try{var r=c(e);return r?"<"+r+">":"<...>"}catch{return"<...>"}}function u(){var e=P.A;return e===null?null:e.getOwner()}function i(){return Error("react-stack-top-frame")}function h(e){if(F.call(e,"key")){var r=Object.getOwnPropertyDescriptor(e,"key").get;if(r&&r.isReactWarning)return!1}return e.key!==void 0}function d(e,r){function n(){L||(L=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",r))}n.isReactWarning=!0,Object.defineProperty(e,"key",{get:n,configurable:!0})}function R(){var e=c(this.type);return $[e]||($[e]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),e=this.props.ref,e!==void 0?e:null}function b(e,r,n,a,S,I){var s=n.ref;return e={$$typeof:y,type:e,key:r,props:n,_owner:a},(s!==void 0?s:null)!==null?Object.defineProperty(e,"ref",{enumerable:!1,get:R}):Object.defineProperty(e,"ref",{enumerable:!1,value:null}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:S}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:I}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function v(e,r,n,a,S,I){var s=r.children;if(s!==void 0)if(a)if(ae(s)){for(a=0;a<s.length;a++)t(s[a]);Object.freeze&&Object.freeze(s)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else t(s);if(F.call(r,"key")){s=c(e);var A=Object.keys(r).filter(function(se){return se!=="key"});a=0<A.length?"{key: someKey, "+A.join(": ..., ")+": ...}":"{key: someKey}",U[s+a]||(A=0<A.length?"{"+A.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
|
|
2
|
+
let props = %s;
|
|
3
|
+
<%s {...props} />
|
|
4
|
+
React keys must be passed directly to JSX without using spread:
|
|
5
|
+
let props = %s;
|
|
6
|
+
<%s key={someKey} {...props} />`,a,s,A,s),U[s+a]=!0)}if(s=null,n!==void 0&&(f(n),s=""+n),h(r)&&(f(r.key),s=""+r.key),"key"in r){n={};for(var D in r)D!=="key"&&(n[D]=r[D])}else n=r;return s&&d(n,typeof e=="function"?e.displayName||e.name||"Unknown":e),b(e,s,n,u(),S,I)}function t(e){_(e)?e._store&&(e._store.validated=1):typeof e=="object"&&e!==null&&e.$$typeof===C&&(e._payload.status==="fulfilled"?_(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function _(e){return typeof e=="object"&&e!==null&&e.$$typeof===y}var T=x,y=Symbol.for("react.transitional.element"),o=Symbol.for("react.portal"),p=Symbol.for("react.fragment"),w=Symbol.for("react.strict_mode"),G=Symbol.for("react.profiler"),Z=Symbol.for("react.consumer"),Q=Symbol.for("react.context"),K=Symbol.for("react.forward_ref"),ee=Symbol.for("react.suspense"),re=Symbol.for("react.suspense_list"),te=Symbol.for("react.memo"),C=Symbol.for("react.lazy"),ne=Symbol.for("react.activity"),oe=Symbol.for("react.client.reference"),P=T.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,F=Object.prototype.hasOwnProperty,ae=Array.isArray,N=console.createTask?console.createTask:function(){return null};T={react_stack_bottom_frame:function(e){return e()}};var L,$={},M=T.react_stack_bottom_frame.bind(T,i)(),z=N(l(i)),U={};j.Fragment=p,j.jsx=function(e,r,n){var a=1e4>P.recentlyCreatedOwnerStacks++;return v(e,r,n,!1,a?Error("react-stack-top-frame"):M,a?N(l(e)):z)},j.jsxs=function(e,r,n){var a=1e4>P.recentlyCreatedOwnerStacks++;return v(e,r,n,!0,a?Error("react-stack-top-frame"):M,a?N(l(e)):z)}})()),j}var B;function le(){return B||(B=1,process.env.NODE_ENV==="production"?O.exports=ce():O.exports=ie()),O.exports}var m=le();function J({apps:c,open:E,onClose:f,buttonRef:l,isLoading:u=!1,error:i=null,onRetry:h}){const d=x.useRef(null),[R,b]=x.useState("64px");x.useLayoutEffect(()=>{if(E&&l?.current){const t=l.current.getBoundingClientRect();b(`${t.bottom+8}px`)}},[E,l]),x.useEffect(()=>{const t=_=>{d.current&&!d.current.contains(_.target)&&l?.current&&!l.current.contains(_.target)&&f()};return E&&document.addEventListener("mousedown",t),()=>{document.removeEventListener("mousedown",t)}},[E,f,l]);const v=t=>{window.open(t,"_blank"),f()};return m.jsx(W.AnimatePresence,{children:E&&m.jsx(W.motion.div,{ref:d,initial:{opacity:0,scaleX:.6,scaleY:.6,y:-8},animate:{opacity:1,scaleX:1,scaleY:1,y:0},exit:{opacity:0,scaleX:.6,scaleY:.6,y:-8},transition:{duration:.18,ease:"easeOut"},style:{position:"absolute",top:R,right:"16px",zIndex:1e3,transformOrigin:"top right"},children:m.jsxs(g.Box,{sx:{bgcolor:"#E8F0FE",borderRadius:"8px",boxShadow:"0 2px 8px rgba(0, 0, 0, 0.1)",p:2,width:"320px",minHeight:"100px"},onClick:t=>t.stopPropagation(),children:[u&&c.length===0&&m.jsx(g.Box,{sx:{display:"flex",justifyContent:"center",alignItems:"center",minHeight:"100px"},children:m.jsx(g.CircularProgress,{size:32})}),i&&c.length===0&&m.jsxs(g.Box,{sx:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",minHeight:"100px",gap:1},children:[m.jsx(g.Typography,{sx:{fontSize:"0.875rem",color:"#ea4335",textAlign:"center"},children:"Failed to load apps"}),h&&m.jsx(g.Link,{component:"button",onClick:h,sx:{fontSize:"0.875rem",color:"#1a73e8",cursor:"pointer",textDecoration:"underline"},children:"Retry"})]}),c.length>0&&m.jsx(g.Box,{sx:{display:"grid",gridTemplateColumns:"repeat(3, 1fr)",gap:1},children:c.map(t=>m.jsxs(g.Link,{onClick:()=>v(t.url),sx:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",minHeight:"100px",p:1.5,borderRadius:"12px",cursor:"pointer",textDecoration:"none",transition:"background-color 200ms","&:hover":{bgcolor:"#f1f3f4"}},title:t.description,children:[m.jsx(g.Box,{sx:{pb:1},children:t.iconUrl?m.jsx(g.Box,{component:"img",src:t.iconUrl,alt:t.name,sx:{width:"32px",height:"32px",objectFit:"contain"}}):m.jsx(g.Box,{sx:{width:"32px",height:"32px",borderRadius:"6px",bgcolor:t.color||"#4285f4",display:"flex",alignItems:"center",justifyContent:"center",fontSize:"1.5rem"},children:t.name.charAt(0)})}),m.jsx(g.Typography,{sx:{fontSize:"0.75rem",fontWeight:500,color:"#202124",textAlign:"center",lineHeight:1.2},children:t.name})]},t.id))})]})})})}const Y="spry_apps_cache",ue=300*1e3,fe=300*1e3;function V(c,E={}){const{refetchInterval:f=ue,cacheTime:l=fe}=E,[u,i]=x.useState([]),[h,d]=x.useState(!0),[R,b]=x.useState(null),v=x.useRef(null),t=x.useRef(null),_=x.useCallback(()=>{try{const o=localStorage.getItem(Y);if(!o)return null;const p=JSON.parse(o);return Date.now()-p.timestamp<l?p.apps:(localStorage.removeItem(Y),null)}catch(o){return console.error("Error loading from cache:",o),null}},[l]),T=x.useCallback(o=>{try{const p={apps:o,timestamp:Date.now()};localStorage.setItem(Y,JSON.stringify(p))}catch(p){console.error("Error saving to cache:",p)}},[]),y=x.useCallback(async()=>{t.current&&t.current.abort(),t.current=new AbortController;try{d(!0),b(null);const o=await fetch(`${c}/api/apps`,{signal:t.current.signal,headers:{Accept:"application/json"}});if(!o.ok)throw new Error(`HTTP error! status: ${o.status}`);const p=await o.json();i(p.apps),T(p.apps),b(null)}catch(o){if(o instanceof Error&&o.name==="AbortError")return;const p=o instanceof Error?o.message:"Failed to fetch apps";b(p),console.error("Error fetching apps:",o);const w=_();w&&i(w)}finally{d(!1)}},[c,_,T]);return x.useEffect(()=>{const o=_();return o&&(i(o),d(!1)),y(),f>0&&(v.current=window.setInterval(()=>{y()},f)),()=>{v.current&&window.clearInterval(v.current),t.current&&t.current.abort()}},[c,f,_,y]),{apps:u,isLoading:h,error:R,refetch:y}}function X({apiUrl:c,open:E,onClose:f,buttonRef:l,refetchInterval:u,cacheTime:i}){const{apps:h,isLoading:d,error:R,refetch:b}=V(c,{refetchInterval:u,cacheTime:i});return m.jsx(J,{apps:h,open:E,onClose:f,buttonRef:l,isLoading:d,error:R,onRetry:b})}exports.AppsDropdown=J;exports.AppsDropdownConnected=X;exports.default=X;exports.useAppsData=V;
|
|
7
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../node_modules/react/cjs/react-jsx-runtime.production.js","../node_modules/react/cjs/react-jsx-runtime.development.js","../node_modules/react/jsx-runtime.js","../src/AppsDropdown.tsx","../src/useAppsData.ts","../src/index.tsx"],"sourcesContent":["/**\n * @license React\n * react-jsx-runtime.production.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\nvar REACT_ELEMENT_TYPE = Symbol.for(\"react.transitional.element\"),\n REACT_FRAGMENT_TYPE = Symbol.for(\"react.fragment\");\nfunction jsxProd(type, config, maybeKey) {\n var key = null;\n void 0 !== maybeKey && (key = \"\" + maybeKey);\n void 0 !== config.key && (key = \"\" + config.key);\n if (\"key\" in config) {\n maybeKey = {};\n for (var propName in config)\n \"key\" !== propName && (maybeKey[propName] = config[propName]);\n } else maybeKey = config;\n config = maybeKey.ref;\n return {\n $$typeof: REACT_ELEMENT_TYPE,\n type: type,\n key: key,\n ref: void 0 !== config ? config : null,\n props: maybeKey\n };\n}\nexports.Fragment = REACT_FRAGMENT_TYPE;\nexports.jsx = jsxProd;\nexports.jsxs = jsxProd;\n","/**\n * @license React\n * react-jsx-runtime.development.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\n\"production\" !== process.env.NODE_ENV &&\n (function () {\n function getComponentNameFromType(type) {\n if (null == type) return null;\n if (\"function\" === typeof type)\n return type.$$typeof === REACT_CLIENT_REFERENCE\n ? null\n : type.displayName || type.name || null;\n if (\"string\" === typeof type) return type;\n switch (type) {\n case REACT_FRAGMENT_TYPE:\n return \"Fragment\";\n case REACT_PROFILER_TYPE:\n return \"Profiler\";\n case REACT_STRICT_MODE_TYPE:\n return \"StrictMode\";\n case REACT_SUSPENSE_TYPE:\n return \"Suspense\";\n case REACT_SUSPENSE_LIST_TYPE:\n return \"SuspenseList\";\n case REACT_ACTIVITY_TYPE:\n return \"Activity\";\n }\n if (\"object\" === typeof type)\n switch (\n (\"number\" === typeof type.tag &&\n console.error(\n \"Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue.\"\n ),\n type.$$typeof)\n ) {\n case REACT_PORTAL_TYPE:\n return \"Portal\";\n case REACT_CONTEXT_TYPE:\n return type.displayName || \"Context\";\n case REACT_CONSUMER_TYPE:\n return (type._context.displayName || \"Context\") + \".Consumer\";\n case REACT_FORWARD_REF_TYPE:\n var innerType = type.render;\n type = type.displayName;\n type ||\n ((type = innerType.displayName || innerType.name || \"\"),\n (type = \"\" !== type ? \"ForwardRef(\" + type + \")\" : \"ForwardRef\"));\n return type;\n case REACT_MEMO_TYPE:\n return (\n (innerType = type.displayName || null),\n null !== innerType\n ? innerType\n : getComponentNameFromType(type.type) || \"Memo\"\n );\n case REACT_LAZY_TYPE:\n innerType = type._payload;\n type = type._init;\n try {\n return getComponentNameFromType(type(innerType));\n } catch (x) {}\n }\n return null;\n }\n function testStringCoercion(value) {\n return \"\" + value;\n }\n function checkKeyStringCoercion(value) {\n try {\n testStringCoercion(value);\n var JSCompiler_inline_result = !1;\n } catch (e) {\n JSCompiler_inline_result = !0;\n }\n if (JSCompiler_inline_result) {\n JSCompiler_inline_result = console;\n var JSCompiler_temp_const = JSCompiler_inline_result.error;\n var JSCompiler_inline_result$jscomp$0 =\n (\"function\" === typeof Symbol &&\n Symbol.toStringTag &&\n value[Symbol.toStringTag]) ||\n value.constructor.name ||\n \"Object\";\n JSCompiler_temp_const.call(\n JSCompiler_inline_result,\n \"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.\",\n JSCompiler_inline_result$jscomp$0\n );\n return testStringCoercion(value);\n }\n }\n function getTaskName(type) {\n if (type === REACT_FRAGMENT_TYPE) return \"<>\";\n if (\n \"object\" === typeof type &&\n null !== type &&\n type.$$typeof === REACT_LAZY_TYPE\n )\n return \"<...>\";\n try {\n var name = getComponentNameFromType(type);\n return name ? \"<\" + name + \">\" : \"<...>\";\n } catch (x) {\n return \"<...>\";\n }\n }\n function getOwner() {\n var dispatcher = ReactSharedInternals.A;\n return null === dispatcher ? null : dispatcher.getOwner();\n }\n function UnknownOwner() {\n return Error(\"react-stack-top-frame\");\n }\n function hasValidKey(config) {\n if (hasOwnProperty.call(config, \"key\")) {\n var getter = Object.getOwnPropertyDescriptor(config, \"key\").get;\n if (getter && getter.isReactWarning) return !1;\n }\n return void 0 !== config.key;\n }\n function defineKeyPropWarningGetter(props, displayName) {\n function warnAboutAccessingKey() {\n specialPropKeyWarningShown ||\n ((specialPropKeyWarningShown = !0),\n console.error(\n \"%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)\",\n displayName\n ));\n }\n warnAboutAccessingKey.isReactWarning = !0;\n Object.defineProperty(props, \"key\", {\n get: warnAboutAccessingKey,\n configurable: !0\n });\n }\n function elementRefGetterWithDeprecationWarning() {\n var componentName = getComponentNameFromType(this.type);\n didWarnAboutElementRef[componentName] ||\n ((didWarnAboutElementRef[componentName] = !0),\n console.error(\n \"Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.\"\n ));\n componentName = this.props.ref;\n return void 0 !== componentName ? componentName : null;\n }\n function ReactElement(type, key, props, owner, debugStack, debugTask) {\n var refProp = props.ref;\n type = {\n $$typeof: REACT_ELEMENT_TYPE,\n type: type,\n key: key,\n props: props,\n _owner: owner\n };\n null !== (void 0 !== refProp ? refProp : null)\n ? Object.defineProperty(type, \"ref\", {\n enumerable: !1,\n get: elementRefGetterWithDeprecationWarning\n })\n : Object.defineProperty(type, \"ref\", { enumerable: !1, value: null });\n type._store = {};\n Object.defineProperty(type._store, \"validated\", {\n configurable: !1,\n enumerable: !1,\n writable: !0,\n value: 0\n });\n Object.defineProperty(type, \"_debugInfo\", {\n configurable: !1,\n enumerable: !1,\n writable: !0,\n value: null\n });\n Object.defineProperty(type, \"_debugStack\", {\n configurable: !1,\n enumerable: !1,\n writable: !0,\n value: debugStack\n });\n Object.defineProperty(type, \"_debugTask\", {\n configurable: !1,\n enumerable: !1,\n writable: !0,\n value: debugTask\n });\n Object.freeze && (Object.freeze(type.props), Object.freeze(type));\n return type;\n }\n function jsxDEVImpl(\n type,\n config,\n maybeKey,\n isStaticChildren,\n debugStack,\n debugTask\n ) {\n var children = config.children;\n if (void 0 !== children)\n if (isStaticChildren)\n if (isArrayImpl(children)) {\n for (\n isStaticChildren = 0;\n isStaticChildren < children.length;\n isStaticChildren++\n )\n validateChildKeys(children[isStaticChildren]);\n Object.freeze && Object.freeze(children);\n } else\n console.error(\n \"React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.\"\n );\n else validateChildKeys(children);\n if (hasOwnProperty.call(config, \"key\")) {\n children = getComponentNameFromType(type);\n var keys = Object.keys(config).filter(function (k) {\n return \"key\" !== k;\n });\n isStaticChildren =\n 0 < keys.length\n ? \"{key: someKey, \" + keys.join(\": ..., \") + \": ...}\"\n : \"{key: someKey}\";\n didWarnAboutKeySpread[children + isStaticChildren] ||\n ((keys =\n 0 < keys.length ? \"{\" + keys.join(\": ..., \") + \": ...}\" : \"{}\"),\n console.error(\n 'A props object containing a \"key\" prop is being spread into JSX:\\n let props = %s;\\n <%s {...props} />\\nReact keys must be passed directly to JSX without using spread:\\n let props = %s;\\n <%s key={someKey} {...props} />',\n isStaticChildren,\n children,\n keys,\n children\n ),\n (didWarnAboutKeySpread[children + isStaticChildren] = !0));\n }\n children = null;\n void 0 !== maybeKey &&\n (checkKeyStringCoercion(maybeKey), (children = \"\" + maybeKey));\n hasValidKey(config) &&\n (checkKeyStringCoercion(config.key), (children = \"\" + config.key));\n if (\"key\" in config) {\n maybeKey = {};\n for (var propName in config)\n \"key\" !== propName && (maybeKey[propName] = config[propName]);\n } else maybeKey = config;\n children &&\n defineKeyPropWarningGetter(\n maybeKey,\n \"function\" === typeof type\n ? type.displayName || type.name || \"Unknown\"\n : type\n );\n return ReactElement(\n type,\n children,\n maybeKey,\n getOwner(),\n debugStack,\n debugTask\n );\n }\n function validateChildKeys(node) {\n isValidElement(node)\n ? node._store && (node._store.validated = 1)\n : \"object\" === typeof node &&\n null !== node &&\n node.$$typeof === REACT_LAZY_TYPE &&\n (\"fulfilled\" === node._payload.status\n ? isValidElement(node._payload.value) &&\n node._payload.value._store &&\n (node._payload.value._store.validated = 1)\n : node._store && (node._store.validated = 1));\n }\n function isValidElement(object) {\n return (\n \"object\" === typeof object &&\n null !== object &&\n object.$$typeof === REACT_ELEMENT_TYPE\n );\n }\n var React = require(\"react\"),\n REACT_ELEMENT_TYPE = Symbol.for(\"react.transitional.element\"),\n REACT_PORTAL_TYPE = Symbol.for(\"react.portal\"),\n REACT_FRAGMENT_TYPE = Symbol.for(\"react.fragment\"),\n REACT_STRICT_MODE_TYPE = Symbol.for(\"react.strict_mode\"),\n REACT_PROFILER_TYPE = Symbol.for(\"react.profiler\"),\n REACT_CONSUMER_TYPE = Symbol.for(\"react.consumer\"),\n REACT_CONTEXT_TYPE = Symbol.for(\"react.context\"),\n REACT_FORWARD_REF_TYPE = Symbol.for(\"react.forward_ref\"),\n REACT_SUSPENSE_TYPE = Symbol.for(\"react.suspense\"),\n REACT_SUSPENSE_LIST_TYPE = Symbol.for(\"react.suspense_list\"),\n REACT_MEMO_TYPE = Symbol.for(\"react.memo\"),\n REACT_LAZY_TYPE = Symbol.for(\"react.lazy\"),\n REACT_ACTIVITY_TYPE = Symbol.for(\"react.activity\"),\n REACT_CLIENT_REFERENCE = Symbol.for(\"react.client.reference\"),\n ReactSharedInternals =\n React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,\n hasOwnProperty = Object.prototype.hasOwnProperty,\n isArrayImpl = Array.isArray,\n createTask = console.createTask\n ? console.createTask\n : function () {\n return null;\n };\n React = {\n react_stack_bottom_frame: function (callStackForError) {\n return callStackForError();\n }\n };\n var specialPropKeyWarningShown;\n var didWarnAboutElementRef = {};\n var unknownOwnerDebugStack = React.react_stack_bottom_frame.bind(\n React,\n UnknownOwner\n )();\n var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));\n var didWarnAboutKeySpread = {};\n exports.Fragment = REACT_FRAGMENT_TYPE;\n exports.jsx = function (type, config, maybeKey) {\n var trackActualOwner =\n 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;\n return jsxDEVImpl(\n type,\n config,\n maybeKey,\n !1,\n trackActualOwner\n ? Error(\"react-stack-top-frame\")\n : unknownOwnerDebugStack,\n trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask\n );\n };\n exports.jsxs = function (type, config, maybeKey) {\n var trackActualOwner =\n 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;\n return jsxDEVImpl(\n type,\n config,\n maybeKey,\n !0,\n trackActualOwner\n ? Error(\"react-stack-top-frame\")\n : unknownOwnerDebugStack,\n trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask\n );\n };\n })();\n","'use strict';\n\nif (process.env.NODE_ENV === 'production') {\n module.exports = require('./cjs/react-jsx-runtime.production.js');\n} else {\n module.exports = require('./cjs/react-jsx-runtime.development.js');\n}\n","import { useEffect, useRef, useState, useLayoutEffect } from 'react'\nimport { Box, Link, Typography, CircularProgress } from '@mui/material'\nimport { motion, AnimatePresence } from 'framer-motion'\nimport type { AppsDropdownProps } from './types'\n\nexport function AppsDropdown({\n apps,\n open,\n onClose,\n buttonRef,\n isLoading = false,\n error = null,\n onRetry\n}: AppsDropdownProps) {\n const dropdownRef = useRef<HTMLDivElement>(null)\n const [topPosition, setTopPosition] = useState('64px')\n\n useLayoutEffect(() => {\n if (open && buttonRef?.current) {\n const rect = buttonRef.current.getBoundingClientRect()\n setTopPosition(`${rect.bottom + 8}px`)\n }\n }, [open, buttonRef])\n\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n dropdownRef.current &&\n !dropdownRef.current.contains(event.target as Node) &&\n buttonRef?.current &&\n !buttonRef.current.contains(event.target as Node)\n ) {\n onClose()\n }\n }\n\n if (open) {\n document.addEventListener('mousedown', handleClickOutside)\n }\n\n return () => {\n document.removeEventListener('mousedown', handleClickOutside)\n }\n }, [open, onClose, buttonRef])\n\n const handleAppClick = (url: string) => {\n window.open(url, '_blank')\n onClose()\n }\n\n return (\n <AnimatePresence>\n {open && (\n <motion.div\n ref={dropdownRef}\n initial={{\n opacity: 0,\n scaleX: 0.6,\n scaleY: 0.6,\n y: -8,\n }}\n animate={{\n opacity: 1,\n scaleX: 1,\n scaleY: 1,\n y: 0,\n }}\n exit={{\n opacity: 0,\n scaleX: 0.6,\n scaleY: 0.6,\n y: -8,\n }}\n transition={{\n duration: 0.18,\n ease: 'easeOut',\n }}\n style={{\n position: 'absolute',\n top: topPosition,\n right: '16px',\n zIndex: 1000,\n transformOrigin: 'top right',\n }}\n >\n <Box\n sx={{\n bgcolor: '#E8F0FE',\n borderRadius: '8px',\n boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)',\n p: 2,\n width: '320px',\n minHeight: '100px',\n }}\n onClick={(e) => e.stopPropagation()}\n >\n {isLoading && apps.length === 0 && (\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n minHeight: '100px',\n }}\n >\n <CircularProgress size={32} />\n </Box>\n )}\n\n {error && apps.length === 0 && (\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: '100px',\n gap: 1,\n }}\n >\n <Typography\n sx={{\n fontSize: '0.875rem',\n color: '#ea4335',\n textAlign: 'center',\n }}\n >\n Failed to load apps\n </Typography>\n {onRetry && (\n <Link\n component=\"button\"\n onClick={onRetry}\n sx={{\n fontSize: '0.875rem',\n color: '#1a73e8',\n cursor: 'pointer',\n textDecoration: 'underline',\n }}\n >\n Retry\n </Link>\n )}\n </Box>\n )}\n\n {apps.length > 0 && (\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: 'repeat(3, 1fr)',\n gap: 1,\n }}\n >\n {apps.map((app) => (\n <Link\n key={app.id}\n onClick={() => handleAppClick(app.url)}\n sx={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: '100px',\n p: 1.5,\n borderRadius: '12px',\n cursor: 'pointer',\n textDecoration: 'none',\n transition: 'background-color 200ms',\n '&:hover': {\n bgcolor: '#f1f3f4',\n },\n }}\n title={app.description}\n >\n <Box sx={{ pb: 1 }}>\n {app.iconUrl ? (\n <Box\n component=\"img\"\n src={app.iconUrl}\n alt={app.name}\n sx={{\n width: '32px',\n height: '32px',\n objectFit: 'contain',\n }}\n />\n ) : (\n <Box\n sx={{\n width: '32px',\n height: '32px',\n borderRadius: '6px',\n bgcolor: app.color || '#4285f4',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '1.5rem',\n }}\n >\n {app.name.charAt(0)}\n </Box>\n )}\n </Box>\n <Typography\n sx={{\n fontSize: '0.75rem',\n fontWeight: 500,\n color: '#202124',\n textAlign: 'center',\n lineHeight: 1.2,\n }}\n >\n {app.name}\n </Typography>\n </Link>\n ))}\n </Box>\n )}\n </Box>\n </motion.div>\n )}\n </AnimatePresence>\n )\n}\n","import { useState, useEffect, useCallback, useRef } from 'react'\nimport type { App, AppsResponse, UseAppsDataOptions, UseAppsDataReturn } from './types'\n\nconst CACHE_KEY = 'spry_apps_cache'\nconst DEFAULT_REFETCH_INTERVAL = 5 * 60 * 1000 // 5 minutes\nconst DEFAULT_CACHE_TIME = 5 * 60 * 1000 // 5 minutes\n\ninterface CacheData {\n apps: App[]\n timestamp: number\n}\n\nexport function useAppsData(\n apiUrl: string,\n options: UseAppsDataOptions = {}\n): UseAppsDataReturn {\n const {\n refetchInterval = DEFAULT_REFETCH_INTERVAL,\n cacheTime = DEFAULT_CACHE_TIME\n } = options\n\n const [apps, setApps] = useState<App[]>([])\n const [isLoading, setIsLoading] = useState(true)\n const [error, setError] = useState<string | null>(null)\n const intervalRef = useRef<number | null>(null)\n const abortControllerRef = useRef<AbortController | null>(null)\n\n // Load from cache\n const loadFromCache = useCallback((): App[] | null => {\n try {\n const cached = localStorage.getItem(CACHE_KEY)\n if (!cached) return null\n\n const data: CacheData = JSON.parse(cached)\n const now = Date.now()\n\n if (now - data.timestamp < cacheTime) {\n return data.apps\n }\n\n // Cache expired, remove it\n localStorage.removeItem(CACHE_KEY)\n return null\n } catch (error) {\n console.error('Error loading from cache:', error)\n return null\n }\n }, [cacheTime])\n\n // Save to cache\n const saveToCache = useCallback((apps: App[]) => {\n try {\n const data: CacheData = {\n apps,\n timestamp: Date.now()\n }\n localStorage.setItem(CACHE_KEY, JSON.stringify(data))\n } catch (error) {\n console.error('Error saving to cache:', error)\n }\n }, [])\n\n // Fetch apps from API\n const fetchApps = useCallback(async () => {\n // Cancel previous request if still pending\n if (abortControllerRef.current) {\n abortControllerRef.current.abort()\n }\n\n // Create new abort controller\n abortControllerRef.current = new AbortController()\n\n try {\n setIsLoading(true)\n setError(null)\n\n const response = await fetch(`${apiUrl}/api/apps`, {\n signal: abortControllerRef.current.signal,\n headers: {\n 'Accept': 'application/json'\n }\n })\n\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`)\n }\n\n const data: AppsResponse = await response.json()\n setApps(data.apps)\n saveToCache(data.apps)\n setError(null)\n } catch (err) {\n // Don't set error if request was aborted\n if (err instanceof Error && err.name === 'AbortError') {\n return\n }\n\n const errorMessage = err instanceof Error ? err.message : 'Failed to fetch apps'\n setError(errorMessage)\n console.error('Error fetching apps:', err)\n\n // Try to use cached data on error\n const cachedApps = loadFromCache()\n if (cachedApps) {\n setApps(cachedApps)\n }\n } finally {\n setIsLoading(false)\n }\n }, [apiUrl, loadFromCache, saveToCache])\n\n // Initial load\n useEffect(() => {\n // Try to load from cache first\n const cachedApps = loadFromCache()\n if (cachedApps) {\n setApps(cachedApps)\n setIsLoading(false)\n }\n\n // Fetch fresh data\n fetchApps()\n\n // Set up refetch interval if specified\n if (refetchInterval > 0) {\n intervalRef.current = window.setInterval(() => {\n fetchApps()\n }, refetchInterval)\n }\n\n // Cleanup\n return () => {\n if (intervalRef.current) {\n window.clearInterval(intervalRef.current)\n }\n if (abortControllerRef.current) {\n abortControllerRef.current.abort()\n }\n }\n }, [apiUrl, refetchInterval, loadFromCache, fetchApps])\n\n return {\n apps,\n isLoading,\n error,\n refetch: fetchApps\n }\n}\n","import { AppsDropdown } from './AppsDropdown'\nimport { useAppsData } from './useAppsData'\nimport type { AppsDropdownConnectedProps } from './types'\n\n/**\n * AppsDropdownConnected component that automatically fetches apps from API\n * \n * @param apiUrl - Base URL of the Spry Apps API (e.g., \"http://localhost:3002\")\n * @param open - Whether the dropdown is open\n * @param onClose - Callback when dropdown should close\n * @param buttonRef - Ref to the button that triggers the dropdown (for positioning)\n * @param refetchInterval - How often to refetch apps in ms (default: 5 minutes)\n * @param cacheTime - How long to cache apps in ms (default: 5 minutes)\n */\nexport function AppsDropdownConnected({\n apiUrl,\n open,\n onClose,\n buttonRef,\n refetchInterval,\n cacheTime\n}: AppsDropdownConnectedProps) {\n const { apps, isLoading, error, refetch } = useAppsData(apiUrl, {\n refetchInterval,\n cacheTime\n })\n\n return (\n <AppsDropdown\n apps={apps}\n open={open}\n onClose={onClose}\n buttonRef={buttonRef}\n isLoading={isLoading}\n error={error}\n onRetry={refetch}\n />\n )\n}\n\n// Named exports\nexport { AppsDropdown } from './AppsDropdown'\nexport { useAppsData } from './useAppsData'\nexport * from './types'\n\n// Default export\nexport default AppsDropdownConnected\n"],"names":["REACT_ELEMENT_TYPE","REACT_FRAGMENT_TYPE","jsxProd","type","config","maybeKey","key","propName","reactJsxRuntime_production","getComponentNameFromType","REACT_CLIENT_REFERENCE","REACT_PROFILER_TYPE","REACT_STRICT_MODE_TYPE","REACT_SUSPENSE_TYPE","REACT_SUSPENSE_LIST_TYPE","REACT_ACTIVITY_TYPE","REACT_PORTAL_TYPE","REACT_CONTEXT_TYPE","REACT_CONSUMER_TYPE","REACT_FORWARD_REF_TYPE","innerType","REACT_MEMO_TYPE","REACT_LAZY_TYPE","testStringCoercion","value","checkKeyStringCoercion","JSCompiler_inline_result","JSCompiler_temp_const","JSCompiler_inline_result$jscomp$0","getTaskName","name","getOwner","dispatcher","ReactSharedInternals","UnknownOwner","hasValidKey","hasOwnProperty","getter","defineKeyPropWarningGetter","props","displayName","warnAboutAccessingKey","specialPropKeyWarningShown","elementRefGetterWithDeprecationWarning","componentName","didWarnAboutElementRef","ReactElement","owner","debugStack","debugTask","refProp","jsxDEVImpl","isStaticChildren","children","isArrayImpl","validateChildKeys","keys","k","didWarnAboutKeySpread","node","isValidElement","object","React","require$$0","createTask","callStackForError","unknownOwnerDebugStack","unknownOwnerDebugTask","reactJsxRuntime_development","trackActualOwner","jsxRuntimeModule","require$$1","AppsDropdown","apps","open","onClose","buttonRef","isLoading","error","onRetry","dropdownRef","useRef","topPosition","setTopPosition","useState","useLayoutEffect","rect","useEffect","handleClickOutside","event","handleAppClick","url","jsx","AnimatePresence","motion","jsxs","Box","e","CircularProgress","Typography","Link","app","CACHE_KEY","DEFAULT_REFETCH_INTERVAL","DEFAULT_CACHE_TIME","useAppsData","apiUrl","options","refetchInterval","cacheTime","setApps","setIsLoading","setError","intervalRef","abortControllerRef","loadFromCache","useCallback","cached","data","saveToCache","fetchApps","response","err","errorMessage","cachedApps","AppsDropdownConnected","refetch"],"mappings":"yPAWA,IAAIA,EAAqB,OAAO,IAAI,4BAA4B,EAC9DC,EAAsB,OAAO,IAAI,gBAAgB,EACnD,SAASC,EAAQC,EAAMC,EAAQC,EAAU,CACvC,IAAIC,EAAM,KAGV,GAFWD,IAAX,SAAwBC,EAAM,GAAKD,GACxBD,EAAO,MAAlB,SAA0BE,EAAM,GAAKF,EAAO,KACxC,QAASA,EAAQ,CACnBC,EAAW,CAAA,EACX,QAASE,KAAYH,EACTG,IAAV,QAAuBF,EAASE,CAAQ,EAAIH,EAAOG,CAAQ,EACjE,MAASF,EAAWD,EAClB,OAAAA,EAASC,EAAS,IACX,CACL,SAAUL,EACV,KAAMG,EACN,IAAKG,EACL,IAAgBF,IAAX,OAAoBA,EAAS,KAClC,MAAOC,EAEX,CACA,OAAAG,EAAA,SAAmBP,EACnBO,EAAA,IAAcN,EACdM,EAAA,KAAeN,gDCtBE,QAAQ,IAAI,WAA7B,eACG,UAAY,CACX,SAASO,EAAyBN,EAAM,CACtC,GAAYA,GAAR,KAAc,OAAO,KACzB,GAAmB,OAAOA,GAAtB,WACF,OAAOA,EAAK,WAAaO,GACrB,KACAP,EAAK,aAAeA,EAAK,MAAQ,KACvC,GAAiB,OAAOA,GAApB,SAA0B,OAAOA,EACrC,OAAQA,EAAI,CACV,KAAKF,EACH,MAAO,WACT,KAAKU,EACH,MAAO,WACT,KAAKC,EACH,MAAO,aACT,KAAKC,GACH,MAAO,WACT,KAAKC,GACH,MAAO,eACT,KAAKC,GACH,MAAO,UACjB,CACM,GAAiB,OAAOZ,GAApB,SACF,OACgB,OAAOA,EAAK,KAAzB,UACC,QAAQ,MACN,qHAEJA,EAAK,SACf,CACU,KAAKa,EACH,MAAO,SACT,KAAKC,EACH,OAAOd,EAAK,aAAe,UAC7B,KAAKe,EACH,OAAQf,EAAK,SAAS,aAAe,WAAa,YACpD,KAAKgB,EACH,IAAIC,EAAYjB,EAAK,OACrB,OAAAA,EAAOA,EAAK,YACZA,IACIA,EAAOiB,EAAU,aAAeA,EAAU,MAAQ,GACnDjB,EAAcA,IAAP,GAAc,cAAgBA,EAAO,IAAM,cAC9CA,EACT,KAAKkB,GACH,OACGD,EAAYjB,EAAK,aAAe,KACxBiB,IAAT,KACIA,EACAX,EAAyBN,EAAK,IAAI,GAAK,OAE/C,KAAKmB,EACHF,EAAYjB,EAAK,SACjBA,EAAOA,EAAK,MACZ,GAAI,CACF,OAAOM,EAAyBN,EAAKiB,CAAS,CAAC,CAC7D,MAAwB,CAAA,CACxB,CACM,OAAO,IACb,CACI,SAASG,EAAmBC,EAAO,CACjC,MAAO,GAAKA,CAClB,CACI,SAASC,EAAuBD,EAAO,CACrC,GAAI,CACFD,EAAmBC,CAAK,EACxB,IAAIE,EAA2B,EACvC,MAAkB,CACVA,EAA2B,EACnC,CACM,GAAIA,EAA0B,CAC5BA,EAA2B,QAC3B,IAAIC,EAAwBD,EAAyB,MACjDE,EACc,OAAO,QAAtB,YACC,OAAO,aACPJ,EAAM,OAAO,WAAW,GAC1BA,EAAM,YAAY,MAClB,SACF,OAAAG,EAAsB,KACpBD,EACA,2GACAE,GAEKL,EAAmBC,CAAK,CACvC,CACA,CACI,SAASK,EAAY1B,EAAM,CACzB,GAAIA,IAASF,EAAqB,MAAO,KACzC,GACe,OAAOE,GAApB,UACSA,IAAT,MACAA,EAAK,WAAamB,EAElB,MAAO,QACT,GAAI,CACF,IAAIQ,EAAOrB,EAAyBN,CAAI,EACxC,OAAO2B,EAAO,IAAMA,EAAO,IAAM,OACzC,MAAkB,CACV,MAAO,OACf,CACA,CACI,SAASC,GAAW,CAClB,IAAIC,EAAaC,EAAqB,EACtC,OAAgBD,IAAT,KAAsB,KAAOA,EAAW,SAAQ,CAC7D,CACI,SAASE,GAAe,CACtB,OAAO,MAAM,uBAAuB,CAC1C,CACI,SAASC,EAAY/B,EAAQ,CAC3B,GAAIgC,EAAe,KAAKhC,EAAQ,KAAK,EAAG,CACtC,IAAIiC,EAAS,OAAO,yBAAyBjC,EAAQ,KAAK,EAAE,IAC5D,GAAIiC,GAAUA,EAAO,eAAgB,MAAO,EACpD,CACM,OAAkBjC,EAAO,MAAlB,MACb,CACI,SAASkC,EAA2BC,EAAOC,EAAa,CACtD,SAASC,GAAwB,CAC/BC,IACIA,EAA6B,GAC/B,QAAQ,MACN,0OACAF,CACZ,EACA,CACMC,EAAsB,eAAiB,GACvC,OAAO,eAAeF,EAAO,MAAO,CAClC,IAAKE,EACL,aAAc,EACtB,CAAO,CACP,CACI,SAASE,GAAyC,CAChD,IAAIC,EAAgBnC,EAAyB,KAAK,IAAI,EACtD,OAAAoC,EAAuBD,CAAa,IAChCC,EAAuBD,CAAa,EAAI,GAC1C,QAAQ,MACN,6IACV,GACMA,EAAgB,KAAK,MAAM,IACTA,IAAX,OAA2BA,EAAgB,IACxD,CACI,SAASE,EAAa3C,EAAMG,EAAKiC,EAAOQ,EAAOC,EAAYC,EAAW,CACpE,IAAIC,EAAUX,EAAM,IACpB,OAAApC,EAAO,CACL,SAAUH,EACV,KAAMG,EACN,IAAKG,EACL,MAAOiC,EACP,OAAQQ,IAEWG,IAAX,OAAqBA,EAAU,QAAzC,KACI,OAAO,eAAe/C,EAAM,MAAO,CACjC,WAAY,GACZ,IAAKwC,EACN,EACD,OAAO,eAAexC,EAAM,MAAO,CAAE,WAAY,GAAI,MAAO,KAAM,EACtEA,EAAK,OAAS,CAAA,EACd,OAAO,eAAeA,EAAK,OAAQ,YAAa,CAC9C,aAAc,GACd,WAAY,GACZ,SAAU,GACV,MAAO,CACf,CAAO,EACD,OAAO,eAAeA,EAAM,aAAc,CACxC,aAAc,GACd,WAAY,GACZ,SAAU,GACV,MAAO,IACf,CAAO,EACD,OAAO,eAAeA,EAAM,cAAe,CACzC,aAAc,GACd,WAAY,GACZ,SAAU,GACV,MAAO6C,CACf,CAAO,EACD,OAAO,eAAe7C,EAAM,aAAc,CACxC,aAAc,GACd,WAAY,GACZ,SAAU,GACV,MAAO8C,CACf,CAAO,EACD,OAAO,SAAW,OAAO,OAAO9C,EAAK,KAAK,EAAG,OAAO,OAAOA,CAAI,GACxDA,CACb,CACI,SAASgD,EACPhD,EACAC,EACAC,EACA+C,EACAJ,EACAC,EACA,CACA,IAAII,EAAWjD,EAAO,SACtB,GAAeiD,IAAX,OACF,GAAID,EACF,GAAIE,GAAYD,CAAQ,EAAG,CACzB,IACED,EAAmB,EACnBA,EAAmBC,EAAS,OAC5BD,IAEAG,EAAkBF,EAASD,CAAgB,CAAC,EAC9C,OAAO,QAAU,OAAO,OAAOC,CAAQ,CACnD,MACY,QAAQ,MACN,6JAEDE,EAAkBF,CAAQ,EACjC,GAAIjB,EAAe,KAAKhC,EAAQ,KAAK,EAAG,CACtCiD,EAAW5C,EAAyBN,CAAI,EACxC,IAAIqD,EAAO,OAAO,KAAKpD,CAAM,EAAE,OAAO,SAAUqD,GAAG,CACjD,OAAiBA,KAAV,KACjB,CAAS,EACDL,EACE,EAAII,EAAK,OACL,kBAAoBA,EAAK,KAAK,SAAS,EAAI,SAC3C,iBACNE,EAAsBL,EAAWD,CAAgB,IAC7CI,EACA,EAAIA,EAAK,OAAS,IAAMA,EAAK,KAAK,SAAS,EAAI,SAAW,KAC5D,QAAQ,MACN;AAAA;AAAA;AAAA;AAAA;AAAA,mCACAJ,EACAC,EACAG,EACAH,GAEDK,EAAsBL,EAAWD,CAAgB,EAAI,GAChE,CAMM,GALAC,EAAW,KACAhD,IAAX,SACGoB,EAAuBpB,CAAQ,EAAIgD,EAAW,GAAKhD,GACtD8B,EAAY/B,CAAM,IACfqB,EAAuBrB,EAAO,GAAG,EAAIiD,EAAW,GAAKjD,EAAO,KAC3D,QAASA,EAAQ,CACnBC,EAAW,CAAA,EACX,QAASE,KAAYH,EACTG,IAAV,QAAuBF,EAASE,CAAQ,EAAIH,EAAOG,CAAQ,EACrE,MAAaF,EAAWD,EAClB,OAAAiD,GACEf,EACEjC,EACe,OAAOF,GAAtB,WACIA,EAAK,aAAeA,EAAK,MAAQ,UACjCA,GAED2C,EACL3C,EACAkD,EACAhD,EACA0B,EAAQ,EACRiB,EACAC,EAER,CACI,SAASM,EAAkBI,EAAM,CAC/BC,EAAeD,CAAI,EACfA,EAAK,SAAWA,EAAK,OAAO,UAAY,GAC3B,OAAOA,GAApB,UACSA,IAAT,MACAA,EAAK,WAAarC,IACDqC,EAAK,SAAS,SAA9B,YACGC,EAAeD,EAAK,SAAS,KAAK,GAClCA,EAAK,SAAS,MAAM,SACnBA,EAAK,SAAS,MAAM,OAAO,UAAY,GACxCA,EAAK,SAAWA,EAAK,OAAO,UAAY,GACtD,CACI,SAASC,EAAeC,EAAQ,CAC9B,OACe,OAAOA,GAApB,UACSA,IAAT,MACAA,EAAO,WAAa7D,CAE5B,CACI,IAAI8D,EAAQC,EACV/D,EAAqB,OAAO,IAAI,4BAA4B,EAC5DgB,EAAoB,OAAO,IAAI,cAAc,EAC7Cf,EAAsB,OAAO,IAAI,gBAAgB,EACjDW,EAAyB,OAAO,IAAI,mBAAmB,EACvDD,EAAsB,OAAO,IAAI,gBAAgB,EACjDO,EAAsB,OAAO,IAAI,gBAAgB,EACjDD,EAAqB,OAAO,IAAI,eAAe,EAC/CE,EAAyB,OAAO,IAAI,mBAAmB,EACvDN,GAAsB,OAAO,IAAI,gBAAgB,EACjDC,GAA2B,OAAO,IAAI,qBAAqB,EAC3DO,GAAkB,OAAO,IAAI,YAAY,EACzCC,EAAkB,OAAO,IAAI,YAAY,EACzCP,GAAsB,OAAO,IAAI,gBAAgB,EACjDL,GAAyB,OAAO,IAAI,wBAAwB,EAC5DuB,EACE6B,EAAM,gEACR1B,EAAiB,OAAO,UAAU,eAClCkB,GAAc,MAAM,QACpBU,EAAa,QAAQ,WACjB,QAAQ,WACR,UAAY,CACV,OAAO,IACnB,EACIF,EAAQ,CACN,yBAA0B,SAAUG,EAAmB,CACrD,OAAOA,EAAiB,CAChC,GAEI,IAAIvB,EACAG,EAAyB,CAAA,EACzBqB,EAAyBJ,EAAM,yBAAyB,KAC1DA,EACA5B,CACN,EAAK,EACGiC,EAAwBH,EAAWnC,EAAYK,CAAY,CAAC,EAC5DwB,EAAwB,CAAA,EAC5BU,EAAA,SAAmBnE,EACnBmE,EAAA,IAAc,SAAUjE,EAAMC,EAAQC,EAAU,CAC9C,IAAIgE,EACF,IAAMpC,EAAqB,6BAC7B,OAAOkB,EACLhD,EACAC,EACAC,EACA,GACAgE,EACI,MAAM,uBAAuB,EAC7BH,EACJG,EAAmBL,EAAWnC,EAAY1B,CAAI,CAAC,EAAIgE,EAE3D,EACIC,EAAA,KAAe,SAAUjE,EAAMC,EAAQC,EAAU,CAC/C,IAAIgE,EACF,IAAMpC,EAAqB,6BAC7B,OAAOkB,EACLhD,EACAC,EACAC,EACA,GACAgE,EACI,MAAM,uBAAuB,EAC7BH,EACJG,EAAmBL,EAAWnC,EAAY1B,CAAI,CAAC,EAAIgE,EAE3D,CACA,GAAG,wCC7VC,QAAQ,IAAI,WAAa,aAC3BG,EAAA,QAAiBP,GAAA,EAEjBO,EAAA,QAAiBC,GAAA,wBCAZ,SAASC,EAAa,CAC3B,KAAAC,EACA,KAAAC,EACA,QAAAC,EACA,UAAAC,EACA,UAAAC,EAAY,GACZ,MAAAC,EAAQ,KACR,QAAAC,CACF,EAAsB,CACpB,MAAMC,EAAcC,EAAAA,OAAuB,IAAI,EACzC,CAACC,EAAaC,CAAc,EAAIC,EAAAA,SAAS,MAAM,EAErDC,EAAAA,gBAAgB,IAAM,CACpB,GAAIX,GAAQE,GAAW,QAAS,CAC9B,MAAMU,EAAOV,EAAU,QAAQ,sBAAA,EAC/BO,EAAe,GAAGG,EAAK,OAAS,CAAC,IAAI,CACvC,CACF,EAAG,CAACZ,EAAME,CAAS,CAAC,EAEpBW,EAAAA,UAAU,IAAM,CACd,MAAMC,EAAsBC,GAAsB,CAE9CT,EAAY,SACZ,CAACA,EAAY,QAAQ,SAASS,EAAM,MAAc,GAClDb,GAAW,SACX,CAACA,EAAU,QAAQ,SAASa,EAAM,MAAc,GAEhDd,EAAA,CAEJ,EAEA,OAAID,GACF,SAAS,iBAAiB,YAAac,CAAkB,EAGpD,IAAM,CACX,SAAS,oBAAoB,YAAaA,CAAkB,CAC9D,CACF,EAAG,CAACd,EAAMC,EAASC,CAAS,CAAC,EAE7B,MAAMc,EAAkBC,GAAgB,CACtC,OAAO,KAAKA,EAAK,QAAQ,EACzBhB,EAAA,CACF,EAEA,OACEiB,EAAAA,IAACC,EAAAA,iBACE,SAAAnB,GACCkB,EAAAA,IAACE,EAAAA,OAAO,IAAP,CACC,IAAKd,EACL,QAAS,CACP,QAAS,EACT,OAAQ,GACR,OAAQ,GACR,EAAG,EAAA,EAEL,QAAS,CACP,QAAS,EACT,OAAQ,EACR,OAAQ,EACR,EAAG,CAAA,EAEL,KAAM,CACJ,QAAS,EACT,OAAQ,GACR,OAAQ,GACR,EAAG,EAAA,EAEL,WAAY,CACV,SAAU,IACV,KAAM,SAAA,EAER,MAAO,CACL,SAAU,WACV,IAAKE,EACL,MAAO,OACP,OAAQ,IACR,gBAAiB,WAAA,EAGnB,SAAAa,EAAAA,KAACC,EAAAA,IAAA,CACC,GAAI,CACF,QAAS,UACT,aAAc,MACd,UAAW,+BACX,EAAG,EACH,MAAO,QACP,UAAW,OAAA,EAEb,QAAUC,GAAMA,EAAE,gBAAA,EAEjB,SAAA,CAAApB,GAAaJ,EAAK,SAAW,GAC5BmB,EAAAA,IAACI,EAAAA,IAAA,CACC,GAAI,CACF,QAAS,OACT,eAAgB,SAChB,WAAY,SACZ,UAAW,OAAA,EAGb,SAAAJ,EAAAA,IAACM,EAAAA,iBAAA,CAAiB,KAAM,EAAA,CAAI,CAAA,CAAA,EAI/BpB,GAASL,EAAK,SAAW,GACxBsB,EAAAA,KAACC,EAAAA,IAAA,CACC,GAAI,CACF,QAAS,OACT,cAAe,SACf,WAAY,SACZ,eAAgB,SAChB,UAAW,QACX,IAAK,CAAA,EAGP,SAAA,CAAAJ,EAAAA,IAACO,EAAAA,WAAA,CACC,GAAI,CACF,SAAU,WACV,MAAO,UACP,UAAW,QAAA,EAEd,SAAA,qBAAA,CAAA,EAGApB,GACCa,EAAAA,IAACQ,EAAAA,KAAA,CACC,UAAU,SACV,QAASrB,EACT,GAAI,CACF,SAAU,WACV,MAAO,UACP,OAAQ,UACR,eAAgB,WAAA,EAEnB,SAAA,OAAA,CAAA,CAED,CAAA,CAAA,EAKLN,EAAK,OAAS,GACbmB,EAAAA,IAACI,EAAAA,IAAA,CACC,GAAI,CACF,QAAS,OACT,oBAAqB,iBACrB,IAAK,CAAA,EAGN,SAAAvB,EAAK,IAAK4B,GACTN,EAAAA,KAACK,EAAAA,KAAA,CAEC,QAAS,IAAMV,EAAeW,EAAI,GAAG,EACrC,GAAI,CACF,QAAS,OACT,cAAe,SACf,WAAY,SACZ,eAAgB,SAChB,UAAW,QACX,EAAG,IACH,aAAc,OACd,OAAQ,UACR,eAAgB,OAChB,WAAY,yBACZ,UAAW,CACT,QAAS,SAAA,CACX,EAEF,MAAOA,EAAI,YAEX,SAAA,CAAAT,MAACI,EAAAA,KAAI,GAAI,CAAE,GAAI,CAAA,EACZ,WAAI,QACHJ,EAAAA,IAACI,EAAAA,IAAA,CACC,UAAU,MACV,IAAKK,EAAI,QACT,IAAKA,EAAI,KACT,GAAI,CACF,MAAO,OACP,OAAQ,OACR,UAAW,SAAA,CACb,CAAA,EAGFT,EAAAA,IAACI,EAAAA,IAAA,CACC,GAAI,CACF,MAAO,OACP,OAAQ,OACR,aAAc,MACd,QAASK,EAAI,OAAS,UACtB,QAAS,OACT,WAAY,SACZ,eAAgB,SAChB,SAAU,QAAA,EAGX,SAAAA,EAAI,KAAK,OAAO,CAAC,CAAA,CAAA,EAGxB,EACAT,EAAAA,IAACO,EAAAA,WAAA,CACC,GAAI,CACF,SAAU,UACV,WAAY,IACZ,MAAO,UACP,UAAW,SACX,WAAY,GAAA,EAGb,SAAAE,EAAI,IAAA,CAAA,CACP,CAAA,EA1DKA,EAAI,EAAA,CA4DZ,CAAA,CAAA,CACH,CAAA,CAAA,CAEJ,CAAA,EAGN,CAEJ,CC7NA,MAAMC,EAAY,kBACZC,GAA2B,IAAS,IACpCC,GAAqB,IAAS,IAO7B,SAASC,EACdC,EACAC,EAA8B,GACX,CACnB,KAAM,CACJ,gBAAAC,EAAkBL,GAClB,UAAAM,EAAYL,EAAA,EACVG,EAEE,CAAClC,EAAMqC,CAAO,EAAI1B,EAAAA,SAAgB,CAAA,CAAE,EACpC,CAACP,EAAWkC,CAAY,EAAI3B,EAAAA,SAAS,EAAI,EACzC,CAACN,EAAOkC,CAAQ,EAAI5B,EAAAA,SAAwB,IAAI,EAChD6B,EAAchC,EAAAA,OAAsB,IAAI,EACxCiC,EAAqBjC,EAAAA,OAA+B,IAAI,EAGxDkC,EAAgBC,EAAAA,YAAY,IAAoB,CACpD,GAAI,CACF,MAAMC,EAAS,aAAa,QAAQf,CAAS,EAC7C,GAAI,CAACe,EAAQ,OAAO,KAEpB,MAAMC,EAAkB,KAAK,MAAMD,CAAM,EAGzC,OAFY,KAAK,IAAA,EAEPC,EAAK,UAAYT,EAClBS,EAAK,MAId,aAAa,WAAWhB,CAAS,EAC1B,KACT,OAASxB,EAAO,CACd,eAAQ,MAAM,4BAA6BA,CAAK,EACzC,IACT,CACF,EAAG,CAAC+B,CAAS,CAAC,EAGRU,EAAcH,cAAa3C,GAAgB,CAC/C,GAAI,CACF,MAAM6C,EAAkB,CACtB,KAAA7C,EACA,UAAW,KAAK,IAAA,CAAI,EAEtB,aAAa,QAAQ6B,EAAW,KAAK,UAAUgB,CAAI,CAAC,CACtD,OAASxC,EAAO,CACd,QAAQ,MAAM,yBAA0BA,CAAK,CAC/C,CACF,EAAG,CAAA,CAAE,EAGC0C,EAAYJ,EAAAA,YAAY,SAAY,CAEpCF,EAAmB,SACrBA,EAAmB,QAAQ,MAAA,EAI7BA,EAAmB,QAAU,IAAI,gBAEjC,GAAI,CACFH,EAAa,EAAI,EACjBC,EAAS,IAAI,EAEb,MAAMS,EAAW,MAAM,MAAM,GAAGf,CAAM,YAAa,CACjD,OAAQQ,EAAmB,QAAQ,OACnC,QAAS,CACP,OAAU,kBAAA,CACZ,CACD,EAED,GAAI,CAACO,EAAS,GACZ,MAAM,IAAI,MAAM,uBAAuBA,EAAS,MAAM,EAAE,EAG1D,MAAMH,EAAqB,MAAMG,EAAS,KAAA,EAC1CX,EAAQQ,EAAK,IAAI,EACjBC,EAAYD,EAAK,IAAI,EACrBN,EAAS,IAAI,CACf,OAASU,EAAK,CAEZ,GAAIA,aAAe,OAASA,EAAI,OAAS,aACvC,OAGF,MAAMC,EAAeD,aAAe,MAAQA,EAAI,QAAU,uBAC1DV,EAASW,CAAY,EACrB,QAAQ,MAAM,uBAAwBD,CAAG,EAGzC,MAAME,EAAaT,EAAA,EACfS,GACFd,EAAQc,CAAU,CAEtB,QAAA,CACEb,EAAa,EAAK,CACpB,CACF,EAAG,CAACL,EAAQS,EAAeI,CAAW,CAAC,EAGvChC,OAAAA,EAAAA,UAAU,IAAM,CAEd,MAAMqC,EAAaT,EAAA,EACnB,OAAIS,IACFd,EAAQc,CAAU,EAClBb,EAAa,EAAK,GAIpBS,EAAA,EAGIZ,EAAkB,IACpBK,EAAY,QAAU,OAAO,YAAY,IAAM,CAC7CO,EAAA,CACF,EAAGZ,CAAe,GAIb,IAAM,CACPK,EAAY,SACd,OAAO,cAAcA,EAAY,OAAO,EAEtCC,EAAmB,SACrBA,EAAmB,QAAQ,MAAA,CAE/B,CACF,EAAG,CAACR,EAAQE,EAAiBO,EAAeK,CAAS,CAAC,EAE/C,CACL,KAAA/C,EACA,UAAAI,EACA,MAAAC,EACA,QAAS0C,CAAA,CAEb,CCrIO,SAASK,EAAsB,CACpC,OAAAnB,EACA,KAAAhC,EACA,QAAAC,EACA,UAAAC,EACA,gBAAAgC,EACA,UAAAC,CACF,EAA+B,CAC7B,KAAM,CAAE,KAAApC,EAAM,UAAAI,EAAW,MAAAC,EAAO,QAAAgD,CAAA,EAAYrB,EAAYC,EAAQ,CAC9D,gBAAAE,EACA,UAAAC,CAAA,CACD,EAED,OACEjB,EAAAA,IAACpB,EAAA,CACC,KAAAC,EACA,KAAAC,EACA,QAAAC,EACA,UAAAC,EACA,UAAAC,EACA,MAAAC,EACA,QAASgD,CAAA,CAAA,CAGf","x_google_ignoreList":[0,1,2]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AppsDropdownConnectedProps } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* AppsDropdownConnected component that automatically fetches apps from API
|
|
4
|
+
*
|
|
5
|
+
* @param apiUrl - Base URL of the Spry Apps API (e.g., "http://localhost:3002")
|
|
6
|
+
* @param open - Whether the dropdown is open
|
|
7
|
+
* @param onClose - Callback when dropdown should close
|
|
8
|
+
* @param buttonRef - Ref to the button that triggers the dropdown (for positioning)
|
|
9
|
+
* @param refetchInterval - How often to refetch apps in ms (default: 5 minutes)
|
|
10
|
+
* @param cacheTime - How long to cache apps in ms (default: 5 minutes)
|
|
11
|
+
*/
|
|
12
|
+
export declare function AppsDropdownConnected({ apiUrl, open, onClose, buttonRef, refetchInterval, cacheTime }: AppsDropdownConnectedProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export { AppsDropdown } from './AppsDropdown';
|
|
14
|
+
export { useAppsData } from './useAppsData';
|
|
15
|
+
export * from './types';
|
|
16
|
+
export default AppsDropdownConnected;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
import ie, { useRef as L, useState as O, useLayoutEffect as le, useEffect as B, useCallback as Y } from "react";
|
|
2
|
+
import { Box as T, CircularProgress as ue, Typography as J, Link as V } from "@mui/material";
|
|
3
|
+
import { AnimatePresence as fe, motion as de } from "framer-motion";
|
|
4
|
+
var S = { exports: {} }, A = {};
|
|
5
|
+
var q;
|
|
6
|
+
function pe() {
|
|
7
|
+
if (q) return A;
|
|
8
|
+
q = 1;
|
|
9
|
+
var c = /* @__PURE__ */ Symbol.for("react.transitional.element"), E = /* @__PURE__ */ Symbol.for("react.fragment");
|
|
10
|
+
function f(l, u, i) {
|
|
11
|
+
var x = null;
|
|
12
|
+
if (i !== void 0 && (x = "" + i), u.key !== void 0 && (x = "" + u.key), "key" in u) {
|
|
13
|
+
i = {};
|
|
14
|
+
for (var d in u)
|
|
15
|
+
d !== "key" && (i[d] = u[d]);
|
|
16
|
+
} else i = u;
|
|
17
|
+
return u = i.ref, {
|
|
18
|
+
$$typeof: c,
|
|
19
|
+
type: l,
|
|
20
|
+
key: x,
|
|
21
|
+
ref: u !== void 0 ? u : null,
|
|
22
|
+
props: i
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return A.Fragment = E, A.jsx = f, A.jsxs = f, A;
|
|
26
|
+
}
|
|
27
|
+
var j = {};
|
|
28
|
+
var X;
|
|
29
|
+
function me() {
|
|
30
|
+
return X || (X = 1, process.env.NODE_ENV !== "production" && (function() {
|
|
31
|
+
function c(e) {
|
|
32
|
+
if (e == null) return null;
|
|
33
|
+
if (typeof e == "function")
|
|
34
|
+
return e.$$typeof === ae ? null : e.displayName || e.name || null;
|
|
35
|
+
if (typeof e == "string") return e;
|
|
36
|
+
switch (e) {
|
|
37
|
+
case p:
|
|
38
|
+
return "Fragment";
|
|
39
|
+
case Z:
|
|
40
|
+
return "Profiler";
|
|
41
|
+
case w:
|
|
42
|
+
return "StrictMode";
|
|
43
|
+
case re:
|
|
44
|
+
return "Suspense";
|
|
45
|
+
case te:
|
|
46
|
+
return "SuspenseList";
|
|
47
|
+
case oe:
|
|
48
|
+
return "Activity";
|
|
49
|
+
}
|
|
50
|
+
if (typeof e == "object")
|
|
51
|
+
switch (typeof e.tag == "number" && console.error(
|
|
52
|
+
"Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."
|
|
53
|
+
), e.$$typeof) {
|
|
54
|
+
case o:
|
|
55
|
+
return "Portal";
|
|
56
|
+
case K:
|
|
57
|
+
return e.displayName || "Context";
|
|
58
|
+
case Q:
|
|
59
|
+
return (e._context.displayName || "Context") + ".Consumer";
|
|
60
|
+
case ee:
|
|
61
|
+
var r = e.render;
|
|
62
|
+
return e = e.displayName, e || (e = r.displayName || r.name || "", e = e !== "" ? "ForwardRef(" + e + ")" : "ForwardRef"), e;
|
|
63
|
+
case ne:
|
|
64
|
+
return r = e.displayName || null, r !== null ? r : c(e.type) || "Memo";
|
|
65
|
+
case C:
|
|
66
|
+
r = e._payload, e = e._init;
|
|
67
|
+
try {
|
|
68
|
+
return c(e(r));
|
|
69
|
+
} catch {
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
function E(e) {
|
|
75
|
+
return "" + e;
|
|
76
|
+
}
|
|
77
|
+
function f(e) {
|
|
78
|
+
try {
|
|
79
|
+
E(e);
|
|
80
|
+
var r = !1;
|
|
81
|
+
} catch {
|
|
82
|
+
r = !0;
|
|
83
|
+
}
|
|
84
|
+
if (r) {
|
|
85
|
+
r = console;
|
|
86
|
+
var n = r.error, a = typeof Symbol == "function" && Symbol.toStringTag && e[Symbol.toStringTag] || e.constructor.name || "Object";
|
|
87
|
+
return n.call(
|
|
88
|
+
r,
|
|
89
|
+
"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",
|
|
90
|
+
a
|
|
91
|
+
), E(e);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function l(e) {
|
|
95
|
+
if (e === p) return "<>";
|
|
96
|
+
if (typeof e == "object" && e !== null && e.$$typeof === C)
|
|
97
|
+
return "<...>";
|
|
98
|
+
try {
|
|
99
|
+
var r = c(e);
|
|
100
|
+
return r ? "<" + r + ">" : "<...>";
|
|
101
|
+
} catch {
|
|
102
|
+
return "<...>";
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function u() {
|
|
106
|
+
var e = P.A;
|
|
107
|
+
return e === null ? null : e.getOwner();
|
|
108
|
+
}
|
|
109
|
+
function i() {
|
|
110
|
+
return Error("react-stack-top-frame");
|
|
111
|
+
}
|
|
112
|
+
function x(e) {
|
|
113
|
+
if ($.call(e, "key")) {
|
|
114
|
+
var r = Object.getOwnPropertyDescriptor(e, "key").get;
|
|
115
|
+
if (r && r.isReactWarning) return !1;
|
|
116
|
+
}
|
|
117
|
+
return e.key !== void 0;
|
|
118
|
+
}
|
|
119
|
+
function d(e, r) {
|
|
120
|
+
function n() {
|
|
121
|
+
z || (z = !0, console.error(
|
|
122
|
+
"%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",
|
|
123
|
+
r
|
|
124
|
+
));
|
|
125
|
+
}
|
|
126
|
+
n.isReactWarning = !0, Object.defineProperty(e, "key", {
|
|
127
|
+
get: n,
|
|
128
|
+
configurable: !0
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
function b() {
|
|
132
|
+
var e = c(this.type);
|
|
133
|
+
return M[e] || (M[e] = !0, console.error(
|
|
134
|
+
"Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release."
|
|
135
|
+
)), e = this.props.ref, e !== void 0 ? e : null;
|
|
136
|
+
}
|
|
137
|
+
function g(e, r, n, a, k, I) {
|
|
138
|
+
var s = n.ref;
|
|
139
|
+
return e = {
|
|
140
|
+
$$typeof: R,
|
|
141
|
+
type: e,
|
|
142
|
+
key: r,
|
|
143
|
+
props: n,
|
|
144
|
+
_owner: a
|
|
145
|
+
}, (s !== void 0 ? s : null) !== null ? Object.defineProperty(e, "ref", {
|
|
146
|
+
enumerable: !1,
|
|
147
|
+
get: b
|
|
148
|
+
}) : Object.defineProperty(e, "ref", { enumerable: !1, value: null }), e._store = {}, Object.defineProperty(e._store, "validated", {
|
|
149
|
+
configurable: !1,
|
|
150
|
+
enumerable: !1,
|
|
151
|
+
writable: !0,
|
|
152
|
+
value: 0
|
|
153
|
+
}), Object.defineProperty(e, "_debugInfo", {
|
|
154
|
+
configurable: !1,
|
|
155
|
+
enumerable: !1,
|
|
156
|
+
writable: !0,
|
|
157
|
+
value: null
|
|
158
|
+
}), Object.defineProperty(e, "_debugStack", {
|
|
159
|
+
configurable: !1,
|
|
160
|
+
enumerable: !1,
|
|
161
|
+
writable: !0,
|
|
162
|
+
value: k
|
|
163
|
+
}), Object.defineProperty(e, "_debugTask", {
|
|
164
|
+
configurable: !1,
|
|
165
|
+
enumerable: !1,
|
|
166
|
+
writable: !0,
|
|
167
|
+
value: I
|
|
168
|
+
}), Object.freeze && (Object.freeze(e.props), Object.freeze(e)), e;
|
|
169
|
+
}
|
|
170
|
+
function _(e, r, n, a, k, I) {
|
|
171
|
+
var s = r.children;
|
|
172
|
+
if (s !== void 0)
|
|
173
|
+
if (a)
|
|
174
|
+
if (se(s)) {
|
|
175
|
+
for (a = 0; a < s.length; a++)
|
|
176
|
+
t(s[a]);
|
|
177
|
+
Object.freeze && Object.freeze(s);
|
|
178
|
+
} else
|
|
179
|
+
console.error(
|
|
180
|
+
"React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead."
|
|
181
|
+
);
|
|
182
|
+
else t(s);
|
|
183
|
+
if ($.call(r, "key")) {
|
|
184
|
+
s = c(e);
|
|
185
|
+
var y = Object.keys(r).filter(function(ce) {
|
|
186
|
+
return ce !== "key";
|
|
187
|
+
});
|
|
188
|
+
a = 0 < y.length ? "{key: someKey, " + y.join(": ..., ") + ": ...}" : "{key: someKey}", H[s + a] || (y = 0 < y.length ? "{" + y.join(": ..., ") + ": ...}" : "{}", console.error(
|
|
189
|
+
`A props object containing a "key" prop is being spread into JSX:
|
|
190
|
+
let props = %s;
|
|
191
|
+
<%s {...props} />
|
|
192
|
+
React keys must be passed directly to JSX without using spread:
|
|
193
|
+
let props = %s;
|
|
194
|
+
<%s key={someKey} {...props} />`,
|
|
195
|
+
a,
|
|
196
|
+
s,
|
|
197
|
+
y,
|
|
198
|
+
s
|
|
199
|
+
), H[s + a] = !0);
|
|
200
|
+
}
|
|
201
|
+
if (s = null, n !== void 0 && (f(n), s = "" + n), x(r) && (f(r.key), s = "" + r.key), "key" in r) {
|
|
202
|
+
n = {};
|
|
203
|
+
for (var D in r)
|
|
204
|
+
D !== "key" && (n[D] = r[D]);
|
|
205
|
+
} else n = r;
|
|
206
|
+
return s && d(
|
|
207
|
+
n,
|
|
208
|
+
typeof e == "function" ? e.displayName || e.name || "Unknown" : e
|
|
209
|
+
), g(
|
|
210
|
+
e,
|
|
211
|
+
s,
|
|
212
|
+
n,
|
|
213
|
+
u(),
|
|
214
|
+
k,
|
|
215
|
+
I
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
function t(e) {
|
|
219
|
+
h(e) ? e._store && (e._store.validated = 1) : typeof e == "object" && e !== null && e.$$typeof === C && (e._payload.status === "fulfilled" ? h(e._payload.value) && e._payload.value._store && (e._payload.value._store.validated = 1) : e._store && (e._store.validated = 1));
|
|
220
|
+
}
|
|
221
|
+
function h(e) {
|
|
222
|
+
return typeof e == "object" && e !== null && e.$$typeof === R;
|
|
223
|
+
}
|
|
224
|
+
var v = ie, R = /* @__PURE__ */ Symbol.for("react.transitional.element"), o = /* @__PURE__ */ Symbol.for("react.portal"), p = /* @__PURE__ */ Symbol.for("react.fragment"), w = /* @__PURE__ */ Symbol.for("react.strict_mode"), Z = /* @__PURE__ */ Symbol.for("react.profiler"), Q = /* @__PURE__ */ Symbol.for("react.consumer"), K = /* @__PURE__ */ Symbol.for("react.context"), ee = /* @__PURE__ */ Symbol.for("react.forward_ref"), re = /* @__PURE__ */ Symbol.for("react.suspense"), te = /* @__PURE__ */ Symbol.for("react.suspense_list"), ne = /* @__PURE__ */ Symbol.for("react.memo"), C = /* @__PURE__ */ Symbol.for("react.lazy"), oe = /* @__PURE__ */ Symbol.for("react.activity"), ae = /* @__PURE__ */ Symbol.for("react.client.reference"), P = v.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, $ = Object.prototype.hasOwnProperty, se = Array.isArray, N = console.createTask ? console.createTask : function() {
|
|
225
|
+
return null;
|
|
226
|
+
};
|
|
227
|
+
v = {
|
|
228
|
+
react_stack_bottom_frame: function(e) {
|
|
229
|
+
return e();
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
var z, M = {}, U = v.react_stack_bottom_frame.bind(
|
|
233
|
+
v,
|
|
234
|
+
i
|
|
235
|
+
)(), W = N(l(i)), H = {};
|
|
236
|
+
j.Fragment = p, j.jsx = function(e, r, n) {
|
|
237
|
+
var a = 1e4 > P.recentlyCreatedOwnerStacks++;
|
|
238
|
+
return _(
|
|
239
|
+
e,
|
|
240
|
+
r,
|
|
241
|
+
n,
|
|
242
|
+
!1,
|
|
243
|
+
a ? Error("react-stack-top-frame") : U,
|
|
244
|
+
a ? N(l(e)) : W
|
|
245
|
+
);
|
|
246
|
+
}, j.jsxs = function(e, r, n) {
|
|
247
|
+
var a = 1e4 > P.recentlyCreatedOwnerStacks++;
|
|
248
|
+
return _(
|
|
249
|
+
e,
|
|
250
|
+
r,
|
|
251
|
+
n,
|
|
252
|
+
!0,
|
|
253
|
+
a ? Error("react-stack-top-frame") : U,
|
|
254
|
+
a ? N(l(e)) : W
|
|
255
|
+
);
|
|
256
|
+
};
|
|
257
|
+
})()), j;
|
|
258
|
+
}
|
|
259
|
+
var G;
|
|
260
|
+
function Ee() {
|
|
261
|
+
return G || (G = 1, process.env.NODE_ENV === "production" ? S.exports = pe() : S.exports = me()), S.exports;
|
|
262
|
+
}
|
|
263
|
+
var m = Ee();
|
|
264
|
+
function xe({
|
|
265
|
+
apps: c,
|
|
266
|
+
open: E,
|
|
267
|
+
onClose: f,
|
|
268
|
+
buttonRef: l,
|
|
269
|
+
isLoading: u = !1,
|
|
270
|
+
error: i = null,
|
|
271
|
+
onRetry: x
|
|
272
|
+
}) {
|
|
273
|
+
const d = L(null), [b, g] = O("64px");
|
|
274
|
+
le(() => {
|
|
275
|
+
if (E && l?.current) {
|
|
276
|
+
const t = l.current.getBoundingClientRect();
|
|
277
|
+
g(`${t.bottom + 8}px`);
|
|
278
|
+
}
|
|
279
|
+
}, [E, l]), B(() => {
|
|
280
|
+
const t = (h) => {
|
|
281
|
+
d.current && !d.current.contains(h.target) && l?.current && !l.current.contains(h.target) && f();
|
|
282
|
+
};
|
|
283
|
+
return E && document.addEventListener("mousedown", t), () => {
|
|
284
|
+
document.removeEventListener("mousedown", t);
|
|
285
|
+
};
|
|
286
|
+
}, [E, f, l]);
|
|
287
|
+
const _ = (t) => {
|
|
288
|
+
window.open(t, "_blank"), f();
|
|
289
|
+
};
|
|
290
|
+
return /* @__PURE__ */ m.jsx(fe, { children: E && /* @__PURE__ */ m.jsx(
|
|
291
|
+
de.div,
|
|
292
|
+
{
|
|
293
|
+
ref: d,
|
|
294
|
+
initial: {
|
|
295
|
+
opacity: 0,
|
|
296
|
+
scaleX: 0.6,
|
|
297
|
+
scaleY: 0.6,
|
|
298
|
+
y: -8
|
|
299
|
+
},
|
|
300
|
+
animate: {
|
|
301
|
+
opacity: 1,
|
|
302
|
+
scaleX: 1,
|
|
303
|
+
scaleY: 1,
|
|
304
|
+
y: 0
|
|
305
|
+
},
|
|
306
|
+
exit: {
|
|
307
|
+
opacity: 0,
|
|
308
|
+
scaleX: 0.6,
|
|
309
|
+
scaleY: 0.6,
|
|
310
|
+
y: -8
|
|
311
|
+
},
|
|
312
|
+
transition: {
|
|
313
|
+
duration: 0.18,
|
|
314
|
+
ease: "easeOut"
|
|
315
|
+
},
|
|
316
|
+
style: {
|
|
317
|
+
position: "absolute",
|
|
318
|
+
top: b,
|
|
319
|
+
right: "16px",
|
|
320
|
+
zIndex: 1e3,
|
|
321
|
+
transformOrigin: "top right"
|
|
322
|
+
},
|
|
323
|
+
children: /* @__PURE__ */ m.jsxs(
|
|
324
|
+
T,
|
|
325
|
+
{
|
|
326
|
+
sx: {
|
|
327
|
+
bgcolor: "#E8F0FE",
|
|
328
|
+
borderRadius: "8px",
|
|
329
|
+
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.1)",
|
|
330
|
+
p: 2,
|
|
331
|
+
width: "320px",
|
|
332
|
+
minHeight: "100px"
|
|
333
|
+
},
|
|
334
|
+
onClick: (t) => t.stopPropagation(),
|
|
335
|
+
children: [
|
|
336
|
+
u && c.length === 0 && /* @__PURE__ */ m.jsx(
|
|
337
|
+
T,
|
|
338
|
+
{
|
|
339
|
+
sx: {
|
|
340
|
+
display: "flex",
|
|
341
|
+
justifyContent: "center",
|
|
342
|
+
alignItems: "center",
|
|
343
|
+
minHeight: "100px"
|
|
344
|
+
},
|
|
345
|
+
children: /* @__PURE__ */ m.jsx(ue, { size: 32 })
|
|
346
|
+
}
|
|
347
|
+
),
|
|
348
|
+
i && c.length === 0 && /* @__PURE__ */ m.jsxs(
|
|
349
|
+
T,
|
|
350
|
+
{
|
|
351
|
+
sx: {
|
|
352
|
+
display: "flex",
|
|
353
|
+
flexDirection: "column",
|
|
354
|
+
alignItems: "center",
|
|
355
|
+
justifyContent: "center",
|
|
356
|
+
minHeight: "100px",
|
|
357
|
+
gap: 1
|
|
358
|
+
},
|
|
359
|
+
children: [
|
|
360
|
+
/* @__PURE__ */ m.jsx(
|
|
361
|
+
J,
|
|
362
|
+
{
|
|
363
|
+
sx: {
|
|
364
|
+
fontSize: "0.875rem",
|
|
365
|
+
color: "#ea4335",
|
|
366
|
+
textAlign: "center"
|
|
367
|
+
},
|
|
368
|
+
children: "Failed to load apps"
|
|
369
|
+
}
|
|
370
|
+
),
|
|
371
|
+
x && /* @__PURE__ */ m.jsx(
|
|
372
|
+
V,
|
|
373
|
+
{
|
|
374
|
+
component: "button",
|
|
375
|
+
onClick: x,
|
|
376
|
+
sx: {
|
|
377
|
+
fontSize: "0.875rem",
|
|
378
|
+
color: "#1a73e8",
|
|
379
|
+
cursor: "pointer",
|
|
380
|
+
textDecoration: "underline"
|
|
381
|
+
},
|
|
382
|
+
children: "Retry"
|
|
383
|
+
}
|
|
384
|
+
)
|
|
385
|
+
]
|
|
386
|
+
}
|
|
387
|
+
),
|
|
388
|
+
c.length > 0 && /* @__PURE__ */ m.jsx(
|
|
389
|
+
T,
|
|
390
|
+
{
|
|
391
|
+
sx: {
|
|
392
|
+
display: "grid",
|
|
393
|
+
gridTemplateColumns: "repeat(3, 1fr)",
|
|
394
|
+
gap: 1
|
|
395
|
+
},
|
|
396
|
+
children: c.map((t) => /* @__PURE__ */ m.jsxs(
|
|
397
|
+
V,
|
|
398
|
+
{
|
|
399
|
+
onClick: () => _(t.url),
|
|
400
|
+
sx: {
|
|
401
|
+
display: "flex",
|
|
402
|
+
flexDirection: "column",
|
|
403
|
+
alignItems: "center",
|
|
404
|
+
justifyContent: "center",
|
|
405
|
+
minHeight: "100px",
|
|
406
|
+
p: 1.5,
|
|
407
|
+
borderRadius: "12px",
|
|
408
|
+
cursor: "pointer",
|
|
409
|
+
textDecoration: "none",
|
|
410
|
+
transition: "background-color 200ms",
|
|
411
|
+
"&:hover": {
|
|
412
|
+
bgcolor: "#f1f3f4"
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
title: t.description,
|
|
416
|
+
children: [
|
|
417
|
+
/* @__PURE__ */ m.jsx(T, { sx: { pb: 1 }, children: t.iconUrl ? /* @__PURE__ */ m.jsx(
|
|
418
|
+
T,
|
|
419
|
+
{
|
|
420
|
+
component: "img",
|
|
421
|
+
src: t.iconUrl,
|
|
422
|
+
alt: t.name,
|
|
423
|
+
sx: {
|
|
424
|
+
width: "32px",
|
|
425
|
+
height: "32px",
|
|
426
|
+
objectFit: "contain"
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
) : /* @__PURE__ */ m.jsx(
|
|
430
|
+
T,
|
|
431
|
+
{
|
|
432
|
+
sx: {
|
|
433
|
+
width: "32px",
|
|
434
|
+
height: "32px",
|
|
435
|
+
borderRadius: "6px",
|
|
436
|
+
bgcolor: t.color || "#4285f4",
|
|
437
|
+
display: "flex",
|
|
438
|
+
alignItems: "center",
|
|
439
|
+
justifyContent: "center",
|
|
440
|
+
fontSize: "1.5rem"
|
|
441
|
+
},
|
|
442
|
+
children: t.name.charAt(0)
|
|
443
|
+
}
|
|
444
|
+
) }),
|
|
445
|
+
/* @__PURE__ */ m.jsx(
|
|
446
|
+
J,
|
|
447
|
+
{
|
|
448
|
+
sx: {
|
|
449
|
+
fontSize: "0.75rem",
|
|
450
|
+
fontWeight: 500,
|
|
451
|
+
color: "#202124",
|
|
452
|
+
textAlign: "center",
|
|
453
|
+
lineHeight: 1.2
|
|
454
|
+
},
|
|
455
|
+
children: t.name
|
|
456
|
+
}
|
|
457
|
+
)
|
|
458
|
+
]
|
|
459
|
+
},
|
|
460
|
+
t.id
|
|
461
|
+
))
|
|
462
|
+
}
|
|
463
|
+
)
|
|
464
|
+
]
|
|
465
|
+
}
|
|
466
|
+
)
|
|
467
|
+
}
|
|
468
|
+
) });
|
|
469
|
+
}
|
|
470
|
+
const F = "spry_apps_cache", he = 300 * 1e3, ge = 300 * 1e3;
|
|
471
|
+
function _e(c, E = {}) {
|
|
472
|
+
const {
|
|
473
|
+
refetchInterval: f = he,
|
|
474
|
+
cacheTime: l = ge
|
|
475
|
+
} = E, [u, i] = O([]), [x, d] = O(!0), [b, g] = O(null), _ = L(null), t = L(null), h = Y(() => {
|
|
476
|
+
try {
|
|
477
|
+
const o = localStorage.getItem(F);
|
|
478
|
+
if (!o) return null;
|
|
479
|
+
const p = JSON.parse(o);
|
|
480
|
+
return Date.now() - p.timestamp < l ? p.apps : (localStorage.removeItem(F), null);
|
|
481
|
+
} catch (o) {
|
|
482
|
+
return console.error("Error loading from cache:", o), null;
|
|
483
|
+
}
|
|
484
|
+
}, [l]), v = Y((o) => {
|
|
485
|
+
try {
|
|
486
|
+
const p = {
|
|
487
|
+
apps: o,
|
|
488
|
+
timestamp: Date.now()
|
|
489
|
+
};
|
|
490
|
+
localStorage.setItem(F, JSON.stringify(p));
|
|
491
|
+
} catch (p) {
|
|
492
|
+
console.error("Error saving to cache:", p);
|
|
493
|
+
}
|
|
494
|
+
}, []), R = Y(async () => {
|
|
495
|
+
t.current && t.current.abort(), t.current = new AbortController();
|
|
496
|
+
try {
|
|
497
|
+
d(!0), g(null);
|
|
498
|
+
const o = await fetch(`${c}/api/apps`, {
|
|
499
|
+
signal: t.current.signal,
|
|
500
|
+
headers: {
|
|
501
|
+
Accept: "application/json"
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
if (!o.ok)
|
|
505
|
+
throw new Error(`HTTP error! status: ${o.status}`);
|
|
506
|
+
const p = await o.json();
|
|
507
|
+
i(p.apps), v(p.apps), g(null);
|
|
508
|
+
} catch (o) {
|
|
509
|
+
if (o instanceof Error && o.name === "AbortError")
|
|
510
|
+
return;
|
|
511
|
+
const p = o instanceof Error ? o.message : "Failed to fetch apps";
|
|
512
|
+
g(p), console.error("Error fetching apps:", o);
|
|
513
|
+
const w = h();
|
|
514
|
+
w && i(w);
|
|
515
|
+
} finally {
|
|
516
|
+
d(!1);
|
|
517
|
+
}
|
|
518
|
+
}, [c, h, v]);
|
|
519
|
+
return B(() => {
|
|
520
|
+
const o = h();
|
|
521
|
+
return o && (i(o), d(!1)), R(), f > 0 && (_.current = window.setInterval(() => {
|
|
522
|
+
R();
|
|
523
|
+
}, f)), () => {
|
|
524
|
+
_.current && window.clearInterval(_.current), t.current && t.current.abort();
|
|
525
|
+
};
|
|
526
|
+
}, [c, f, h, R]), {
|
|
527
|
+
apps: u,
|
|
528
|
+
isLoading: x,
|
|
529
|
+
error: b,
|
|
530
|
+
refetch: R
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
function Te({
|
|
534
|
+
apiUrl: c,
|
|
535
|
+
open: E,
|
|
536
|
+
onClose: f,
|
|
537
|
+
buttonRef: l,
|
|
538
|
+
refetchInterval: u,
|
|
539
|
+
cacheTime: i
|
|
540
|
+
}) {
|
|
541
|
+
const { apps: x, isLoading: d, error: b, refetch: g } = _e(c, {
|
|
542
|
+
refetchInterval: u,
|
|
543
|
+
cacheTime: i
|
|
544
|
+
});
|
|
545
|
+
return /* @__PURE__ */ m.jsx(
|
|
546
|
+
xe,
|
|
547
|
+
{
|
|
548
|
+
apps: x,
|
|
549
|
+
open: E,
|
|
550
|
+
onClose: f,
|
|
551
|
+
buttonRef: l,
|
|
552
|
+
isLoading: d,
|
|
553
|
+
error: b,
|
|
554
|
+
onRetry: g
|
|
555
|
+
}
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
export {
|
|
559
|
+
xe as AppsDropdown,
|
|
560
|
+
Te as AppsDropdownConnected,
|
|
561
|
+
Te as default,
|
|
562
|
+
_e as useAppsData
|
|
563
|
+
};
|
|
564
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../node_modules/react/cjs/react-jsx-runtime.production.js","../node_modules/react/cjs/react-jsx-runtime.development.js","../node_modules/react/jsx-runtime.js","../src/AppsDropdown.tsx","../src/useAppsData.ts","../src/index.tsx"],"sourcesContent":["/**\n * @license React\n * react-jsx-runtime.production.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\nvar REACT_ELEMENT_TYPE = Symbol.for(\"react.transitional.element\"),\n REACT_FRAGMENT_TYPE = Symbol.for(\"react.fragment\");\nfunction jsxProd(type, config, maybeKey) {\n var key = null;\n void 0 !== maybeKey && (key = \"\" + maybeKey);\n void 0 !== config.key && (key = \"\" + config.key);\n if (\"key\" in config) {\n maybeKey = {};\n for (var propName in config)\n \"key\" !== propName && (maybeKey[propName] = config[propName]);\n } else maybeKey = config;\n config = maybeKey.ref;\n return {\n $$typeof: REACT_ELEMENT_TYPE,\n type: type,\n key: key,\n ref: void 0 !== config ? config : null,\n props: maybeKey\n };\n}\nexports.Fragment = REACT_FRAGMENT_TYPE;\nexports.jsx = jsxProd;\nexports.jsxs = jsxProd;\n","/**\n * @license React\n * react-jsx-runtime.development.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\n\"production\" !== process.env.NODE_ENV &&\n (function () {\n function getComponentNameFromType(type) {\n if (null == type) return null;\n if (\"function\" === typeof type)\n return type.$$typeof === REACT_CLIENT_REFERENCE\n ? null\n : type.displayName || type.name || null;\n if (\"string\" === typeof type) return type;\n switch (type) {\n case REACT_FRAGMENT_TYPE:\n return \"Fragment\";\n case REACT_PROFILER_TYPE:\n return \"Profiler\";\n case REACT_STRICT_MODE_TYPE:\n return \"StrictMode\";\n case REACT_SUSPENSE_TYPE:\n return \"Suspense\";\n case REACT_SUSPENSE_LIST_TYPE:\n return \"SuspenseList\";\n case REACT_ACTIVITY_TYPE:\n return \"Activity\";\n }\n if (\"object\" === typeof type)\n switch (\n (\"number\" === typeof type.tag &&\n console.error(\n \"Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue.\"\n ),\n type.$$typeof)\n ) {\n case REACT_PORTAL_TYPE:\n return \"Portal\";\n case REACT_CONTEXT_TYPE:\n return type.displayName || \"Context\";\n case REACT_CONSUMER_TYPE:\n return (type._context.displayName || \"Context\") + \".Consumer\";\n case REACT_FORWARD_REF_TYPE:\n var innerType = type.render;\n type = type.displayName;\n type ||\n ((type = innerType.displayName || innerType.name || \"\"),\n (type = \"\" !== type ? \"ForwardRef(\" + type + \")\" : \"ForwardRef\"));\n return type;\n case REACT_MEMO_TYPE:\n return (\n (innerType = type.displayName || null),\n null !== innerType\n ? innerType\n : getComponentNameFromType(type.type) || \"Memo\"\n );\n case REACT_LAZY_TYPE:\n innerType = type._payload;\n type = type._init;\n try {\n return getComponentNameFromType(type(innerType));\n } catch (x) {}\n }\n return null;\n }\n function testStringCoercion(value) {\n return \"\" + value;\n }\n function checkKeyStringCoercion(value) {\n try {\n testStringCoercion(value);\n var JSCompiler_inline_result = !1;\n } catch (e) {\n JSCompiler_inline_result = !0;\n }\n if (JSCompiler_inline_result) {\n JSCompiler_inline_result = console;\n var JSCompiler_temp_const = JSCompiler_inline_result.error;\n var JSCompiler_inline_result$jscomp$0 =\n (\"function\" === typeof Symbol &&\n Symbol.toStringTag &&\n value[Symbol.toStringTag]) ||\n value.constructor.name ||\n \"Object\";\n JSCompiler_temp_const.call(\n JSCompiler_inline_result,\n \"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.\",\n JSCompiler_inline_result$jscomp$0\n );\n return testStringCoercion(value);\n }\n }\n function getTaskName(type) {\n if (type === REACT_FRAGMENT_TYPE) return \"<>\";\n if (\n \"object\" === typeof type &&\n null !== type &&\n type.$$typeof === REACT_LAZY_TYPE\n )\n return \"<...>\";\n try {\n var name = getComponentNameFromType(type);\n return name ? \"<\" + name + \">\" : \"<...>\";\n } catch (x) {\n return \"<...>\";\n }\n }\n function getOwner() {\n var dispatcher = ReactSharedInternals.A;\n return null === dispatcher ? null : dispatcher.getOwner();\n }\n function UnknownOwner() {\n return Error(\"react-stack-top-frame\");\n }\n function hasValidKey(config) {\n if (hasOwnProperty.call(config, \"key\")) {\n var getter = Object.getOwnPropertyDescriptor(config, \"key\").get;\n if (getter && getter.isReactWarning) return !1;\n }\n return void 0 !== config.key;\n }\n function defineKeyPropWarningGetter(props, displayName) {\n function warnAboutAccessingKey() {\n specialPropKeyWarningShown ||\n ((specialPropKeyWarningShown = !0),\n console.error(\n \"%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)\",\n displayName\n ));\n }\n warnAboutAccessingKey.isReactWarning = !0;\n Object.defineProperty(props, \"key\", {\n get: warnAboutAccessingKey,\n configurable: !0\n });\n }\n function elementRefGetterWithDeprecationWarning() {\n var componentName = getComponentNameFromType(this.type);\n didWarnAboutElementRef[componentName] ||\n ((didWarnAboutElementRef[componentName] = !0),\n console.error(\n \"Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.\"\n ));\n componentName = this.props.ref;\n return void 0 !== componentName ? componentName : null;\n }\n function ReactElement(type, key, props, owner, debugStack, debugTask) {\n var refProp = props.ref;\n type = {\n $$typeof: REACT_ELEMENT_TYPE,\n type: type,\n key: key,\n props: props,\n _owner: owner\n };\n null !== (void 0 !== refProp ? refProp : null)\n ? Object.defineProperty(type, \"ref\", {\n enumerable: !1,\n get: elementRefGetterWithDeprecationWarning\n })\n : Object.defineProperty(type, \"ref\", { enumerable: !1, value: null });\n type._store = {};\n Object.defineProperty(type._store, \"validated\", {\n configurable: !1,\n enumerable: !1,\n writable: !0,\n value: 0\n });\n Object.defineProperty(type, \"_debugInfo\", {\n configurable: !1,\n enumerable: !1,\n writable: !0,\n value: null\n });\n Object.defineProperty(type, \"_debugStack\", {\n configurable: !1,\n enumerable: !1,\n writable: !0,\n value: debugStack\n });\n Object.defineProperty(type, \"_debugTask\", {\n configurable: !1,\n enumerable: !1,\n writable: !0,\n value: debugTask\n });\n Object.freeze && (Object.freeze(type.props), Object.freeze(type));\n return type;\n }\n function jsxDEVImpl(\n type,\n config,\n maybeKey,\n isStaticChildren,\n debugStack,\n debugTask\n ) {\n var children = config.children;\n if (void 0 !== children)\n if (isStaticChildren)\n if (isArrayImpl(children)) {\n for (\n isStaticChildren = 0;\n isStaticChildren < children.length;\n isStaticChildren++\n )\n validateChildKeys(children[isStaticChildren]);\n Object.freeze && Object.freeze(children);\n } else\n console.error(\n \"React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.\"\n );\n else validateChildKeys(children);\n if (hasOwnProperty.call(config, \"key\")) {\n children = getComponentNameFromType(type);\n var keys = Object.keys(config).filter(function (k) {\n return \"key\" !== k;\n });\n isStaticChildren =\n 0 < keys.length\n ? \"{key: someKey, \" + keys.join(\": ..., \") + \": ...}\"\n : \"{key: someKey}\";\n didWarnAboutKeySpread[children + isStaticChildren] ||\n ((keys =\n 0 < keys.length ? \"{\" + keys.join(\": ..., \") + \": ...}\" : \"{}\"),\n console.error(\n 'A props object containing a \"key\" prop is being spread into JSX:\\n let props = %s;\\n <%s {...props} />\\nReact keys must be passed directly to JSX without using spread:\\n let props = %s;\\n <%s key={someKey} {...props} />',\n isStaticChildren,\n children,\n keys,\n children\n ),\n (didWarnAboutKeySpread[children + isStaticChildren] = !0));\n }\n children = null;\n void 0 !== maybeKey &&\n (checkKeyStringCoercion(maybeKey), (children = \"\" + maybeKey));\n hasValidKey(config) &&\n (checkKeyStringCoercion(config.key), (children = \"\" + config.key));\n if (\"key\" in config) {\n maybeKey = {};\n for (var propName in config)\n \"key\" !== propName && (maybeKey[propName] = config[propName]);\n } else maybeKey = config;\n children &&\n defineKeyPropWarningGetter(\n maybeKey,\n \"function\" === typeof type\n ? type.displayName || type.name || \"Unknown\"\n : type\n );\n return ReactElement(\n type,\n children,\n maybeKey,\n getOwner(),\n debugStack,\n debugTask\n );\n }\n function validateChildKeys(node) {\n isValidElement(node)\n ? node._store && (node._store.validated = 1)\n : \"object\" === typeof node &&\n null !== node &&\n node.$$typeof === REACT_LAZY_TYPE &&\n (\"fulfilled\" === node._payload.status\n ? isValidElement(node._payload.value) &&\n node._payload.value._store &&\n (node._payload.value._store.validated = 1)\n : node._store && (node._store.validated = 1));\n }\n function isValidElement(object) {\n return (\n \"object\" === typeof object &&\n null !== object &&\n object.$$typeof === REACT_ELEMENT_TYPE\n );\n }\n var React = require(\"react\"),\n REACT_ELEMENT_TYPE = Symbol.for(\"react.transitional.element\"),\n REACT_PORTAL_TYPE = Symbol.for(\"react.portal\"),\n REACT_FRAGMENT_TYPE = Symbol.for(\"react.fragment\"),\n REACT_STRICT_MODE_TYPE = Symbol.for(\"react.strict_mode\"),\n REACT_PROFILER_TYPE = Symbol.for(\"react.profiler\"),\n REACT_CONSUMER_TYPE = Symbol.for(\"react.consumer\"),\n REACT_CONTEXT_TYPE = Symbol.for(\"react.context\"),\n REACT_FORWARD_REF_TYPE = Symbol.for(\"react.forward_ref\"),\n REACT_SUSPENSE_TYPE = Symbol.for(\"react.suspense\"),\n REACT_SUSPENSE_LIST_TYPE = Symbol.for(\"react.suspense_list\"),\n REACT_MEMO_TYPE = Symbol.for(\"react.memo\"),\n REACT_LAZY_TYPE = Symbol.for(\"react.lazy\"),\n REACT_ACTIVITY_TYPE = Symbol.for(\"react.activity\"),\n REACT_CLIENT_REFERENCE = Symbol.for(\"react.client.reference\"),\n ReactSharedInternals =\n React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,\n hasOwnProperty = Object.prototype.hasOwnProperty,\n isArrayImpl = Array.isArray,\n createTask = console.createTask\n ? console.createTask\n : function () {\n return null;\n };\n React = {\n react_stack_bottom_frame: function (callStackForError) {\n return callStackForError();\n }\n };\n var specialPropKeyWarningShown;\n var didWarnAboutElementRef = {};\n var unknownOwnerDebugStack = React.react_stack_bottom_frame.bind(\n React,\n UnknownOwner\n )();\n var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));\n var didWarnAboutKeySpread = {};\n exports.Fragment = REACT_FRAGMENT_TYPE;\n exports.jsx = function (type, config, maybeKey) {\n var trackActualOwner =\n 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;\n return jsxDEVImpl(\n type,\n config,\n maybeKey,\n !1,\n trackActualOwner\n ? Error(\"react-stack-top-frame\")\n : unknownOwnerDebugStack,\n trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask\n );\n };\n exports.jsxs = function (type, config, maybeKey) {\n var trackActualOwner =\n 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;\n return jsxDEVImpl(\n type,\n config,\n maybeKey,\n !0,\n trackActualOwner\n ? Error(\"react-stack-top-frame\")\n : unknownOwnerDebugStack,\n trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask\n );\n };\n })();\n","'use strict';\n\nif (process.env.NODE_ENV === 'production') {\n module.exports = require('./cjs/react-jsx-runtime.production.js');\n} else {\n module.exports = require('./cjs/react-jsx-runtime.development.js');\n}\n","import { useEffect, useRef, useState, useLayoutEffect } from 'react'\nimport { Box, Link, Typography, CircularProgress } from '@mui/material'\nimport { motion, AnimatePresence } from 'framer-motion'\nimport type { AppsDropdownProps } from './types'\n\nexport function AppsDropdown({\n apps,\n open,\n onClose,\n buttonRef,\n isLoading = false,\n error = null,\n onRetry\n}: AppsDropdownProps) {\n const dropdownRef = useRef<HTMLDivElement>(null)\n const [topPosition, setTopPosition] = useState('64px')\n\n useLayoutEffect(() => {\n if (open && buttonRef?.current) {\n const rect = buttonRef.current.getBoundingClientRect()\n setTopPosition(`${rect.bottom + 8}px`)\n }\n }, [open, buttonRef])\n\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n dropdownRef.current &&\n !dropdownRef.current.contains(event.target as Node) &&\n buttonRef?.current &&\n !buttonRef.current.contains(event.target as Node)\n ) {\n onClose()\n }\n }\n\n if (open) {\n document.addEventListener('mousedown', handleClickOutside)\n }\n\n return () => {\n document.removeEventListener('mousedown', handleClickOutside)\n }\n }, [open, onClose, buttonRef])\n\n const handleAppClick = (url: string) => {\n window.open(url, '_blank')\n onClose()\n }\n\n return (\n <AnimatePresence>\n {open && (\n <motion.div\n ref={dropdownRef}\n initial={{\n opacity: 0,\n scaleX: 0.6,\n scaleY: 0.6,\n y: -8,\n }}\n animate={{\n opacity: 1,\n scaleX: 1,\n scaleY: 1,\n y: 0,\n }}\n exit={{\n opacity: 0,\n scaleX: 0.6,\n scaleY: 0.6,\n y: -8,\n }}\n transition={{\n duration: 0.18,\n ease: 'easeOut',\n }}\n style={{\n position: 'absolute',\n top: topPosition,\n right: '16px',\n zIndex: 1000,\n transformOrigin: 'top right',\n }}\n >\n <Box\n sx={{\n bgcolor: '#E8F0FE',\n borderRadius: '8px',\n boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)',\n p: 2,\n width: '320px',\n minHeight: '100px',\n }}\n onClick={(e) => e.stopPropagation()}\n >\n {isLoading && apps.length === 0 && (\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n minHeight: '100px',\n }}\n >\n <CircularProgress size={32} />\n </Box>\n )}\n\n {error && apps.length === 0 && (\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: '100px',\n gap: 1,\n }}\n >\n <Typography\n sx={{\n fontSize: '0.875rem',\n color: '#ea4335',\n textAlign: 'center',\n }}\n >\n Failed to load apps\n </Typography>\n {onRetry && (\n <Link\n component=\"button\"\n onClick={onRetry}\n sx={{\n fontSize: '0.875rem',\n color: '#1a73e8',\n cursor: 'pointer',\n textDecoration: 'underline',\n }}\n >\n Retry\n </Link>\n )}\n </Box>\n )}\n\n {apps.length > 0 && (\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: 'repeat(3, 1fr)',\n gap: 1,\n }}\n >\n {apps.map((app) => (\n <Link\n key={app.id}\n onClick={() => handleAppClick(app.url)}\n sx={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: '100px',\n p: 1.5,\n borderRadius: '12px',\n cursor: 'pointer',\n textDecoration: 'none',\n transition: 'background-color 200ms',\n '&:hover': {\n bgcolor: '#f1f3f4',\n },\n }}\n title={app.description}\n >\n <Box sx={{ pb: 1 }}>\n {app.iconUrl ? (\n <Box\n component=\"img\"\n src={app.iconUrl}\n alt={app.name}\n sx={{\n width: '32px',\n height: '32px',\n objectFit: 'contain',\n }}\n />\n ) : (\n <Box\n sx={{\n width: '32px',\n height: '32px',\n borderRadius: '6px',\n bgcolor: app.color || '#4285f4',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '1.5rem',\n }}\n >\n {app.name.charAt(0)}\n </Box>\n )}\n </Box>\n <Typography\n sx={{\n fontSize: '0.75rem',\n fontWeight: 500,\n color: '#202124',\n textAlign: 'center',\n lineHeight: 1.2,\n }}\n >\n {app.name}\n </Typography>\n </Link>\n ))}\n </Box>\n )}\n </Box>\n </motion.div>\n )}\n </AnimatePresence>\n )\n}\n","import { useState, useEffect, useCallback, useRef } from 'react'\nimport type { App, AppsResponse, UseAppsDataOptions, UseAppsDataReturn } from './types'\n\nconst CACHE_KEY = 'spry_apps_cache'\nconst DEFAULT_REFETCH_INTERVAL = 5 * 60 * 1000 // 5 minutes\nconst DEFAULT_CACHE_TIME = 5 * 60 * 1000 // 5 minutes\n\ninterface CacheData {\n apps: App[]\n timestamp: number\n}\n\nexport function useAppsData(\n apiUrl: string,\n options: UseAppsDataOptions = {}\n): UseAppsDataReturn {\n const {\n refetchInterval = DEFAULT_REFETCH_INTERVAL,\n cacheTime = DEFAULT_CACHE_TIME\n } = options\n\n const [apps, setApps] = useState<App[]>([])\n const [isLoading, setIsLoading] = useState(true)\n const [error, setError] = useState<string | null>(null)\n const intervalRef = useRef<number | null>(null)\n const abortControllerRef = useRef<AbortController | null>(null)\n\n // Load from cache\n const loadFromCache = useCallback((): App[] | null => {\n try {\n const cached = localStorage.getItem(CACHE_KEY)\n if (!cached) return null\n\n const data: CacheData = JSON.parse(cached)\n const now = Date.now()\n\n if (now - data.timestamp < cacheTime) {\n return data.apps\n }\n\n // Cache expired, remove it\n localStorage.removeItem(CACHE_KEY)\n return null\n } catch (error) {\n console.error('Error loading from cache:', error)\n return null\n }\n }, [cacheTime])\n\n // Save to cache\n const saveToCache = useCallback((apps: App[]) => {\n try {\n const data: CacheData = {\n apps,\n timestamp: Date.now()\n }\n localStorage.setItem(CACHE_KEY, JSON.stringify(data))\n } catch (error) {\n console.error('Error saving to cache:', error)\n }\n }, [])\n\n // Fetch apps from API\n const fetchApps = useCallback(async () => {\n // Cancel previous request if still pending\n if (abortControllerRef.current) {\n abortControllerRef.current.abort()\n }\n\n // Create new abort controller\n abortControllerRef.current = new AbortController()\n\n try {\n setIsLoading(true)\n setError(null)\n\n const response = await fetch(`${apiUrl}/api/apps`, {\n signal: abortControllerRef.current.signal,\n headers: {\n 'Accept': 'application/json'\n }\n })\n\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`)\n }\n\n const data: AppsResponse = await response.json()\n setApps(data.apps)\n saveToCache(data.apps)\n setError(null)\n } catch (err) {\n // Don't set error if request was aborted\n if (err instanceof Error && err.name === 'AbortError') {\n return\n }\n\n const errorMessage = err instanceof Error ? err.message : 'Failed to fetch apps'\n setError(errorMessage)\n console.error('Error fetching apps:', err)\n\n // Try to use cached data on error\n const cachedApps = loadFromCache()\n if (cachedApps) {\n setApps(cachedApps)\n }\n } finally {\n setIsLoading(false)\n }\n }, [apiUrl, loadFromCache, saveToCache])\n\n // Initial load\n useEffect(() => {\n // Try to load from cache first\n const cachedApps = loadFromCache()\n if (cachedApps) {\n setApps(cachedApps)\n setIsLoading(false)\n }\n\n // Fetch fresh data\n fetchApps()\n\n // Set up refetch interval if specified\n if (refetchInterval > 0) {\n intervalRef.current = window.setInterval(() => {\n fetchApps()\n }, refetchInterval)\n }\n\n // Cleanup\n return () => {\n if (intervalRef.current) {\n window.clearInterval(intervalRef.current)\n }\n if (abortControllerRef.current) {\n abortControllerRef.current.abort()\n }\n }\n }, [apiUrl, refetchInterval, loadFromCache, fetchApps])\n\n return {\n apps,\n isLoading,\n error,\n refetch: fetchApps\n }\n}\n","import { AppsDropdown } from './AppsDropdown'\nimport { useAppsData } from './useAppsData'\nimport type { AppsDropdownConnectedProps } from './types'\n\n/**\n * AppsDropdownConnected component that automatically fetches apps from API\n * \n * @param apiUrl - Base URL of the Spry Apps API (e.g., \"http://localhost:3002\")\n * @param open - Whether the dropdown is open\n * @param onClose - Callback when dropdown should close\n * @param buttonRef - Ref to the button that triggers the dropdown (for positioning)\n * @param refetchInterval - How often to refetch apps in ms (default: 5 minutes)\n * @param cacheTime - How long to cache apps in ms (default: 5 minutes)\n */\nexport function AppsDropdownConnected({\n apiUrl,\n open,\n onClose,\n buttonRef,\n refetchInterval,\n cacheTime\n}: AppsDropdownConnectedProps) {\n const { apps, isLoading, error, refetch } = useAppsData(apiUrl, {\n refetchInterval,\n cacheTime\n })\n\n return (\n <AppsDropdown\n apps={apps}\n open={open}\n onClose={onClose}\n buttonRef={buttonRef}\n isLoading={isLoading}\n error={error}\n onRetry={refetch}\n />\n )\n}\n\n// Named exports\nexport { AppsDropdown } from './AppsDropdown'\nexport { useAppsData } from './useAppsData'\nexport * from './types'\n\n// Default export\nexport default AppsDropdownConnected\n"],"names":["REACT_ELEMENT_TYPE","REACT_FRAGMENT_TYPE","jsxProd","type","config","maybeKey","key","propName","reactJsxRuntime_production","getComponentNameFromType","REACT_CLIENT_REFERENCE","REACT_PROFILER_TYPE","REACT_STRICT_MODE_TYPE","REACT_SUSPENSE_TYPE","REACT_SUSPENSE_LIST_TYPE","REACT_ACTIVITY_TYPE","REACT_PORTAL_TYPE","REACT_CONTEXT_TYPE","REACT_CONSUMER_TYPE","REACT_FORWARD_REF_TYPE","innerType","REACT_MEMO_TYPE","REACT_LAZY_TYPE","testStringCoercion","value","checkKeyStringCoercion","JSCompiler_inline_result","JSCompiler_temp_const","JSCompiler_inline_result$jscomp$0","getTaskName","name","getOwner","dispatcher","ReactSharedInternals","UnknownOwner","hasValidKey","hasOwnProperty","getter","defineKeyPropWarningGetter","props","displayName","warnAboutAccessingKey","specialPropKeyWarningShown","elementRefGetterWithDeprecationWarning","componentName","didWarnAboutElementRef","ReactElement","owner","debugStack","debugTask","refProp","jsxDEVImpl","isStaticChildren","children","isArrayImpl","validateChildKeys","keys","k","didWarnAboutKeySpread","node","isValidElement","object","React","require$$0","createTask","callStackForError","unknownOwnerDebugStack","unknownOwnerDebugTask","reactJsxRuntime_development","trackActualOwner","jsxRuntimeModule","require$$1","AppsDropdown","apps","open","onClose","buttonRef","isLoading","error","onRetry","dropdownRef","useRef","topPosition","setTopPosition","useState","useLayoutEffect","rect","useEffect","handleClickOutside","event","handleAppClick","url","jsx","AnimatePresence","motion","jsxs","Box","e","CircularProgress","Typography","Link","app","CACHE_KEY","DEFAULT_REFETCH_INTERVAL","DEFAULT_CACHE_TIME","useAppsData","apiUrl","options","refetchInterval","cacheTime","setApps","setIsLoading","setError","intervalRef","abortControllerRef","loadFromCache","useCallback","cached","data","saveToCache","fetchApps","response","err","errorMessage","cachedApps","AppsDropdownConnected","refetch"],"mappings":"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","x_google_ignoreList":[0,1,2]}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export interface App {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
url: string;
|
|
6
|
+
iconUrl: string;
|
|
7
|
+
color: string;
|
|
8
|
+
order: number;
|
|
9
|
+
createdAt: string;
|
|
10
|
+
updatedAt: string;
|
|
11
|
+
}
|
|
12
|
+
export interface AppsResponse {
|
|
13
|
+
apps: App[];
|
|
14
|
+
lastUpdated: string;
|
|
15
|
+
}
|
|
16
|
+
export interface AppsDropdownProps {
|
|
17
|
+
apps: App[];
|
|
18
|
+
open: boolean;
|
|
19
|
+
onClose: () => void;
|
|
20
|
+
buttonRef?: React.RefObject<HTMLButtonElement | null>;
|
|
21
|
+
isLoading?: boolean;
|
|
22
|
+
error?: string | null;
|
|
23
|
+
onRetry?: () => void;
|
|
24
|
+
}
|
|
25
|
+
export interface AppsDropdownConnectedProps {
|
|
26
|
+
apiUrl: string;
|
|
27
|
+
open: boolean;
|
|
28
|
+
onClose: () => void;
|
|
29
|
+
buttonRef?: React.RefObject<HTMLButtonElement | null>;
|
|
30
|
+
refetchInterval?: number;
|
|
31
|
+
cacheTime?: number;
|
|
32
|
+
}
|
|
33
|
+
export interface UseAppsDataOptions {
|
|
34
|
+
refetchInterval?: number;
|
|
35
|
+
cacheTime?: number;
|
|
36
|
+
}
|
|
37
|
+
export interface UseAppsDataReturn {
|
|
38
|
+
apps: App[];
|
|
39
|
+
isLoading: boolean;
|
|
40
|
+
error: string | null;
|
|
41
|
+
refetch: () => Promise<void>;
|
|
42
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "spry-apps-dropdown",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "React dropdown component for displaying Spry apps with dynamic API integration",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "vite build && tsc --emitDeclarationOnly",
|
|
22
|
+
"dev": "vite build --watch",
|
|
23
|
+
"prepublishOnly": "npm run build"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"spry",
|
|
27
|
+
"apps",
|
|
28
|
+
"dropdown",
|
|
29
|
+
"react",
|
|
30
|
+
"component"
|
|
31
|
+
],
|
|
32
|
+
"author": "",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@mui/material": "^6.0.0",
|
|
36
|
+
"framer-motion": "^11.0.0",
|
|
37
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
38
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/react": "^19.0.1",
|
|
42
|
+
"@types/react-dom": "^19.0.1",
|
|
43
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
44
|
+
"typescript": "^5.9.3",
|
|
45
|
+
"vite": "^7.2.4"
|
|
46
|
+
}
|
|
47
|
+
}
|