mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-27 16:02:43 +00:00
feat: implement usage tracker + quotas
This commit is contained in:
@@ -77,7 +77,7 @@
|
||||
<div class="flex flex-row justify-between">The next runs will be scheduled at:</div>
|
||||
<ul class="list-disc mx-12">
|
||||
{#each preview.slice(0, limit) as p}
|
||||
<li class="mx-2 text-gray-700 text-sm">{displayDate(p)}</li>
|
||||
<li class="mx-2 text-gray-700 text-sm">{displayDate(p, true)}</li>
|
||||
{/each}
|
||||
<li class="text-sm mx-2">...</li>
|
||||
{#if limit != 10}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
dispatch('click', { item: item?.eventName })
|
||||
}
|
||||
}}
|
||||
class="block whitespace-nowrap hover:drop-shadow-sm hover:bg-gray-50 hover:bg-opacity-30 px-4 py-2 text-sm text-gray-700 text-left{item.separatorTop
|
||||
class="block w-full whitespace-nowrap hover:drop-shadow-sm hover:bg-gray-50 hover:bg-opacity-30 px-4 py-2 text-sm text-gray-700 text-left {item.separatorTop
|
||||
? 'border-t'
|
||||
: ''} {item.separatorBottom ? 'border-b' : ''} {item.type == 'delete'
|
||||
? 'text-red-500'
|
||||
@@ -64,7 +64,7 @@
|
||||
close()
|
||||
}
|
||||
}}
|
||||
class="block px-4 py-2 text-sm text-gray-700 hover:drop-shadow-sm hover:bg-gray-50 hover:bg-opacity-30"
|
||||
class="block w-full px-4 py-2 text-sm text-gray-700 hover:drop-shadow-sm hover:bg-gray-50 hover:bg-opacity-30"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
id="user-menu-item-{name}-{i}}"
|
||||
@@ -81,7 +81,7 @@
|
||||
</a>
|
||||
{:else}
|
||||
<span
|
||||
class="block px-4 py-2 text-sm text-gray-700"
|
||||
class="block px-4 py-2 text-sm text-gray-700"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
id="user-menu-item-{name}-{i}}"
|
||||
|
||||
@@ -28,13 +28,13 @@
|
||||
fill: #ffffff;
|
||||
}
|
||||
.st2 {
|
||||
fill: #999;
|
||||
fill: #bcd4fc;
|
||||
}
|
||||
.st3 {
|
||||
fill: black;
|
||||
fill: #3b82f6;
|
||||
}
|
||||
.st4 {
|
||||
fill: #999;
|
||||
fill: #b3b3b3;
|
||||
}
|
||||
.st5 {
|
||||
fill: url(#SVGID_1_);
|
||||
|
||||
@@ -8,6 +8,7 @@ export interface UserExt {
|
||||
email: string;
|
||||
username: string;
|
||||
is_admin: boolean;
|
||||
is_super_admin: boolean;
|
||||
created_at: string;
|
||||
groups: string[];
|
||||
pgroups: string[];
|
||||
|
||||
@@ -4,7 +4,7 @@ import { FlowService, Script, ScriptService, type Flow, type FlowModule, type Us
|
||||
import { toast } from '@zerodevx/svelte-toast'
|
||||
import { get } from 'svelte/store'
|
||||
import type { Schema, SupportedLanguage } from './common'
|
||||
import { hubScripts, superadmin, workspaceStore, type UserExt } from './stores'
|
||||
import { hubScripts, workspaceStore, type UserExt } from './stores'
|
||||
|
||||
export function validateUsername(username: string): string {
|
||||
if (username != '' && !/^\w+$/.test(username)) {
|
||||
@@ -179,7 +179,7 @@ export function canWrite(
|
||||
if (!user) {
|
||||
return false
|
||||
}
|
||||
if (user.is_admin || get(superadmin)) {
|
||||
if (user.is_admin || user.is_super_admin) {
|
||||
return true
|
||||
}
|
||||
let userOwner = `u/${user.username}`
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
<script context="module">
|
||||
export function load({ params }) {
|
||||
return {
|
||||
stuff: { title: `Script ${params.hash}` }
|
||||
stuff: { title: `App ${params.path}` }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores'
|
||||
import AppEditor from '$lib/components/apps/editor/AppEditor.svelte'
|
||||
import AppPreview from '$lib/components/apps/editor/AppPreview.svelte'
|
||||
|
||||
import CenteredPage from '$lib/components/CenteredPage.svelte'
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
import ShareModal from '$lib/components/ShareModal.svelte'
|
||||
import SharedBadge from '$lib/components/SharedBadge.svelte'
|
||||
import {
|
||||
faCircle,
|
||||
faEdit,
|
||||
faPlus,
|
||||
faShare,
|
||||
@@ -28,6 +29,8 @@
|
||||
import CenteredPage from '$lib/components/CenteredPage.svelte'
|
||||
import Toggle from '$lib/components/Toggle.svelte'
|
||||
import { Badge, Button, Skeleton } from '$lib/components/common'
|
||||
import Popover from '$lib/components/Popover.svelte'
|
||||
import { Icon } from 'svelte-awesome'
|
||||
|
||||
type ScheduleW = Schedule & { canWrite: boolean }
|
||||
|
||||
@@ -51,7 +54,7 @@
|
||||
})
|
||||
loadSchedules()
|
||||
} catch (err) {
|
||||
sendUserToast(`Cannot ` + (enabled ? 'disable' : 'enable') + ` schedule: ${err}`, true)
|
||||
sendUserToast(`Cannot ` + (enabled ? 'enable' : 'disable') + ` schedule: ${err.body}`, true)
|
||||
loadSchedules()
|
||||
}
|
||||
}
|
||||
@@ -79,13 +82,14 @@
|
||||
<th>Schedule</th>
|
||||
<th>Script or Flow</th>
|
||||
<th>schedule</th>
|
||||
<th />
|
||||
<th>off/on</th>
|
||||
<th>timezone</th>
|
||||
<th>last edit</th>
|
||||
<th />
|
||||
</tr>
|
||||
<tbody slot="body">
|
||||
{#each schedules as { path, edited_by, edited_at, schedule, offset_, enabled, script_path, is_flow, extra_perms, canWrite }}
|
||||
{#each schedules as { path, error, edited_by, edited_at, schedule, offset_, enabled, script_path, is_flow, extra_perms, canWrite }}
|
||||
<tr class={enabled ? '' : 'bg-gray-50'}>
|
||||
<td class="max-w-sm"
|
||||
><a class="break-words text-sm" href="/schedule/add?edit={path}&isFlow={is_flow}"
|
||||
@@ -101,6 +105,32 @@
|
||||
></div
|
||||
>
|
||||
</td><td><Badge color="blue">{schedule}</Badge></td>
|
||||
<td>
|
||||
<div class="w-10">
|
||||
{#if error}
|
||||
<Popover notClickable>
|
||||
<span class="flex h-4 w-4">
|
||||
<Icon
|
||||
class="text-red-600 animate-ping absolute inline-flex "
|
||||
data={faCircle}
|
||||
scale={0.7}
|
||||
label="Error during last job scheduling"
|
||||
/>
|
||||
<Icon
|
||||
class="text-red-600 relative inline-flex"
|
||||
data={faCircle}
|
||||
scale={0.7}
|
||||
label="Error during last job scheduling"
|
||||
/>
|
||||
</span>
|
||||
<div slot="text">
|
||||
The schedule disabled itself because there was an error scheduling the next
|
||||
job: {error}
|
||||
</div>
|
||||
</Popover>
|
||||
{/if}
|
||||
</div></td
|
||||
>
|
||||
<td>
|
||||
<Toggle
|
||||
checked={enabled}
|
||||
@@ -117,8 +147,8 @@
|
||||
<td
|
||||
><span class="text-2xs">By {edited_by} <br />the {displayDate(edited_at)}</span></td
|
||||
>
|
||||
<td
|
||||
><Dropdown
|
||||
<td>
|
||||
<Dropdown
|
||||
placement="bottom-end"
|
||||
dropdownItems={[
|
||||
{
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
sendUserToast(`Job <a href='/run/${run}?workspace=${$workspaceStore}'>${run}</a> started`)
|
||||
goto('/run/' + run + '?workspace=' + $workspaceStore)
|
||||
} catch (err) {
|
||||
sendUserToast(`Could not create job: ${err}`, true)
|
||||
sendUserToast(`Could not create job: ${err.body}`, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -229,12 +229,20 @@
|
||||
<div class="w-10">
|
||||
{#if refresh_error}
|
||||
<Popover notClickable>
|
||||
<Icon
|
||||
class="text-red-600 animate-[pulse_5s_linear_infinite]"
|
||||
data={faCircle}
|
||||
scale={0.7}
|
||||
label="Error during exchange of the refresh token"
|
||||
/>
|
||||
<span class="flex h-4 w-4">
|
||||
<Icon
|
||||
class="text-red-600 animate-ping absolute inline-flex "
|
||||
data={faCircle}
|
||||
scale={0.7}
|
||||
label="Error during exchange of the refresh token"
|
||||
/>
|
||||
<Icon
|
||||
class="text-red-600 relative inline-flex"
|
||||
data={faCircle}
|
||||
scale={0.7}
|
||||
label="Error during exchange of the refresh token"
|
||||
/>
|
||||
</span>
|
||||
<div slot="text">
|
||||
Latest exchange of the refresh token did not succeed. Error: {refresh_error}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user