mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-12 00:06:14 +00:00
revert fix hub list
This commit is contained in:
+5
-11
@@ -28,23 +28,20 @@ docker compose up db windmill_server windmill_worker
|
||||
- Install llvm
|
||||
|
||||
**On OSX:**
|
||||
|
||||
```bash
|
||||
brew install llvm caddy gsed
|
||||
|
||||
|
||||
# make LLVM tools available on PATH
|
||||
echo 'export PATH="/opt/homebrew/opt/llvm/bin:$PATH"' >> ~/.zshrc
|
||||
|
||||
|
||||
# now, restart your shell. You should now have the `lld` binary on your PATH.
|
||||
```
|
||||
|
||||
- To test that you have Rust and Cargo installed run `cargo --version`
|
||||
|
||||
- In your terminal, go to the backend directory and run `cargo build`
|
||||
- Run `cargo run`
|
||||
|
||||
**Known issue on M1 Mac while running `cargo build`**
|
||||
|
||||
- You may encounter `linking with cc failed` build time error.
|
||||
- To solve this run:
|
||||
```bash
|
||||
@@ -52,6 +49,7 @@ docker compose up db windmill_server windmill_worker
|
||||
source ~/.zshrc
|
||||
```
|
||||
|
||||
|
||||
**Do a Frontend Build**
|
||||
|
||||
In order to run the backend, you need to have a frontend build inside `frontend/build/`.
|
||||
@@ -72,14 +70,11 @@ npm run build
|
||||
```
|
||||
|
||||
**Known issue while running `npm run build`**
|
||||
|
||||
- You may encounter `FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory` error.
|
||||
- To solve this run:
|
||||
|
||||
```bash
|
||||
export NODE_OPTIONS=--max_old_space_size=8096
|
||||
```
|
||||
|
||||
- run `npm run build` again
|
||||
|
||||
In the root folder:
|
||||
@@ -151,13 +146,13 @@ Recommended config for VS Code:
|
||||
|
||||
- turn _format on save_ on
|
||||
|
||||
|
||||
## Building
|
||||
|
||||
The project is built with [SvelteKit](https://kit.svelte.dev/) and uses as output static files.
|
||||
There are others adapters for sveltekit, but we use the static adapter.
|
||||
|
||||
To build the frontend as static assets, use:
|
||||
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
@@ -165,11 +160,10 @@ npm run build
|
||||
The output is in the `build` folder.
|
||||
|
||||
The default build assume you serve every non static files as the 200.html file which is catchall. If you prefer a normal layout, you can use:
|
||||
|
||||
```
|
||||
NOTCATCHALL=true npm run build
|
||||
```
|
||||
|
||||
which will generate an index.html and allow you to serve the frontend with any static server.
|
||||
|
||||
Env variables used for build are set in .env file. See [https://vitejs.dev/guide/env-and-mode.html#env-files](https://vitejs.dev/guide/env-and-mode.html#env-files) for more details.
|
||||
|
||||
|
||||
@@ -26,11 +26,11 @@
|
||||
import DrawerContent from './common/drawer/DrawerContent.svelte'
|
||||
import { Badge, Drawer } from './common'
|
||||
import WorkspaceScriptPicker from './flows/pickers/WorkspaceScriptPicker.svelte'
|
||||
import PickHubScript from './flows/pickers/PickHubScript.svelte'
|
||||
import ToggleHubWorkspace from './ToggleHubWorkspace.svelte'
|
||||
import Skeleton from './common/skeleton/Skeleton.svelte'
|
||||
import Popover from './Popover.svelte'
|
||||
import Kbd from './common/kbd/Kbd.svelte'
|
||||
import PickHubItems from './flows/pickers/PickHubItems.svelte'
|
||||
|
||||
export let lang: 'python3' | 'deno' | 'go' | 'bash'
|
||||
export let editor: Editor | undefined
|
||||
@@ -86,9 +86,9 @@
|
||||
<Drawer bind:this={scriptPicker} size="900px">
|
||||
<DrawerContent title="Code" on:close={scriptPicker.closeDrawer}>
|
||||
{#if pick_existing == 'hub'}
|
||||
<PickHubItems bind:filter {kind} on:pickScript={onScriptPick} selectedKind="script">
|
||||
<PickHubScript bind:filter {kind} on:pick={onScriptPick}>
|
||||
<ToggleHubWorkspace bind:selected={pick_existing} />
|
||||
</PickHubItems>
|
||||
</PickHubScript>
|
||||
{:else}
|
||||
<WorkspaceScriptPicker bind:filter {kind} on:pick={onScriptPick}>
|
||||
<ToggleHubWorkspace bind:selected={pick_existing} />
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { Schema } from '$lib/common'
|
||||
import { Button, Drawer, DrawerContent, Tab, Tabs } from '$lib/components/common'
|
||||
import FlowScriptPicker from '$lib/components/flows/pickers/FlowScriptPicker.svelte'
|
||||
import PickHubScript from '$lib/components/flows/pickers/PickHubScript.svelte'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
import { Script, type Preview } from '$lib/gen'
|
||||
import { inferArgs } from '$lib/infer'
|
||||
@@ -15,7 +16,6 @@
|
||||
import { defaultCode } from '../component'
|
||||
import InlineScriptList from '../settingsPanel/mainInput/InlineScriptList.svelte'
|
||||
import WorkspaceScriptList from '../settingsPanel/mainInput/WorkspaceScriptList.svelte'
|
||||
import PickHubItems from '$lib/components/flows/pickers/PickHubItems.svelte'
|
||||
|
||||
export let name: string
|
||||
export let componentType: string | undefined = undefined
|
||||
@@ -130,11 +130,7 @@
|
||||
{:else if tab == 'workspacescripts'}
|
||||
<WorkspaceScriptList on:pick={(e) => pickScript(e.detail)} />
|
||||
{:else if tab == 'hubscripts'}
|
||||
<PickHubItems
|
||||
selectedKind="script"
|
||||
bind:filter
|
||||
on:pickScript={(e) => pickHubScript(e.detail.path)}
|
||||
/>
|
||||
<PickHubScript bind:filter on:pick={(e) => pickHubScript(e.detail.path)} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+2
-6
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { faMousePointer, faPlus } from '@fortawesome/free-solid-svg-icons'
|
||||
import { Button, Drawer, DrawerContent, Tab, Tabs } from '$lib/components/common'
|
||||
import PickHubScript from '$lib/components/flows/pickers/PickHubScript.svelte'
|
||||
import { Building, Globe2 } from 'lucide-svelte'
|
||||
import InlineScriptList from './InlineScriptList.svelte'
|
||||
import type { ResultAppInput } from '$lib/components/apps/inputType'
|
||||
@@ -11,7 +12,6 @@
|
||||
import type { Schema } from '$lib/common'
|
||||
import { getAllScriptNames, loadSchema, schemaToInputsSpec } from '$lib/components/apps/utils'
|
||||
import { emptySchema } from '$lib/utils'
|
||||
import PickHubItems from '$lib/components/flows/pickers/PickHubItems.svelte'
|
||||
|
||||
type Tab = 'hubscripts' | 'workspacescripts' | 'workspaceflows' | 'inlinescripts'
|
||||
|
||||
@@ -165,11 +165,7 @@
|
||||
{:else if tab == 'workspaceflows'}
|
||||
<WorkspaceFlowList on:pick={(e) => pickFlow(e.detail)} />
|
||||
{:else if tab == 'hubscripts'}
|
||||
<PickHubItems
|
||||
bind:filter
|
||||
on:pickScript={(e) => pickHubScript(e.detail.path)}
|
||||
selectedKind="script"
|
||||
/>
|
||||
<PickHubScript bind:filter on:pick={(e) => pickHubScript(e.detail.path)} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
import { faBolt, faCheck, faCode } from '@fortawesome/free-solid-svg-icons'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import FlowScriptPicker from '../pickers/FlowScriptPicker.svelte'
|
||||
import PickHubScript from '../pickers/PickHubScript.svelte'
|
||||
import WorkspaceScriptPicker from '../pickers/WorkspaceScriptPicker.svelte'
|
||||
import PickHubItems from '../pickers/PickHubItems.svelte'
|
||||
|
||||
export let failureModule: boolean
|
||||
export let shouldDisableTriggerScripts: boolean = false
|
||||
@@ -157,9 +157,9 @@
|
||||
>Use pre-made <span class="text-blue-500">{kind == 'script' ? 'action' : kind}</span> script</h3
|
||||
>
|
||||
{#if pick_existing == 'hub'}
|
||||
<PickHubItems bind:filter {kind} on:pickScript={() => dispatch('pick')}>
|
||||
<PickHubScript bind:filter {kind} on:pick>
|
||||
<ToggleHubWorkspace bind:selected={pick_existing} />
|
||||
</PickHubItems>
|
||||
</PickHubScript>
|
||||
{:else}
|
||||
<WorkspaceScriptPicker displayLock bind:filter {kind} on:pick>
|
||||
<ToggleHubWorkspace bind:selected={pick_existing} />
|
||||
|
||||
@@ -1,34 +1,81 @@
|
||||
<script lang="ts">
|
||||
import { Badge } from '$lib/components/common'
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
import { Badge, Skeleton } from '$lib/components/common'
|
||||
import SearchItems from '$lib/components/SearchItems.svelte'
|
||||
import { loadHubApps } from '$lib/utils'
|
||||
import ListFilters from '$lib/components/home/ListFilters.svelte'
|
||||
import NoItemFound from '$lib/components/home/NoItemFound.svelte'
|
||||
import RowIcon from '$lib/components/common/table/RowIcon.svelte'
|
||||
import type { HubApp } from '$lib/stores'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
export let item: HubApp & { marked?: string }
|
||||
export let filter = ''
|
||||
|
||||
type Item = { apps: string[]; summary: string; path: string }
|
||||
let hubApps: any[] | undefined = undefined
|
||||
let filteredItems: (Item & { marked?: string })[] = []
|
||||
let appFilter: string | undefined = undefined
|
||||
|
||||
$: prefilteredItems = appFilter
|
||||
? (hubApps ?? []).filter((i) => i.apps.includes(appFilter))
|
||||
: hubApps ?? []
|
||||
|
||||
$: apps = Array.from(new Set(filteredItems?.flatMap((x) => x.apps) ?? [])).sort()
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
onMount(async () => {
|
||||
hubApps = await loadHubApps()
|
||||
})
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="p-4 gap-4 flex flex-row grow justify-between hover:bg-gray-50 bg-white transition-all items-center rounded-md"
|
||||
on:click={() => dispatch('pick', item)}
|
||||
>
|
||||
<div class="flex items-center gap-4">
|
||||
<RowIcon kind="app" />
|
||||
<SearchItems
|
||||
{filter}
|
||||
items={prefilteredItems}
|
||||
bind:filteredItems
|
||||
f={(x) => x.summary + ' (' + x.apps.join(', ') + ')'}
|
||||
/>
|
||||
<div class="w-full flex mt-1 items-center gap-2">
|
||||
<slot />
|
||||
<input type="text" placeholder="Search Hub Apps" bind:value={filter} class="text-2xl grow" />
|
||||
</div>
|
||||
<ListFilters filters={apps} bind:selectedFilter={appFilter} resourceType />
|
||||
|
||||
<div class="w-full text-left font-normal">
|
||||
<div class="text-gray-900 flex-wrap text-md font-semibold mb-1">
|
||||
{#if item.marked}
|
||||
{@html item.marked ?? ''}
|
||||
{:else}
|
||||
{item.summary ?? ''}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="min-w-1/3 gap-2 flex flex-wrap justify-end">
|
||||
{#each item.apps as app}
|
||||
<Badge color="gray" baseClass="border">{app}</Badge>
|
||||
{/each}
|
||||
</div>
|
||||
</button>
|
||||
{#if hubApps}
|
||||
{#if filteredItems.length == 0}
|
||||
<NoItemFound />
|
||||
{:else}
|
||||
<ul class="divide-y divide-gray-200 border rounded-md">
|
||||
{#each filteredItems as item (item)}
|
||||
<li class="flex flex-row w-full">
|
||||
<button
|
||||
class="p-4 gap-4 flex flex-row grow justify-between hover:bg-gray-50 bg-white transition-all items-center rounded-md"
|
||||
on:click={() => dispatch('pick', item)}
|
||||
>
|
||||
<div class="flex items-center gap-4">
|
||||
<RowIcon kind="app" />
|
||||
|
||||
<div class="w-full text-left font-normal ">
|
||||
<div class="text-gray-900 flex-wrap text-md font-semibold mb-1">
|
||||
{#if item.marked}
|
||||
{@html item.marked ?? ''}
|
||||
{:else}
|
||||
{item.summary ?? ''}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="min-w-1/3 gap-2 flex flex-wrap justify-end">
|
||||
{#each item.apps as app}
|
||||
<Badge color="gray" baseClass="border">{app}</Badge>
|
||||
{/each}
|
||||
</div>
|
||||
</button>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="my-2" />
|
||||
{#each Array(10).fill(0) as _}
|
||||
<Skeleton layout={[[4], 0.5]} />
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
@@ -1,34 +1,82 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { Badge } from '$lib/components/common'
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
import { Badge, Skeleton } from '$lib/components/common'
|
||||
import SearchItems from '$lib/components/SearchItems.svelte'
|
||||
import { loadHubFlows } from '$lib/utils'
|
||||
import ListFilters from '$lib/components/home/ListFilters.svelte'
|
||||
import NoItemFound from '$lib/components/home/NoItemFound.svelte'
|
||||
import RowIcon from '$lib/components/common/table/RowIcon.svelte'
|
||||
import type { HubFlow } from '$lib/stores'
|
||||
|
||||
export let item: HubFlow & { marked?: string }
|
||||
export let filter = ''
|
||||
|
||||
type Item = { apps: string[]; summary: string; path: string }
|
||||
let hubFlows: any[] | undefined = undefined
|
||||
let filteredItems: (Item & { marked?: string })[] = []
|
||||
let appFilter: string | undefined = undefined
|
||||
|
||||
$: prefilteredItems = appFilter
|
||||
? (hubFlows ?? []).filter((i) => i.apps.includes(appFilter))
|
||||
: hubFlows ?? []
|
||||
|
||||
$: apps = Array.from(new Set(filteredItems?.flatMap((x) => x.apps) ?? [])).sort()
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
onMount(async () => {
|
||||
hubFlows = await loadHubFlows()
|
||||
})
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="p-4 gap-4 flex flex-row grow justify-between hover:bg-gray-50 bg-white transition-all items-center rounded-md"
|
||||
on:click={() => dispatch('pick', item)}
|
||||
>
|
||||
<div class="flex items-center gap-4">
|
||||
<RowIcon kind="flow" />
|
||||
<SearchItems
|
||||
{filter}
|
||||
items={prefilteredItems}
|
||||
bind:filteredItems
|
||||
f={(x) => x.summary + ' (' + x.apps.join(', ') + ')'}
|
||||
/>
|
||||
<div class="w-full flex mt-1 items-center gap-2">
|
||||
<slot />
|
||||
<input type="text" placeholder="Search Hub Flows" bind:value={filter} class="text-2xl grow" />
|
||||
</div>
|
||||
<ListFilters filters={apps} bind:selectedFilter={appFilter} resourceType />
|
||||
|
||||
<div class="w-full text-left font-normal">
|
||||
<div class="text-gray-900 flex-wrap text-md font-semibold mb-1">
|
||||
{#if item.marked}
|
||||
{@html item.marked ?? ''}
|
||||
{:else}
|
||||
{item.summary ?? ''}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="min-w-1/3 gap-2 flex flex-wrap justify-end">
|
||||
{#each item.apps as app}
|
||||
<Badge color="gray" baseClass="border">{app}</Badge>
|
||||
{/each}
|
||||
</div>
|
||||
</button>
|
||||
{#if hubFlows}
|
||||
{#if filteredItems.length == 0}
|
||||
<NoItemFound />
|
||||
{:else}
|
||||
<ul class="divide-y divide-gray-200 border rounded-md">
|
||||
{#each filteredItems as item (item)}
|
||||
<li class="flex flex-row w-full">
|
||||
<button
|
||||
class="p-4 gap-4 flex flex-row grow justify-between hover:bg-gray-50 bg-white transition-all items-center rounded-md"
|
||||
on:click={() => dispatch('pick', item)}
|
||||
>
|
||||
<div class="flex items-center gap-4">
|
||||
<RowIcon kind="flow" />
|
||||
|
||||
<div class="w-full text-left font-normal ">
|
||||
<div class="text-gray-900 flex-wrap text-md font-semibold mb-1">
|
||||
{#if item.marked}
|
||||
{@html item.marked ?? ''}
|
||||
{:else}
|
||||
{item.summary ?? ''}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="min-w-1/3 gap-2 flex flex-wrap justify-end">
|
||||
{#each item.apps as app}
|
||||
<Badge color="gray" baseClass="border">{app}</Badge>
|
||||
{/each}
|
||||
</div>
|
||||
</button>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="my-2" />
|
||||
|
||||
{#each Array(10).fill(0) as _}
|
||||
<Skeleton layout={[[4], 0.5]} />
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
<!-- PickHubItems.svelte -->
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
import { Skeleton, ToggleButton, ToggleButtonGroup } from '$lib/components/common'
|
||||
import SearchItems from '$lib/components/SearchItems.svelte'
|
||||
import { loadHubScripts, loadHubFlows, loadHubApps } from '$lib/utils'
|
||||
import ListFilters from '$lib/components/home/ListFilters.svelte'
|
||||
import NoItemFound from '$lib/components/home/NoItemFound.svelte'
|
||||
import { hubScripts, hubFlows, hubApps, type HubItem } from '$lib/stores'
|
||||
import PickHubScript from './PickHubScript.svelte'
|
||||
import PickHubFlow from './PickHubFlow.svelte'
|
||||
import PickHubApp from './PickHubApp.svelte'
|
||||
import { faBarsStaggered } from '@fortawesome/free-solid-svg-icons'
|
||||
import { Code2, LayoutDashboard } from 'lucide-svelte'
|
||||
import { Icon } from 'svelte-awesome'
|
||||
|
||||
export let filter = ''
|
||||
export let selectedKind: 'script' | 'flow' | 'app' | undefined = undefined
|
||||
export let kind: 'script' | 'trigger' | 'approval' | 'failure' | undefined = undefined
|
||||
|
||||
let itemKind: 'script' | 'flow' | 'app' = 'app'
|
||||
const dispatch = createEventDispatcher()
|
||||
let filteredItems: (HubItem & { marked?: string })[] = []
|
||||
let appFilter: string | undefined = undefined
|
||||
|
||||
$: items = [
|
||||
...($hubScripts?.map((s) => ({ itemType: 'script', data: s })) ?? []),
|
||||
...($hubFlows?.map((s) => ({ itemType: 'flow', data: s })) ?? []),
|
||||
...($hubApps?.map((s) => ({ itemType: 'app', data: s })) ?? [])
|
||||
] as HubItem[]
|
||||
|
||||
$: apps = Array.from(
|
||||
new Set(
|
||||
filteredItems
|
||||
?.map((x) => {
|
||||
if (x.itemType === 'script') {
|
||||
return x.data.app
|
||||
} else if (x.itemType === 'flow') {
|
||||
return x.data.apps
|
||||
} else if (x.itemType === 'app') {
|
||||
return x.data.apps
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
})
|
||||
.filter(Boolean)
|
||||
.flat() ?? []
|
||||
)
|
||||
).sort() as string[]
|
||||
|
||||
$: prefilteredItems =
|
||||
appFilter || itemKind
|
||||
? items.filter((i) => {
|
||||
if (i.itemType !== itemKind) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (selectedKind && i.itemType !== selectedKind) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (i.itemType === 'script' && appFilter) {
|
||||
return i.data.app === appFilter
|
||||
} else if (i.itemType === 'flow' && appFilter) {
|
||||
return i.data.apps.includes(appFilter)
|
||||
} else if (i.itemType === 'app' && appFilter) {
|
||||
return i.data.apps.includes(appFilter)
|
||||
}
|
||||
return true
|
||||
})
|
||||
: items
|
||||
|
||||
let notLoaded = true
|
||||
async function loadApps() {
|
||||
$hubApps = await loadHubApps()
|
||||
notLoaded = false
|
||||
}
|
||||
|
||||
async function loadFlows() {
|
||||
loadHubFlows()
|
||||
}
|
||||
onMount(async () => {
|
||||
loadHubScripts()
|
||||
loadApps()
|
||||
loadFlows()
|
||||
})
|
||||
</script>
|
||||
|
||||
<SearchItems {filter} items={prefilteredItems} bind:filteredItems f={(x) => x.data.summary} />
|
||||
<div class="w-full flex mt-1 items-center gap-2">
|
||||
{#if selectedKind === undefined}
|
||||
<ToggleButtonGroup bind:selected={itemKind}>
|
||||
<ToggleButton light position="left" value="script" size="sm">
|
||||
<div class="flex gap-1 items-center">
|
||||
<Code2 size={16} />
|
||||
Scripts
|
||||
</div>
|
||||
</ToggleButton>
|
||||
<ToggleButton light position="center" value="flow" size="sm">
|
||||
<div class="flex gap-1 items-center">
|
||||
<Icon data={faBarsStaggered} scale={0.8} class="mr-1" />
|
||||
Flows
|
||||
</div>
|
||||
</ToggleButton>
|
||||
<ToggleButton light position="right" value="app" size="sm">
|
||||
<div class="flex gap-1 items-center">
|
||||
<LayoutDashboard size={16} />
|
||||
Apps
|
||||
</div>
|
||||
</ToggleButton>
|
||||
</ToggleButtonGroup>
|
||||
{/if}
|
||||
<input type="text" placeholder="Search Hub Items" bind:value={filter} class="text-2xl grow" />
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<ListFilters filters={apps} bind:selectedFilter={appFilter} resourceType />
|
||||
|
||||
{#if Array.isArray(prefilteredItems)}
|
||||
{#if notLoaded}
|
||||
{#each Array(10).fill(0) as _}
|
||||
<Skeleton layout={[[4], 0.5]} />
|
||||
{/each}
|
||||
{:else if filteredItems.length == 0}
|
||||
<NoItemFound />
|
||||
{:else}
|
||||
<ul class="divide-y divide-gray-200 border rounded-md">
|
||||
{#each filteredItems as item, index (index)}
|
||||
<li class="flex flex-row w-full">
|
||||
{#if item.itemType === 'script'}
|
||||
<PickHubScript
|
||||
item={item.data}
|
||||
on:pick={() => dispatch('pickScript', item.data)}
|
||||
{kind}
|
||||
/>
|
||||
{:else if item.itemType === 'flow'}
|
||||
<PickHubFlow item={item.data} on:pick={() => dispatch('pickFlow', item.data)} />
|
||||
{:else if item.itemType === 'app'}
|
||||
<PickHubApp item={item.data} on:pick={() => dispatch('pickApp', item.data)} />
|
||||
{/if}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="my-2" />
|
||||
{#each Array(10).fill(0) as _}
|
||||
<Skeleton layout={[[4], 0.5]} />
|
||||
{/each}
|
||||
{/if}
|
||||
@@ -1,44 +1,95 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { Badge } from '$lib/components/common'
|
||||
import { capitalize, classNames } from '$lib/utils'
|
||||
import { hubScripts } from '$lib/stores'
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
import type { HubItem } from './model'
|
||||
import { Badge, Skeleton } from '$lib/components/common'
|
||||
import SearchItems from '$lib/components/SearchItems.svelte'
|
||||
import { capitalize, classNames, loadHubScripts } from '$lib/utils'
|
||||
import NoItemFound from '$lib/components/home/NoItemFound.svelte'
|
||||
import { APP_TO_ICON_COMPONENT } from '$lib/components/icons'
|
||||
import type { HubScript } from '$lib/stores'
|
||||
import ListFilters from '$lib/components/home/ListFilters.svelte'
|
||||
|
||||
export let kind: 'script' | 'trigger' | 'approval' | 'failure' = 'script'
|
||||
export let item: HubScript & { marked?: string }
|
||||
export let filter = ''
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let filteredItems: (HubItem & { marked?: string })[] = []
|
||||
let appFilter: string | undefined = undefined
|
||||
|
||||
$: items = ($hubScripts ?? []).filter((i) => i.kind === kind)
|
||||
$: prefilteredItems = appFilter ? (items ?? []).filter((i) => i.app == appFilter) : items ?? []
|
||||
$: apps = Array.from(new Set(filteredItems?.map((x) => x.app) ?? [])).sort()
|
||||
|
||||
onMount(() => {
|
||||
if (!$hubScripts) {
|
||||
loadHubScripts()
|
||||
}
|
||||
})
|
||||
const maxItems = 40
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="p-4 gap-4 flex flex-row grow hover:bg-gray-50 bg-white transition-all items-center rounded-md"
|
||||
on:click={() => dispatch('pick', item)}
|
||||
>
|
||||
<div class="flex items-center gap-4">
|
||||
<div
|
||||
class={classNames(
|
||||
'rounded-md p-1 flex justify-center items-center border',
|
||||
'bg-gray-50 border-gray-200'
|
||||
)}
|
||||
>
|
||||
<svelte:component this={APP_TO_ICON_COMPONENT[item['app']]} height={18} width={18} />
|
||||
</div>
|
||||
<SearchItems {filter} items={prefilteredItems} bind:filteredItems f={(x) => x.summary} />
|
||||
<div class="w-full flex mt-1 items-center gap-2">
|
||||
<slot />
|
||||
<input type="text" placeholder="Search Hub Scripts" bind:value={filter} class="text-2xl grow" />
|
||||
</div>
|
||||
<ListFilters filters={apps} bind:selectedFilter={appFilter} resourceType />
|
||||
|
||||
<div class="w-full text-left font-normal">
|
||||
<div class="text-gray-900 flex-wrap text-md font-semibold mb-1">
|
||||
{#if item.marked}
|
||||
{@html item.marked ?? ''}
|
||||
{:else}
|
||||
{item.summary ?? ''}
|
||||
{/if}
|
||||
</div>
|
||||
<div class="text-gray-600 text-xs">
|
||||
{item.path}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{#if kind !== 'script'}
|
||||
<Badge color="gray" baseClass="border">{capitalize(kind)}</Badge>
|
||||
{#if $hubScripts}
|
||||
{#if filteredItems.length == 0}
|
||||
<NoItemFound />
|
||||
{:else}
|
||||
<ul class="divide-y divide-gray-200 border rounded-md">
|
||||
{#each filteredItems.slice(0, maxItems) as item (item.path)}
|
||||
<li class="flex flex-row w-full">
|
||||
<button
|
||||
class="p-4 gap-4 flex flex-row grow hover:bg-gray-50 bg-white transition-all items-center rounded-md"
|
||||
on:click={() => dispatch('pick', item)}
|
||||
>
|
||||
<div class="flex items-center gap-4">
|
||||
<div
|
||||
class={classNames(
|
||||
'rounded-md p-1 flex justify-center items-center border',
|
||||
'bg-gray-50 border-gray-200'
|
||||
)}
|
||||
>
|
||||
<svelte:component
|
||||
this={APP_TO_ICON_COMPONENT[item['app']]}
|
||||
height={18}
|
||||
width={18}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="w-full text-left font-normal ">
|
||||
<div class="text-gray-900 flex-wrap text-md font-semibold mb-1">
|
||||
{#if item.marked}
|
||||
{@html item.marked ?? ''}
|
||||
{:else}
|
||||
{item.summary ?? ''}
|
||||
{/if}
|
||||
</div>
|
||||
<div class="text-gray-600 text-xs ">
|
||||
{item.path}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{#if kind !== 'script'}
|
||||
<Badge color="gray" baseClass="border">{capitalize(kind)}</Badge>
|
||||
{/if}
|
||||
</button>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{/if}
|
||||
</button>
|
||||
{#if filteredItems.length > maxItems}
|
||||
<div class="text-gray-500 text-sm py-4">
|
||||
There are more items ({filteredItems.length}) than being displayed. Refine your search.
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="my-2" />
|
||||
{#each Array(10).fill(0) as _}
|
||||
<Skeleton layout={[0.5, [4]]} />
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
+11
-36
@@ -52,42 +52,17 @@ export const userWorkspaces: Readable<
|
||||
return originalWorkspaces
|
||||
}
|
||||
})
|
||||
|
||||
export type HubScript = {
|
||||
path: string
|
||||
summary: string
|
||||
approved: boolean
|
||||
kind: string
|
||||
app: string
|
||||
ask_id: number
|
||||
}
|
||||
|
||||
export type HubFlow = {
|
||||
id: number
|
||||
flow_id: number
|
||||
summary: string
|
||||
apps: string[]
|
||||
approved: boolean
|
||||
votes: number
|
||||
}
|
||||
|
||||
export type HubApp = {
|
||||
id: number
|
||||
app_id: number
|
||||
summary: string
|
||||
apps: Array<string>
|
||||
approved: boolean
|
||||
votes: number
|
||||
}
|
||||
|
||||
export type HubItem =
|
||||
| { itemType: 'script'; data: HubScript & { marked?: string } }
|
||||
| { itemType: 'flow'; data: HubFlow & { marked?: string } }
|
||||
| { itemType: 'app'; data: HubApp & { marked?: string } }
|
||||
|
||||
export const hubScripts = writable<Array<HubScript> | undefined>(undefined)
|
||||
export const hubFlows = writable<Array<HubFlow> | undefined>(undefined)
|
||||
export const hubApps = writable<Array<HubApp> | undefined>(undefined)
|
||||
export const hubScripts = writable<
|
||||
| Array<{
|
||||
path: string
|
||||
summary: string
|
||||
approved: boolean
|
||||
kind: string
|
||||
app: string
|
||||
ask_id: number
|
||||
}>
|
||||
| undefined
|
||||
>(undefined)
|
||||
|
||||
if (browser) {
|
||||
workspaceStore.subscribe(async (workspace) => {
|
||||
|
||||
@@ -8,19 +8,20 @@
|
||||
import { getScriptByPath } from '$lib/utils'
|
||||
import type { HubItem } from '$lib/components/flows/pickers/model'
|
||||
import { faCodeFork } from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
import PickHubScript from '$lib/components/flows/pickers/PickHubScript.svelte'
|
||||
import PickHubFlow from '$lib/components/flows/pickers/PickHubFlow.svelte'
|
||||
import FlowViewer from '$lib/components/FlowViewer.svelte'
|
||||
import HighlightCode from '$lib/components/HighlightCode.svelte'
|
||||
import { Building, Globe2 } from 'lucide-svelte'
|
||||
|
||||
import ItemsList from '$lib/components/home/ItemsList.svelte'
|
||||
import CreateActionsApp from '$lib/components/flows/CreateActionsApp.svelte'
|
||||
import PickHubApp from '$lib/components/flows/pickers/PickHubApp.svelte'
|
||||
import AppPreview from '$lib/components/apps/editor/AppPreview.svelte'
|
||||
import { writable } from 'svelte/store'
|
||||
import type { EditorBreakpoint } from '$lib/components/apps/types'
|
||||
import PickHubItems from '$lib/components/flows/pickers/PickHubItems.svelte'
|
||||
|
||||
type Tab = 'hub' | 'workspace'
|
||||
type Tab = 'hubscripts' | 'hubflows' | 'hubapps' | 'workspace'
|
||||
|
||||
let tab: Tab = window.location.hash?.includes('#')
|
||||
? (window.location.hash?.replace('#', '') as Tab)
|
||||
@@ -202,10 +203,22 @@
|
||||
Workspace
|
||||
</div>
|
||||
</Tab>
|
||||
<Tab size="md" value="hub">
|
||||
<Tab size="md" value="hubscripts">
|
||||
<div class="flex gap-2 items-center my-1">
|
||||
<Globe2 size={18} />
|
||||
Hub
|
||||
Hub Scripts
|
||||
</div>
|
||||
</Tab>
|
||||
<Tab size="md" value="hubflows">
|
||||
<div class="flex gap-2 items-center my-1">
|
||||
<Globe2 size={18} />
|
||||
Hub Flows
|
||||
</div>
|
||||
</Tab>
|
||||
<Tab size="md" value="hubapps">
|
||||
<div class="flex gap-2 items-center my-1">
|
||||
<Globe2 size={18} />
|
||||
Hub Apps
|
||||
</div>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
@@ -214,17 +227,24 @@
|
||||
<div class="my-2" />
|
||||
<div class="flex flex-col gap-y-16">
|
||||
<div class="flex flex-col">
|
||||
{#if tab == 'hub'}
|
||||
<PickHubItems
|
||||
bind:filter
|
||||
on:pickApp={(e) => viewApp(e.detail)}
|
||||
on:pickFlow={(e) => viewFlow(e.detail)}
|
||||
on:pickScript={(e) => viewCode(e.detail)}
|
||||
{#if tab == 'hubscripts'}
|
||||
<PickHubScript bind:filter on:pick={(e) => viewCode(e.detail)}
|
||||
><Button target="_blank" href="https://hub.windmill.dev" variant="border" color="light"
|
||||
>Go to Hub</Button
|
||||
></PickHubScript
|
||||
>
|
||||
{:else if tab == 'hubflows'}
|
||||
<PickHubFlow bind:filter on:pick={(e) => viewFlow(e.detail)}
|
||||
><Button target="_blank" href="https://hub.windmill.dev" variant="border" color="light"
|
||||
>Go to Hub</Button
|
||||
></PickHubFlow
|
||||
>
|
||||
{:else if tab == 'hubapps'}
|
||||
<PickHubApp bind:filter on:pick={(e) => viewApp(e.detail)}
|
||||
><Button target="_blank" href="https://hub.windmill.dev" variant="border" color="light"
|
||||
>Go to Hub</Button
|
||||
></PickHubApp
|
||||
>
|
||||
<Button target="_blank" href="https://hub.windmill.dev" variant="border" color="light">
|
||||
Go to Hub
|
||||
</Button>
|
||||
</PickHubItems>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user