Skip to content

Commit 8233018

Browse files
committed
add quota adjustment editing and direct value editing
updates the org quota editor to allow both adjustment values and direct value editing for quotas other than additional/gifted execution minutes
1 parent 3ed14d4 commit 8233018

File tree

4 files changed

+101
-36
lines changed

4 files changed

+101
-36
lines changed

frontend/src/components/ui/data-grid/data-grid-cell.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { DataGridFocusController } from "@/components/ui/data-grid/controllers/f
2020
import type { UrlInput } from "@/components/ui/url-input";
2121
import { tw } from "@/utils/tailwind";
2222

23-
const cellInputStyle = [
23+
export const cellInputStyle = [
2424
tw`size-full [--sl-input-background-color-hover:transparent] [--sl-input-background-color:transparent] [--sl-input-border-radius-medium:0] [--sl-input-spacing-medium:var(--sl-spacing-small)] focus:z-10`,
2525
// TODO We need to upgrade to Tailwind v4 for inset rings to actually work
2626
// tw`focus-within:part-[base]:inset-ring-2`,

frontend/src/components/ui/data-grid/data-grid-row.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ export type RowEditEventDetail<T extends GridItem = GridItem> =
3030

3131
const cell = directive(CellDirective);
3232

33-
const cellStyle = tw`focus-visible:-outline-offset-2`;
34-
const editableCellStyle = tw`p-0 focus-visible:bg-slate-50 `;
33+
const cellStyle = tw`min-w-0 focus-visible:-outline-offset-2`;
34+
const editableCellStyle = tw`min-w-0 p-0 focus-visible:bg-slate-50`;
3535

3636
/**
3737
* @fires btrix-remove CustomEvent
@@ -223,7 +223,10 @@ export class DataGridRow<
223223

224224
if (!item) return;
225225

226-
const editable = this.editCells && col.editable;
226+
const editable =
227+
this.editCells && typeof col.editable === "function"
228+
? col.editable(item)
229+
: col.editable;
227230
const tooltipContent = editable
228231
? this.#invalidInputsMap.get(col.field)
229232
: col.renderCellTooltip

frontend/src/components/ui/data-grid/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export type GridColumn<
4040
field: Key;
4141
label: string | TemplateResult;
4242
description?: string;
43-
editable?: boolean;
43+
editable?: boolean | ((item: Item | undefined) => boolean | undefined);
4444
required?: boolean;
4545
inputPlaceholder?: string;
4646
width?: string;

frontend/src/features/admin/org-quota-editor.ts

Lines changed: 93 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { localized, msg, str } from "@lit/localize";
22
import { type SlDialog } from "@shoelace-style/shoelace";
3+
import clsx from "clsx";
34
import { html, type PropertyValues } from "lit";
45
import { customElement, property, state } from "lit/decorators.js";
56
import { createRef, ref, type Ref } from "lit/directives/ref.js";
@@ -10,6 +11,7 @@ import { type Entries } from "type-fest";
1011
import z from "zod";
1112

1213
import { BtrixElement } from "@/classes/BtrixElement";
14+
import { cellInputStyle } from "@/components/ui/data-grid/data-grid-cell";
1315
import { type RowEditEventDetail } from "@/components/ui/data-grid/data-grid-row";
1416
import {
1517
GridColumnType,
@@ -31,7 +33,14 @@ const PlansResponseSchema = z.object({
3133

3234
type PlansResponse = z.infer<typeof PlansResponseSchema>;
3335

34-
const LABELS = {
36+
const LABELS: {
37+
[key in keyof OrgQuotas]: {
38+
label: string;
39+
type: "number" | "bytes";
40+
scale?: number;
41+
adjustmentOnly?: boolean;
42+
};
43+
} = {
3544
maxConcurrentCrawls: {
3645
label: msg("Max Concurrent Crawls"),
3746
type: "number",
@@ -52,17 +61,13 @@ const LABELS = {
5261
extraExecMinutes: {
5362
label: msg("Extra Execution Minutes"),
5463
type: "number",
64+
adjustmentOnly: true,
5565
},
5666
giftedExecMinutes: {
5767
label: msg("Gifted Execution Minutes"),
5868
type: "number",
69+
adjustmentOnly: true,
5970
},
60-
} as const satisfies {
61-
[key in keyof OrgQuotas]: {
62-
label: string;
63-
type: "number" | "bytes";
64-
scale?: number;
65-
};
6671
};
6772

6873
@customElement("btrix-org-quota-editor")
@@ -111,7 +116,7 @@ export class OrgQuotaEditor extends BtrixElement {
111116
const items = entries.map(([key, value]) => {
112117
const labelConfig = LABELS[key];
113118
let currentAdjustment = this.orgQuotaAdjustments[key] || 0;
114-
if (labelConfig.type === "bytes") {
119+
if (labelConfig.scale != undefined) {
115120
currentAdjustment = Math.floor(
116121
currentAdjustment / labelConfig.scale,
117122
);
@@ -135,47 +140,95 @@ export class OrgQuotaEditor extends BtrixElement {
135140
{
136141
label: msg("Value"),
137142
field: "current",
138-
editable: false,
143+
editable: (item) => item && !LABELS[item.key].adjustmentOnly,
144+
inputType: GridColumnType.Number,
139145
width: "1fr",
140-
renderCell: ({ item }) => {
146+
renderEditCell: ({ item }) => {
147+
const key = item.key;
148+
let value = item.current;
149+
const labelConfig = LABELS[key];
150+
151+
if (labelConfig.scale != undefined) {
152+
value = Math.floor(value / labelConfig.scale);
153+
}
154+
return html`<sl-input
155+
class=${clsx(cellInputStyle)}
156+
type="number"
157+
value="${value}"
158+
min="0"
159+
step="1"
160+
>
161+
${labelConfig.type === "bytes"
162+
? html`<span class="whitespace-nowrap" slot="suffix"
163+
>GB</span
164+
>`
165+
: ""}
166+
</sl-input>`;
167+
},
168+
},
169+
{
170+
label: msg("Adjustment"),
171+
field: "adjustment",
172+
editable: true,
173+
width: "2fr",
174+
inputType: GridColumnType.Number,
175+
renderEditCell: ({ item }) => {
141176
const key = item.key;
142-
const value = item.current;
177+
let value = this.orgQuotaAdjustments[key] ?? 0;
143178
const labelConfig = LABELS[key];
144179
const format = (v: number, isInitialValue = true) =>
145180
this.format(v, labelConfig.type, isInitialValue);
146181
147-
return this.orgQuotaAdjustments[key]
182+
const displayValue = this.orgQuotaAdjustments[key]
148183
? Math.sign(this.orgQuotaAdjustments[key]) === 1
149184
? html`<span class="tabular-nums">
150-
<b>${format(value + this.orgQuotaAdjustments[key])}</b>
185+
<b
186+
>${format(
187+
(this.org?.quotas[key] || 0) +
188+
this.orgQuotaAdjustments[key],
189+
)}</b
190+
>
151191
<span class="inline-block">
152-
(${format(value, false)}
192+
(${format(this.org?.quotas[key] || 0, false)}
153193
<span class="whitespace-nowrap text-green-600">
154194
+&nbsp;${format(this.orgQuotaAdjustments[key])}</span
155195
>)</span
156196
></span
157197
>`
158198
: html`<span class="tabular-nums">
159-
<b>${format(value + this.orgQuotaAdjustments[key])}</b>
199+
<b
200+
>${format(
201+
(this.org?.quotas[key] || 0) +
202+
this.orgQuotaAdjustments[key],
203+
)}</b
204+
>
160205
<span class="inline-block">
161-
(${format(value, false)}
206+
(${format(this.org?.quotas[key] || 0, false)}
162207
<span class="whitespace-nowrap text-red-600">
163208
-&nbsp;${format(-this.orgQuotaAdjustments[key])}</span
164209
>)</span
165210
></span
166211
>`
167-
: format(value);
212+
: null;
213+
if (labelConfig.scale != undefined) {
214+
value = Math.floor(value / labelConfig.scale);
215+
}
216+
return html`<sl-input
217+
class=${clsx(cellInputStyle)}
218+
type="number"
219+
value="${value}"
220+
min=${-1 * item.current}
221+
step="1"
222+
>
223+
${labelConfig.type === "bytes"
224+
? html`<span class="whitespace-nowrap" slot="suffix"
225+
>GB</span
226+
>`
227+
: ""}
228+
</sl-input>
229+
${displayValue}`;
168230
},
169231
},
170-
{
171-
label: msg("Adjustment"),
172-
field: "adjustment",
173-
editable: true,
174-
width: "1fr",
175-
inputType: GridColumnType.Number,
176-
min: (item) => -1 * (item?.current ?? 0),
177-
step: 1,
178-
},
179232
];
180233
181234
return html`
@@ -267,13 +320,22 @@ export class OrgQuotaEditor extends BtrixElement {
267320
const key = event.detail.rowKey as keyof OrgQuotas;
268321
let value = Number(event.detail.value);
269322
const labelConfig = LABELS[key];
270-
if (labelConfig.type === "bytes") {
323+
if (labelConfig.scale != undefined) {
271324
value = Math.floor(value * labelConfig.scale);
272325
}
273-
this.orgQuotaAdjustments = {
274-
...this.orgQuotaAdjustments,
275-
[key]: value,
276-
};
326+
if (event.detail.field === "adjustment") {
327+
console.log("adjustment", value);
328+
this.orgQuotaAdjustments = {
329+
...this.orgQuotaAdjustments,
330+
[key]: value,
331+
};
332+
} else if (event.detail.field === "current") {
333+
console.log("current", value);
334+
this.orgQuotaAdjustments = {
335+
...this.orgQuotaAdjustments,
336+
[key]: value - (this.org?.quotas[key] || 0),
337+
};
338+
}
277339
}}
278340
></btrix-data-grid>
279341
`;

0 commit comments

Comments
 (0)