feat(shell,api,keys): firefly v1 shell over the api with cookie auth, period, palette and keymap
This commit is contained in:
1 parent
ae4de7911b
commit
c74dac3e00
37 files changed
+58163
-79
No files matched your search
@@ -0,0 +1,130 @@
|
||||
import {
|
||||
addDays,
|
||||
isDynamic,
|
||||
periodOf,
|
||||
type Range,
|
||||
shiftPeriod,
|
||||
today,
|
||||
type ViewRange,
|
||||
} from "#lib/dates.js";
|
||||
import { formatDate, formatRange } from "#lib/format.js";
|
||||
|
||||
const STORAGE_KEY = "ffui.period";
|
||||
const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
||||
|
||||
export interface Preset {
|
||||
label: string;
|
||||
range: Range;
|
||||
}
|
||||
|
||||
function stored(): Range | null {
|
||||
try {
|
||||
const value = JSON.parse(localStorage.getItem(STORAGE_KEY) ?? "null");
|
||||
return ISO_DATE.test(value?.start) && ISO_DATE.test(value?.end)
|
||||
? value
|
||||
: null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function rangeFromUrl(url: {
|
||||
searchParams: { get: (name: string) => string | null };
|
||||
}): Range | null {
|
||||
const start = url.searchParams.get("start") ?? "";
|
||||
const end = url.searchParams.get("end") ?? "";
|
||||
return ISO_DATE.test(start) && ISO_DATE.test(end) && start <= end
|
||||
? { end, start }
|
||||
: null;
|
||||
}
|
||||
|
||||
export function periodLabel(range: Range, view: ViewRange): string {
|
||||
const aligned = periodOf(range.start, isDynamic(view) ? "1M" : view);
|
||||
if (aligned.start === range.start && aligned.end === range.end) {
|
||||
if (view === "1M" || isDynamic(view)) {
|
||||
return formatDate(range.start, "month");
|
||||
}
|
||||
if (view === "1Y") {
|
||||
return formatDate(range.start, "year");
|
||||
}
|
||||
}
|
||||
return formatRange(range.start, range.end);
|
||||
}
|
||||
|
||||
class Period {
|
||||
view = $state<ViewRange>("1M");
|
||||
start = $state(today());
|
||||
end = $state(today());
|
||||
first = $state<string | null>(null);
|
||||
ready = $state(false);
|
||||
|
||||
range = $derived<Range>({ end: this.end, start: this.start });
|
||||
label = $derived(periodLabel(this.range, this.view));
|
||||
isCurrent = $derived(this.start <= today() && today() <= this.end);
|
||||
|
||||
init(view: ViewRange, url: Parameters<typeof rangeFromUrl>[0]) {
|
||||
this.view = view;
|
||||
const range = rangeFromUrl(url) ?? stored() ?? periodOf(today(), view);
|
||||
this.start = range.start;
|
||||
this.end = range.end;
|
||||
this.ready = true;
|
||||
}
|
||||
|
||||
set(range: Range) {
|
||||
if (range.start === this.start && range.end === this.end) {
|
||||
return;
|
||||
}
|
||||
this.start = range.start;
|
||||
this.end = range.end;
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(range));
|
||||
}
|
||||
|
||||
shift(dir: 1 | -1) {
|
||||
this.set(shiftPeriod(this.range, this.view, dir));
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.set(periodOf(today(), this.view));
|
||||
}
|
||||
|
||||
presets(): Preset[] {
|
||||
const now = today();
|
||||
const { view } = this;
|
||||
const presets: Preset[] = [];
|
||||
if (!isDynamic(view)) {
|
||||
const prev = shiftPeriod(this.range, view, -1);
|
||||
const next = shiftPeriod(this.range, view, 1);
|
||||
presets.push({ label: periodLabel(prev, view), range: prev });
|
||||
presets.push({ label: periodLabel(next, view), range: next });
|
||||
}
|
||||
const current = periodOf(now, view);
|
||||
presets.push({
|
||||
label: `Today (${periodLabel(current, view)})`,
|
||||
range: current,
|
||||
});
|
||||
presets.push({
|
||||
label: "Last seven days",
|
||||
range: { end: now, start: addDays(now, -7) },
|
||||
});
|
||||
presets.push({
|
||||
label: "Last thirty days",
|
||||
range: { end: now, start: addDays(now, -30) },
|
||||
});
|
||||
presets.push({ label: "Month to date", range: periodOf(now, "MTD") });
|
||||
presets.push({ label: "Year to date", range: periodOf(now, "YTD") });
|
||||
const year = Number(now.slice(0, 4)) - 1;
|
||||
presets.push({
|
||||
label: `Previous year (${year})`,
|
||||
range: { end: `${year}-12-31`, start: `${year}-01-01` },
|
||||
});
|
||||
if (this.first) {
|
||||
presets.push({
|
||||
label: "Everything",
|
||||
range: { end: now, start: this.first },
|
||||
});
|
||||
}
|
||||
return presets;
|
||||
}
|
||||
}
|
||||
|
||||
export const period = new Period();
|
||||
Reference in new issue
Block a user