mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-24 00:00:46 +00:00
favorites on the sidebar
This commit is contained in:
@@ -71,5 +71,5 @@ async fn unstar(
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
Ok(format!("Starred {}", path))
|
||||
Ok(format!("Unstarred {}", path))
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ async fn list_flows(
|
||||
.left()
|
||||
.join("favorite")
|
||||
.on(
|
||||
"favorite.favorite_kind = 'flow' AND favorite.path = o.path AND favorite.usr = ?"
|
||||
"favorite.favorite_kind = 'flow' AND favorite.workspace_id = o.workspace_id AND favorite.path = o.path AND favorite.usr = ?"
|
||||
.bind(&authed.username),
|
||||
)
|
||||
.order_desc("favorite.path IS NOT NULL")
|
||||
@@ -94,8 +94,8 @@ async fn list_flows(
|
||||
if let Some(cb) = &lq.edited_by {
|
||||
sqlb.and_where_eq("edited_by", "?".bind(cb));
|
||||
}
|
||||
if let Some(so) = &lq.starred_only {
|
||||
sqlb.and_where_eq("starred", "?".bind(so));
|
||||
if lq.starred_only.unwrap_or(false) {
|
||||
sqlb.and_where_is_not_null("favorite.path");
|
||||
}
|
||||
|
||||
let sql = sqlb.sql().map_err(|e| Error::InternalErr(e.to_string()))?;
|
||||
|
||||
@@ -102,7 +102,7 @@ async fn list_scripts(
|
||||
.left()
|
||||
.join("favorite")
|
||||
.on(
|
||||
"favorite.favorite_kind = 'script' AND favorite.path = o.path AND favorite.usr = ?"
|
||||
"favorite.favorite_kind = 'script' AND favorite.workspace_id = o.workspace_id AND favorite.path = o.path AND favorite.usr = ?"
|
||||
.bind(&authed.username),
|
||||
)
|
||||
.order_desc("favorite.path IS NOT NULL")
|
||||
@@ -146,8 +146,8 @@ async fn list_scripts(
|
||||
if let Some(k) = &lq.kind {
|
||||
sqlb.and_where_eq("kind", "?".bind(&k.to_lowercase()));
|
||||
}
|
||||
if let Some(so) = &lq.starred_only {
|
||||
sqlb.and_where_eq("starred", "?".bind(so));
|
||||
if lq.starred_only.unwrap_or(false) {
|
||||
sqlb.and_where_is_not_null("favorite.path");
|
||||
}
|
||||
|
||||
let sql = sqlb.sql().map_err(|e| Error::InternalErr(e.to_string()))?;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { FavoriteService } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { starStore, workspaceStore } from '$lib/stores'
|
||||
import { sendUserToast } from '$lib/utils'
|
||||
import { faStar } from '@fortawesome/free-solid-svg-icons'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
@@ -17,13 +17,15 @@
|
||||
workspace: $workspaceStore!,
|
||||
requestBody: { path, favorite_kind: kind }
|
||||
})
|
||||
sendUserToast('Marked as favorite, it will appear first in the list')
|
||||
sendUserToast('Unstarred')
|
||||
$starStore = $starStore + 1
|
||||
} else {
|
||||
await FavoriteService.star({
|
||||
workspace: $workspaceStore!,
|
||||
requestBody: { path, favorite_kind: kind }
|
||||
})
|
||||
sendUserToast('Marked as favorite, it will appear first in the list')
|
||||
sendUserToast('Marked as favorite, it will appear first')
|
||||
$starStore = $starStore + 1
|
||||
}
|
||||
dispatch('starred', !starred)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import {
|
||||
faBookOpen,
|
||||
faCalendar,
|
||||
faCode,
|
||||
faCubes,
|
||||
faEye,
|
||||
faHomeAlt,
|
||||
@@ -10,12 +9,13 @@
|
||||
faRobot,
|
||||
faUsersCog,
|
||||
faWallet,
|
||||
faWind,
|
||||
faCog
|
||||
faCog,
|
||||
faStar
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import { faDiscord, faGithub } from '@fortawesome/free-brands-svg-icons'
|
||||
import MenuLink from './MenuLink.svelte'
|
||||
import { userStore } from '$lib/stores'
|
||||
import { starStore, userStore, workspaceStore } from '$lib/stores'
|
||||
import { FlowService, ScriptService } from '$lib/gen'
|
||||
|
||||
const mainMenuLinks = [
|
||||
{ label: 'Home', href: '/', icon: faHomeAlt },
|
||||
@@ -25,6 +25,8 @@
|
||||
{ label: 'Resources', href: '/resources', icon: faCubes }
|
||||
]
|
||||
|
||||
export let favoriteLinks = [] as { label: string; href: string }[]
|
||||
|
||||
$: secondaryMenuLinks = [
|
||||
{ label: 'Groups', href: '/groups', icon: faUsersCog },
|
||||
{ label: 'Audit Logs', href: '/audit_logs', icon: faEye },
|
||||
@@ -53,17 +55,23 @@
|
||||
<div class="flex-1 flex flex-col py-4 overflow-x-hidden scrollbar-hidden">
|
||||
<nav class="h-full flex justify-between flex-col px-2">
|
||||
<div class="space-y-1 pt-4">
|
||||
{#each mainMenuLinks as menuLink}
|
||||
{#each mainMenuLinks as menuLink (menuLink.href)}
|
||||
<MenuLink class="text-lg" {...menuLink} {isCollapsed} />
|
||||
{/each}
|
||||
<div class="h-2" />
|
||||
<div class="max-h-40 overflow-y-auto flex flex-col space-y-1.5 max-w-xs">
|
||||
{#each favoriteLinks as menuLink (menuLink.href)}
|
||||
<MenuLink class="text-xs max-w-xs truncate" {...menuLink} {isCollapsed} icon={faStar} />
|
||||
{/each}
|
||||
</div>
|
||||
<div class="h-2" />
|
||||
</div>
|
||||
|
||||
<div class="space-1-2">
|
||||
{#each secondaryMenuLinks as menuLink}
|
||||
{#each secondaryMenuLinks as menuLink (menuLink.href)}
|
||||
<MenuLink class="text-xs" {...menuLink} {isCollapsed} />
|
||||
{/each}
|
||||
<div class="h-8" />
|
||||
{#each thirdMenuLinks as menuLink}
|
||||
{#each thirdMenuLinks as menuLink (menuLink.href)}
|
||||
<MenuLink class="text-xs" {...menuLink} {isCollapsed} />
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
@@ -20,6 +20,7 @@ export const userStore = writable<UserExt | undefined>(undefined)
|
||||
export const workspaceStore = writable<string | undefined>(
|
||||
persistedWorkspace ? String(persistedWorkspace) : undefined
|
||||
)
|
||||
export const starStore = writable(1)
|
||||
export const usersWorkspaceStore = writable<UserWorkspaceList | undefined>(undefined)
|
||||
export const superadmin = writable<String | false | undefined>(undefined)
|
||||
export const hubScripts = writable<
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
import Icon from 'svelte-awesome'
|
||||
|
||||
import UserMenu from '$lib/components/sidebar/UserMenu.svelte'
|
||||
import { OpenAPI } from '$lib/gen'
|
||||
import { FlowService, OpenAPI, ScriptService } from '$lib/gen'
|
||||
import { classNames } from '$lib/utils'
|
||||
|
||||
import WorkspaceMenu from '$lib/components/sidebar/WorkspaceMenu.svelte'
|
||||
import SidebarContent from '$lib/components/sidebar/SidebarContent.svelte'
|
||||
import '../app.css'
|
||||
import { superadmin, userStore } from '$lib/stores'
|
||||
import { starStore, superadmin, userStore, workspaceStore } from '$lib/stores'
|
||||
import CenteredModal from '$lib/components/CenteredModal.svelte'
|
||||
import { beforeNavigate, goto } from '$app/navigation'
|
||||
import UserSettings from '$lib/components/UserSettings.svelte'
|
||||
@@ -34,6 +34,30 @@
|
||||
|
||||
let innerWidth = window.innerWidth
|
||||
|
||||
let favoriteLinks = [] as { label: string; href: string }[]
|
||||
$: $workspaceStore && $starStore && loadFavorites()
|
||||
|
||||
async function loadFavorites() {
|
||||
const scripts = await ScriptService.listScripts({
|
||||
workspace: $workspaceStore ?? '',
|
||||
starredOnly: true
|
||||
})
|
||||
const flows = await FlowService.listFlows({
|
||||
workspace: $workspaceStore ?? '',
|
||||
starredOnly: true
|
||||
})
|
||||
favoriteLinks = [
|
||||
...scripts.map((s) => ({
|
||||
label: s.summary || s.path,
|
||||
href: `/scripts/run/${s.hash}`
|
||||
})),
|
||||
...flows.map((f) => ({
|
||||
label: f.summary || f.path,
|
||||
href: `/flows/run/${f.path}`
|
||||
}))
|
||||
]
|
||||
}
|
||||
|
||||
$: innerWidth < 1248 && innerWidth >= 768 && (isCollapsed = true)
|
||||
$: (innerWidth >= 1248 || innerWidth < 768) && (isCollapsed = false)
|
||||
</script>
|
||||
@@ -116,7 +140,7 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<SidebarContent {isCollapsed} />
|
||||
<SidebarContent {favoriteLinks} {isCollapsed} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -155,7 +179,7 @@
|
||||
{isCollapsed}
|
||||
/>
|
||||
</div>
|
||||
<SidebarContent {isCollapsed} />
|
||||
<SidebarContent {favoriteLinks} {isCollapsed} />
|
||||
|
||||
<div class="flex-shrink-0 flex px-4 pb-3.5 pt-3 border-t border-gray-300">
|
||||
<button
|
||||
|
||||
@@ -334,7 +334,7 @@
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 lg:grid-cols-2 mt-2 w-full">
|
||||
{#if !loading}
|
||||
{#each filter != '' ? filteredItems : preFilteredItems as item (item.path)}
|
||||
{#each filter != '' ? filteredItems : preFilteredItems as item (item.type + item.path)}
|
||||
{#if item.type == 'script'}
|
||||
<ScriptBox
|
||||
starred={item.starred}
|
||||
|
||||
Reference in New Issue
Block a user