chore: reconcile performance layer after stack rebase

This commit is contained in:
ajnart committed 2026-08-13 20:01:46 +02:00
1 parent 1088f058e3
commit c92ca2af5f
235 files changed
+18492 -15756

No files matched your search

-2
View File
@@ -16,7 +16,6 @@ import { bazarrRouter } from "./router/widgets/bazarr";
import { serverSettingsRouter } from "./router/serverSettings";
import { beszelRouter } from "./router/widgets/beszel";
import { calendarRouter } from "./router/widgets/calendar";
import { customWidgetRouter } from "./router/custom-widget/custom-widget-router";
import { dnsHoleRouter } from "./router/widgets/dns-hole";
import { downloadsRouter } from "./router/widgets/downloads";
import { healthMonitoringRouter } from "./router/widgets/health-monitoring";
@@ -40,7 +39,6 @@ export const mcpRouter = createTRPCRouter({
serverSettings: serverSettingsRouter,
beszel: beszelRouter,
calendar: calendarRouter,
customWidget: customWidgetRouter,
dnsHole: dnsHoleRouter,
downloads: downloadsRouter,
healthMonitoring: healthMonitoringRouter,
@@ -1853,47 +1853,6 @@ describe("saveLayouts should save layout changes", () => {
expect(basePosition).toMatchObject({ xOffset: 0, yOffset: 1, width: 4, height: 1, sectionId });
expect(customPosition).toMatchObject({ xOffset: 0, yOffset: 1, width: 4, height: 1, sectionId });
});
test("should project a new custom layout from the resized Base layout", async () => {
const db = createDb();
const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession });
const { boardId, layoutId, sectionId, itemId } = await createFullBoardAsync(db, "default");
const mobileLayoutId = await addMobileLayoutAsync(db, boardId);
const secondItemId = createId();
await db.update(itemLayouts).set({ width: 4, xOffset: 0 }).where(eq(itemLayouts.itemId, itemId));
await db.insert(items).values({
id: secondItemId,
kind: "clock",
boardId,
options: SuperJSON.stringify({ is24HourFormat: true }),
});
await db.insert(itemLayouts).values({
itemId: secondItemId,
layoutId,
sectionId,
width: 4,
height: 1,
xOffset: 6,
yOffset: 0,
});
const resizedBase = { ...createExistingLayout(layoutId), columnCount: 6 };
const savedLayouts = await caller.saveLayouts({
id: boardId,
layouts: [createMobileLayout(mobileLayoutId), createNewLayout(8), resizedBase],
});
const customLayoutId = expectToBeDefined(savedLayouts.find((layout) => layout.role === "custom")).id;
const basePosition = await db.query.itemLayouts.findFirst({
where: and(eq(itemLayouts.itemId, secondItemId), eq(itemLayouts.layoutId, layoutId)),
});
const customPosition = await db.query.itemLayouts.findFirst({
where: and(eq(itemLayouts.itemId, secondItemId), eq(itemLayouts.layoutId, customLayoutId)),
});
expect(basePosition).toMatchObject({ xOffset: 0, yOffset: 1, width: 4, height: 1, sectionId });
expect(customPosition).toMatchObject({ xOffset: 0, yOffset: 1, width: 4, height: 1, sectionId });
});
test("should remove layout when not present in input", async () => {
// Arrange
const db = createDb();
@@ -1,376 +0,0 @@
// @vitest-environment node
import { stringify } from "superjson";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { Session } from "@homarr/auth";
import { createId } from "@homarr/common";
import type { Database } from "@homarr/db";
import { eq } from "@homarr/db";
import { boards, boardUserPermissions, customWidgetDefinitions, items, users } from "@homarr/db/schema";
import { createDb } from "@homarr/db/test";
import type { GroupPermissionKey } from "@homarr/definitions";
import { customWidgetRouter } from "../custom-widget/custom-widget-router";
import { customApiRouter } from "../widgets/custom-api";
const createSession = (userId: string, permissions: GroupPermissionKey[] = []): Session => ({
user: { id: userId, permissions, colorScheme: "light" },
expires: new Date().toISOString(),
});
const createCustomWidgetCaller = (db: Database, session: Session | null) =>
customWidgetRouter.createCaller({ db, deviceType: undefined, session });
const createCustomApiCaller = (db: Database, session: Session | null) =>
customApiRouter.createCaller({ db, deviceType: undefined, session });
async function createFixtureAsync(db: Database) {
const ownerId = createId();
const viewerId = createId();
const modifierId = createId();
const unrelatedId = createId();
const adminId = createId();
const boardId = createId();
const itemId = createId();
const definitionId = createId();
await db.insert(users).values(
[ownerId, viewerId, modifierId, unrelatedId, adminId].map((id) => ({
id,
name: id,
})),
);
await db.insert(boards).values({ id: boardId, name: `board-${boardId}`, creatorId: ownerId, isPublic: false });
await db.insert(boardUserPermissions).values([
{ boardId, userId: viewerId, permission: "view" },
{ boardId, userId: modifierId, permission: "modify" },
]);
await db.insert(customWidgetDefinitions).values({
id: definitionId,
name: "Restart service",
description: "Restarts a service",
url: "https://api.example.com/restart",
method: "POST",
displayType: "actionButton",
displayConfig: stringify({
type: "actionButton",
buttonLabel: "Restart",
confirmText: "Continue?",
}),
creatorId: adminId,
});
await db.insert(items).values({
id: itemId,
boardId,
kind: "customApi",
options: stringify({ definitionId, refreshInterval: 30 }),
});
return { ownerId, viewerId, modifierId, unrelatedId, adminId, boardId, itemId, definitionId };
}
beforeEach(() => {
vi.restoreAllMocks();
vi.useRealTimers();
});
afterEach(() => {
vi.unstubAllGlobals();
vi.useRealTimers();
});
describe("custom widget definition authorization", () => {
it("restricts the full definition list to administrators", async () => {
const db = createDb();
const fixture = await createFixtureAsync(db);
await expect(createCustomWidgetCaller(db, null).all()).rejects.toMatchObject({ code: "UNAUTHORIZED" });
for (const userId of [fixture.ownerId, fixture.viewerId, fixture.modifierId, fixture.unrelatedId]) {
await expect(createCustomWidgetCaller(db, createSession(userId)).all()).rejects.toMatchObject({
code: "FORBIDDEN",
});
}
await expect(createCustomWidgetCaller(db, createSession(fixture.adminId, ["admin"])).all()).resolves.toEqual([
expect.objectContaining({ id: fixture.definitionId, url: "https://api.example.com/restart" }),
]);
});
it("returns only safe definition summaries to board modifiers", async () => {
const db = createDb();
const fixture = await createFixtureAsync(db);
const result = await createCustomWidgetCaller(db, createSession(fixture.modifierId)).available({
boardId: fixture.boardId,
});
expect(result).toEqual([
{
id: fixture.definitionId,
name: "Restart service",
description: "Restarts a service",
iconUrl: null,
displayType: "actionButton",
enabled: true,
},
]);
expect(JSON.stringify(result)).not.toContain("api.example.com");
for (const userId of [fixture.viewerId, fixture.unrelatedId]) {
await expect(
createCustomWidgetCaller(db, createSession(userId)).available({ boardId: fixture.boardId }),
).rejects.toMatchObject({ code: "NOT_FOUND" });
}
});
});
describe("custom widget action authorization", () => {
it("requires an administrator even for users who can view or modify the board", async () => {
const db = createDb();
const fixture = await createFixtureAsync(db);
const input = {
boardId: fixture.boardId,
itemId: fixture.itemId,
definitionId: fixture.definitionId,
};
await expect(createCustomWidgetCaller(db, null).execute(input)).rejects.toMatchObject({ code: "UNAUTHORIZED" });
for (const userId of [fixture.ownerId, fixture.viewerId, fixture.modifierId, fixture.unrelatedId]) {
await expect(createCustomWidgetCaller(db, createSession(userId)).execute(input)).rejects.toMatchObject({
code: "FORBIDDEN",
});
}
});
it("executes for an administrator only when board, item, and definition are bound", async () => {
const db = createDb();
const fixture = await createFixtureAsync(db);
const fetchMock = vi.fn().mockResolvedValue(new Response(null, { status: 204 }));
vi.stubGlobal("fetch", fetchMock);
const caller = createCustomWidgetCaller(db, createSession(fixture.adminId, ["admin"]));
await expect(
caller.execute({
boardId: fixture.boardId,
itemId: fixture.itemId,
definitionId: fixture.definitionId,
}),
).resolves.toEqual({ success: true, responseInfo: { status: 204 } });
expect(fetchMock).toHaveBeenCalledWith(
"https://api.example.com/restart",
expect.objectContaining({ method: "POST", redirect: "error", signal: expect.any(AbortSignal) }),
);
});
it.each(["board", "item", "definition"] as const)("rejects a mismatched %s binding", async (mismatch) => {
const db = createDb();
const fixture = await createFixtureAsync(db);
const fetchMock = vi.fn();
vi.stubGlobal("fetch", fetchMock);
const input = {
boardId: mismatch === "board" ? createId() : fixture.boardId,
itemId: mismatch === "item" ? createId() : fixture.itemId,
definitionId: mismatch === "definition" ? createId() : fixture.definitionId,
};
await expect(
createCustomWidgetCaller(db, createSession(fixture.adminId, ["admin"])).execute(input),
).rejects.toMatchObject({ code: "NOT_FOUND" });
expect(fetchMock).not.toHaveBeenCalled();
});
it("rejects disabled definitions before sending a request", async () => {
const db = createDb();
const fixture = await createFixtureAsync(db);
await db
.update(customWidgetDefinitions)
.set({ enabled: false })
.where(eq(customWidgetDefinitions.id, fixture.definitionId));
const fetchMock = vi.fn();
vi.stubGlobal("fetch", fetchMock);
await expect(
createCustomWidgetCaller(db, createSession(fixture.adminId, ["admin"])).execute({
boardId: fixture.boardId,
itemId: fixture.itemId,
definitionId: fixture.definitionId,
}),
).rejects.toMatchObject({ code: "FORBIDDEN" });
expect(fetchMock).not.toHaveBeenCalled();
});
});
describe("custom API outbound request hardening", () => {
it("rejects credential-bearing action URLs without exposing the credential", async () => {
const db = createDb();
const fixture = await createFixtureAsync(db);
await db
.update(customWidgetDefinitions)
.set({ url: "https://operator:super-secret@private.example.com/restart" })
.where(eq(customWidgetDefinitions.id, fixture.definitionId));
const fetchMock = vi.fn();
vi.stubGlobal("fetch", fetchMock);
const result = await createCustomWidgetCaller(db, createSession(fixture.adminId, ["admin"])).execute({
boardId: fixture.boardId,
itemId: fixture.itemId,
definitionId: fixture.definitionId,
});
expect(result).toEqual({ success: false, errorCode: "REQUEST_FAILED", responseInfo: null });
expect(JSON.stringify(result)).not.toMatch(/super-secret|private\.example\.com/);
expect(fetchMock).not.toHaveBeenCalled();
});
it("rejects redirects and redacts fetch errors", async () => {
const db = createDb();
const fixture = await createFixtureAsync(db);
const fetchMock = vi
.fn()
.mockRejectedValue(
new TypeError("Redirect to http://token:secret@internal.example.local/admin?apiKey=top-secret was rejected"),
);
vi.stubGlobal("fetch", fetchMock);
const result = await createCustomWidgetCaller(db, createSession(fixture.adminId, ["admin"])).execute({
boardId: fixture.boardId,
itemId: fixture.itemId,
definitionId: fixture.definitionId,
});
expect(fetchMock).toHaveBeenCalledWith(
"https://api.example.com/restart",
expect.objectContaining({ redirect: "error" }),
);
expect(result).toEqual({ success: false, errorCode: "REQUEST_FAILED", responseInfo: null });
expect(JSON.stringify(result)).not.toMatch(/top-secret|internal\.example\.local|apiKey/);
});
it("aborts timed-out action requests and returns a stable failure", async () => {
vi.useFakeTimers();
const db = createDb();
const fixture = await createFixtureAsync(db);
const started = Promise.withResolvers<void>();
const fetchMock = vi.fn((_url: string, init: RequestInit) => {
started.resolve();
return new Promise<Response>((_resolve, reject) => {
init.signal?.addEventListener("abort", () => {
reject(new Error("Timed out calling http://internal.example.local?secret=timeout-secret"));
});
});
});
vi.stubGlobal("fetch", fetchMock);
const request = createCustomWidgetCaller(db, createSession(fixture.adminId, ["admin"])).execute({
boardId: fixture.boardId,
itemId: fixture.itemId,
definitionId: fixture.definitionId,
});
await started.promise;
await vi.advanceTimersByTimeAsync(10_000);
const result = await request;
expect(result).toEqual({ success: false, errorCode: "REQUEST_FAILED", responseInfo: null });
expect(JSON.stringify(result)).not.toMatch(/timeout-secret|internal\.example\.local/);
});
it("bounds action responses before reporting success", async () => {
const db = createDb();
const fixture = await createFixtureAsync(db);
vi.stubGlobal("fetch", vi.fn().mockResolvedValue(new Response("x".repeat(2 * 1024 * 1024 + 1))));
await expect(
createCustomWidgetCaller(db, createSession(fixture.adminId, ["admin"])).execute({
boardId: fixture.boardId,
itemId: fixture.itemId,
definitionId: fixture.definitionId,
}),
).resolves.toEqual({ success: false, errorCode: "REQUEST_FAILED", responseInfo: null });
});
it("binds data requests to a viewable item and never exposes backend error text", async () => {
const db = createDb();
const fixture = await createFixtureAsync(db);
await db
.update(customWidgetDefinitions)
.set({
displayType: "singleValue",
method: "GET",
displayConfig: stringify({ type: "singleValue", jsonPath: "$.value" }),
})
.where(eq(customWidgetDefinitions.id, fixture.definitionId));
vi.stubGlobal(
"fetch",
vi.fn().mockRejectedValue(new Error("Backend http://private.example.local/path?token=super-secret\nstack trace")),
);
const input = {
boardId: fixture.boardId,
itemId: fixture.itemId,
definitionId: fixture.definitionId,
};
const error = await createCustomApiCaller(db, createSession(fixture.viewerId))
.getData(input)
.catch((caught: unknown) => caught);
expect(error).toMatchObject({ code: "INTERNAL_SERVER_ERROR", message: "Custom API request failed" });
expect(JSON.stringify(error)).not.toMatch(/super-secret|private\.example\.local|stack trace/);
await expect(createCustomApiCaller(db, createSession(fixture.unrelatedId)).getData(input)).rejects.toMatchObject({
code: "NOT_FOUND",
});
await expect(
createCustomApiCaller(db, createSession(fixture.viewerId)).getData({ ...input, definitionId: createId() }),
).rejects.toMatchObject({ code: "NOT_FOUND" });
});
it("bounds and disposes non-success data responses", async () => {
const db = createDb();
const fixture = await createFixtureAsync(db);
await db
.update(customWidgetDefinitions)
.set({
displayType: "singleValue",
method: "GET",
displayConfig: stringify({ type: "singleValue", jsonPath: "$.value" }),
})
.where(eq(customWidgetDefinitions.id, fixture.definitionId));
vi.stubGlobal("fetch", vi.fn().mockResolvedValue(new Response("x".repeat(2 * 1024 * 1024 + 1), { status: 502 })));
const error = await createCustomApiCaller(db, createSession(fixture.viewerId))
.getData({
boardId: fixture.boardId,
itemId: fixture.itemId,
definitionId: fixture.definitionId,
})
.catch((caught: unknown) => caught);
expect(error).toMatchObject({ code: "INTERNAL_SERVER_ERROR", message: "Custom API request failed" });
expect(JSON.stringify(error)).not.toContain("x".repeat(100));
});
it("redacts unsafe preview failures and rejects redirects", async () => {
const db = createDb();
const fixture = await createFixtureAsync(db);
const fetchMock = vi.fn().mockRejectedValue(new Error("redirected to http://private.local?secret=value"));
vi.stubGlobal("fetch", fetchMock);
const caller = createCustomWidgetCaller(db, createSession(fixture.adminId, ["admin"]));
const result = await caller.preview({
url: "https://api.example.com/data",
method: "GET",
authType: "none",
displayType: "singleValue",
displayConfig: { type: "singleValue", jsonPath: "$.value", label: "Value", unit: "" },
secrets: [],
});
expect(fetchMock).toHaveBeenCalledWith(
"https://api.example.com/data",
expect.objectContaining({ redirect: "error" }),
);
expect(result).toEqual({
success: false,
error: "Custom API preview failed",
responseInfo: null,
rawResponse: null,
});
expect(JSON.stringify(result)).not.toMatch(/private\.local|secret=value/);
});
});
+54 -9
View File
@@ -1,17 +1,47 @@
import { z } from "zod/v4";
import type { IntegrationKindByCategory } from "@homarr/definitions";
import { getIntegrationKindsByCategory } from "@homarr/definitions";
import type { DownloadClientJobsAndStatus } from "@homarr/integrations";
import { createIntegrationAsync, downloadClientItemSchema } from "@homarr/integrations";
import { downloadClientRequestHandler } from "@homarr/request-handler/downloads";
import type { IntegrationAction } from "../../middlewares/integration";
import { createManyIntegrationMiddleware } from "../../middlewares/integration";
import { settleIntegrationQueries } from "../../settle-integrations";
import { PUBLIC_INTEGRATION_ERROR, settleIntegrationQueries } from "../../settle-integrations";
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../../trpc";
const createDownloadClientIntegrationMiddleware = (action: IntegrationAction) =>
createManyIntegrationMiddleware(action, ...getIntegrationKindsByCategory("downloadClient"));
interface DownloadClientQueryResultBase {
integrationId: string;
integrationName: string;
}
type DownloadClientQueryResult = DownloadClientQueryResultBase &
(
| {
integration: {
id: string;
name: string;
kind: IntegrationKindByCategory<"downloadClient">;
updatedAt: Date;
};
data: DownloadClientJobsAndStatus;
error?: never;
}
| {
integration: {
id: string;
name: string;
kind: IntegrationKindByCategory<"downloadClient">;
};
data: null;
error: string;
}
);
export const downloadsRouter = createTRPCRouter({
getJobsAndStatuses: publicProcedure
.meta({
@@ -24,14 +54,29 @@ export const downloadsRouter = createTRPCRouter({
.concat(createDownloadClientIntegrationMiddleware("query"))
.input(z.object({ limitPerIntegration: z.number().default(50) }))
.query(async ({ ctx, input }) => {
return await settleIntegrationQueries(ctx.integrations, async (integration) => {
const innerHandler = downloadClientRequestHandler.handler(integration, { limit: input.limitPerIntegration });
const { data, timestamp } = await innerHandler.getDataAsync();
return {
integration: { id: integration.id, name: integration.name, kind: integration.kind, updatedAt: timestamp },
data,
};
});
return await settleIntegrationQueries<(typeof ctx.integrations)[number], DownloadClientQueryResult>(
ctx.integrations,
async (integration) => {
const innerHandler = downloadClientRequestHandler.handler(integration, { limit: input.limitPerIntegration });
const { data, timestamp } = await innerHandler.getDataAsync();
return {
integrationId: integration.id,
integrationName: integration.name,
integration: { id: integration.id, name: integration.name, kind: integration.kind, updatedAt: timestamp },
data,
};
},
{
fallback: (integration) => ({
integrationId: integration.id,
integrationName: integration.name,
integration: { id: integration.id, name: integration.name, kind: integration.kind },
data: null,
error: PUBLIC_INTEGRATION_ERROR,
}),
throwOnAllFailures: true,
},
);
}),
pause: protectedProcedure
.meta({
@@ -1,9 +1,10 @@
import { createIntegrationAsync } from "@homarr/integrations";
import type { SystemHealthMonitoring } from "@homarr/integrations";
import { SynologyIntegration } from "@homarr/integrations";
import { clusterInfoRequestHandler, systemInfoRequestHandler } from "@homarr/request-handler/health-monitoring";
import { createManyIntegrationMiddleware, createOneIntegrationMiddleware } from "../../middlewares/integration";
import { settleIntegrationQueries } from "../../settle-integrations";
import { PUBLIC_INTEGRATION_ERROR, settleIntegrationQueries } from "../../settle-integrations";
import { createTRPCRouter, publicProcedure } from "../../trpc";
const healthMonitoringIntegrationKinds = [
@@ -16,6 +17,14 @@ const healthMonitoringIntegrationKinds = [
"mock",
] as const;
interface SystemHealthQueryResult {
integrationId: string;
integrationName: string;
healthInfo: SystemHealthMonitoring | null;
updatedAt?: Date;
error?: string;
}
export const healthMonitoringRouter = createTRPCRouter({
getSystemHealthStatus: publicProcedure
.meta({
@@ -27,15 +36,27 @@ export const healthMonitoringRouter = createTRPCRouter({
})
.concat(createManyIntegrationMiddleware("query", ...healthMonitoringIntegrationKinds))
.query(async ({ ctx }) => {
return await settleIntegrationQueries(ctx.integrations, async (integration) => {
const { data, timestamp } = await systemInfoRequestHandler.handler(integration, {}).getDataAsync();
return {
integrationId: integration.id,
integrationName: integration.name,
healthInfo: data,
updatedAt: timestamp,
};
});
return await settleIntegrationQueries<(typeof ctx.integrations)[number], SystemHealthQueryResult>(
ctx.integrations,
async (integration) => {
const { data, timestamp } = await systemInfoRequestHandler.handler(integration, {}).getDataAsync();
return {
integrationId: integration.id,
integrationName: integration.name,
healthInfo: data,
updatedAt: timestamp,
};
},
{
fallback: (integration) => ({
integrationId: integration.id,
integrationName: integration.name,
healthInfo: null,
error: PUBLIC_INTEGRATION_ERROR,
}),
throwOnAllFailures: true,
},
);
}),
listStorageVolumes: publicProcedure
.meta({
@@ -2,32 +2,21 @@ import { getIntegrationKindsByCategory } from "@homarr/definitions";
import { mediaReleaseRequestHandler } from "@homarr/request-handler/media-release";
import { createManyIntegrationMiddleware } from "../../middlewares/integration";
import { settleIntegrationQueries } from "../../settle-integrations";
import { createTRPCRouter, publicProcedure } from "../../trpc";
import { getMediaReleaseResponse } from "./media-release-result";
export const mediaReleaseRouter = createTRPCRouter({
getMediaReleases: publicProcedure
.concat(createManyIntegrationMiddleware("query", ...getIntegrationKindsByCategory("mediaRelease")))
.query(async ({ ctx }) => {
const results = await settleIntegrationQueries(ctx.integrations, async (integration) => {
return await getMediaReleaseResponse(ctx.integrations, async (integration) => {
const innerHandler = mediaReleaseRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
return {
integration: {
id: integration.id,
name: integration.name,
kind: integration.kind,
updatedAt: timestamp,
},
releases: data,
updatedAt: timestamp,
};
});
return results.flatMap((result) =>
result.releases.map((release) => ({
...release,
integration: result.integration,
})),
);
}),
});
+1 -1
View File
@@ -32,7 +32,7 @@ const feedsInput = z.object({
export const rssFeedRouter = createTRPCRouter({
getFeeds: publicProcedure.input(feedsInput).query(async ({ ctx, input }) => {
if (env.NO_EXTERNAL_CONNECTION) return [];
if (env.NO_EXTERNAL_CONNECTION) return { entries: [], failedFeedCount: 0 };
const urls = (await canAccessAllFeedsAsync(ctx.db, ctx.session))
? input.urls
+27 -12
View File
@@ -1,24 +1,39 @@
import { uptimeKumaRequestHandler } from "@homarr/request-handler/uptime-kuma";
import { createManyIntegrationMiddleware } from "../../middlewares/integration";
import { settleIntegrationQueries } from "../../settle-integrations";
import { settleIntegrationQueries, toPublicIntegrationError } from "../../settle-integrations";
import { createTRPCRouter, publicProcedure } from "../../trpc";
export const uptimeKumaRouter = createTRPCRouter({
getDashboard: publicProcedure
.concat(createManyIntegrationMiddleware("query", "uptimeKuma"))
.query(async ({ ctx }) => {
return await settleIntegrationQueries(ctx.integrations, async (integration) => {
const innerHandler = uptimeKumaRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
return await settleIntegrationQueries(
ctx.integrations,
async (integration) => {
const innerHandler = uptimeKumaRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
return {
integrationId: integration.id,
integrationName: integration.name,
integrationUrl: integration.url,
dashboard: data,
updatedAt: timestamp,
};
});
return {
integrationId: integration.id,
integrationName: integration.name,
integrationUrl: integration.url,
dashboard: data as typeof data | null,
updatedAt: timestamp,
error: undefined as string | undefined,
};
},
{
fallback: (integration, error) => ({
integrationId: integration.id,
integrationName: integration.name,
integrationUrl: integration.url,
dashboard: null,
updatedAt: new Date(0),
error: toPublicIntegrationError(error),
}),
throwOnAllFailures: true,
},
);
}),
});
+1 -4
View File
@@ -5,10 +5,7 @@ interface ResponsiveLayout {
breakpoint: number;
}
export const getLayoutIdForViewportWidth = (
layouts: readonly ResponsiveLayout[],
viewportWidth: number,
): string => {
export const getLayoutIdForViewportWidth = (layouts: readonly ResponsiveLayout[], viewportWidth: number): string => {
if (layouts.length === 0) {
throw new Error("Expected the board to contain a layout");
}
@@ -1 +0,0 @@
ALTER TABLE `assistant_configuration` ADD `web_search_enabled` boolean DEFAULT false NOT NULL;
@@ -88,9 +88,7 @@
"indexes": {
"userId_idx": {
"name": "userId_idx",
"columns": [
"user_id"
],
"columns": ["user_id"],
"isUnique": false
}
},
@@ -99,12 +97,8 @@
"name": "account_user_id_user_id_fk",
"tableFrom": "account",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -112,10 +106,7 @@
"compositePrimaryKeys": {
"account_provider_provider_account_id_pk": {
"name": "account_provider_provider_account_id_pk",
"columns": [
"provider",
"provider_account_id"
]
"columns": ["provider", "provider_account_id"]
}
},
"uniqueConstraints": {},
@@ -152,12 +143,8 @@
"name": "apiKey_user_id_user_id_fk",
"tableFrom": "apiKey",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -165,9 +152,7 @@
"compositePrimaryKeys": {
"apiKey_id": {
"name": "apiKey_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -224,9 +209,7 @@
"compositePrimaryKeys": {
"app_id": {
"name": "app_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -263,12 +246,8 @@
"name": "boardGroupPermission_board_id_board_id_fk",
"tableFrom": "boardGroupPermission",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -276,12 +255,8 @@
"name": "boardGroupPermission_group_id_group_id_fk",
"tableFrom": "boardGroupPermission",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -289,11 +264,7 @@
"compositePrimaryKeys": {
"boardGroupPermission_board_id_group_id_permission_pk": {
"name": "boardGroupPermission_board_id_group_id_permission_pk",
"columns": [
"board_id",
"group_id",
"permission"
]
"columns": ["board_id", "group_id", "permission"]
}
},
"uniqueConstraints": {},
@@ -330,12 +301,8 @@
"name": "boardUserPermission_board_id_board_id_fk",
"tableFrom": "boardUserPermission",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -343,12 +310,8 @@
"name": "boardUserPermission_user_id_user_id_fk",
"tableFrom": "boardUserPermission",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -356,11 +319,7 @@
"compositePrimaryKeys": {
"boardUserPermission_board_id_user_id_permission_pk": {
"name": "boardUserPermission_board_id_user_id_permission_pk",
"columns": [
"board_id",
"user_id",
"permission"
]
"columns": ["board_id", "user_id", "permission"]
}
},
"uniqueConstraints": {},
@@ -518,12 +477,8 @@
"name": "board_creator_id_user_id_fk",
"tableFrom": "board",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -531,17 +486,13 @@
"compositePrimaryKeys": {
"board_id": {
"name": "board_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {
"board_name_unique": {
"name": "board_name_unique",
"columns": [
"name"
]
"columns": ["name"]
}
},
"checkConstraint": {}
@@ -577,9 +528,7 @@
"compositePrimaryKeys": {
"cron_job_configuration_name": {
"name": "cron_job_configuration_name",
"columns": [
"name"
]
"columns": ["name"]
}
},
"uniqueConstraints": {},
@@ -609,12 +558,8 @@
"name": "groupMember_group_id_group_id_fk",
"tableFrom": "groupMember",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -622,12 +567,8 @@
"name": "groupMember_user_id_user_id_fk",
"tableFrom": "groupMember",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -635,10 +576,7 @@
"compositePrimaryKeys": {
"groupMember_group_id_user_id_pk": {
"name": "groupMember_group_id_user_id_pk",
"columns": [
"group_id",
"user_id"
]
"columns": ["group_id", "user_id"]
}
},
"uniqueConstraints": {},
@@ -668,12 +606,8 @@
"name": "groupPermission_group_id_group_id_fk",
"tableFrom": "groupPermission",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -734,12 +668,8 @@
"name": "group_owner_id_user_id_fk",
"tableFrom": "group",
"tableTo": "user",
"columnsFrom": [
"owner_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["owner_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -747,12 +677,8 @@
"name": "group_home_board_id_board_id_fk",
"tableFrom": "group",
"tableTo": "board",
"columnsFrom": [
"home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -760,12 +686,8 @@
"name": "group_mobile_home_board_id_board_id_fk",
"tableFrom": "group",
"tableTo": "board",
"columnsFrom": [
"mobile_home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["mobile_home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -773,17 +695,13 @@
"compositePrimaryKeys": {
"group_id": {
"name": "group_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {
"group_name_unique": {
"name": "group_name_unique",
"columns": [
"name"
]
"columns": ["name"]
}
},
"checkConstraint": {}
@@ -811,9 +729,7 @@
"compositePrimaryKeys": {
"iconRepository_id": {
"name": "iconRepository_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -864,12 +780,8 @@
"name": "icon_icon_repository_id_iconRepository_id_fk",
"tableFrom": "icon",
"tableTo": "iconRepository",
"columnsFrom": [
"icon_repository_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["icon_repository_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -877,9 +789,7 @@
"compositePrimaryKeys": {
"icon_id": {
"name": "icon_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -916,12 +826,8 @@
"name": "integrationGroupPermissions_integration_id_integration_id_fk",
"tableFrom": "integrationGroupPermissions",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -929,12 +835,8 @@
"name": "integrationGroupPermissions_group_id_group_id_fk",
"tableFrom": "integrationGroupPermissions",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -942,11 +844,7 @@
"compositePrimaryKeys": {
"integration_group_permission__pk": {
"name": "integration_group_permission__pk",
"columns": [
"integration_id",
"group_id",
"permission"
]
"columns": ["integration_id", "group_id", "permission"]
}
},
"uniqueConstraints": {},
@@ -976,12 +874,8 @@
"name": "integration_item_item_id_item_id_fk",
"tableFrom": "integration_item",
"tableTo": "item",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["item_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -989,12 +883,8 @@
"name": "integration_item_integration_id_integration_id_fk",
"tableFrom": "integration_item",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1002,10 +892,7 @@
"compositePrimaryKeys": {
"integration_item_item_id_integration_id_pk": {
"name": "integration_item_item_id_integration_id_pk",
"columns": [
"item_id",
"integration_id"
]
"columns": ["item_id", "integration_id"]
}
},
"uniqueConstraints": {},
@@ -1046,16 +933,12 @@
"indexes": {
"integration_secret__kind_idx": {
"name": "integration_secret__kind_idx",
"columns": [
"kind"
],
"columns": ["kind"],
"isUnique": false
},
"integration_secret__updated_at_idx": {
"name": "integration_secret__updated_at_idx",
"columns": [
"updated_at"
],
"columns": ["updated_at"],
"isUnique": false
}
},
@@ -1064,12 +947,8 @@
"name": "integrationSecret_integration_id_integration_id_fk",
"tableFrom": "integrationSecret",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1077,10 +956,7 @@
"compositePrimaryKeys": {
"integrationSecret_integration_id_kind_pk": {
"name": "integrationSecret_integration_id_kind_pk",
"columns": [
"integration_id",
"kind"
]
"columns": ["integration_id", "kind"]
}
},
"uniqueConstraints": {},
@@ -1117,12 +993,8 @@
"name": "integrationUserPermission_integration_id_integration_id_fk",
"tableFrom": "integrationUserPermission",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1130,12 +1002,8 @@
"name": "integrationUserPermission_user_id_user_id_fk",
"tableFrom": "integrationUserPermission",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1143,11 +1011,7 @@
"compositePrimaryKeys": {
"integrationUserPermission_integration_id_user_id_permission_pk": {
"name": "integrationUserPermission_integration_id_user_id_permission_pk",
"columns": [
"integration_id",
"user_id",
"permission"
]
"columns": ["integration_id", "user_id", "permission"]
}
},
"uniqueConstraints": {},
@@ -1195,9 +1059,7 @@
"indexes": {
"integration__kind_idx": {
"name": "integration__kind_idx",
"columns": [
"kind"
],
"columns": ["kind"],
"isUnique": false
}
},
@@ -1206,12 +1068,8 @@
"name": "integration_app_id_app_id_fk",
"tableFrom": "integration",
"tableTo": "app",
"columnsFrom": [
"app_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["app_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -1219,9 +1077,7 @@
"compositePrimaryKeys": {
"integration_id": {
"name": "integration_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -1265,12 +1121,8 @@
"name": "invite_creator_id_user_id_fk",
"tableFrom": "invite",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1278,17 +1130,13 @@
"compositePrimaryKeys": {
"invite_id": {
"name": "invite_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {
"invite_token_unique": {
"name": "invite_token_unique",
"columns": [
"token"
]
"columns": ["token"]
}
},
"checkConstraint": {}
@@ -1352,12 +1200,8 @@
"name": "item_layout_item_id_item_id_fk",
"tableFrom": "item_layout",
"tableTo": "item",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["item_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1365,12 +1209,8 @@
"name": "item_layout_section_id_section_id_fk",
"tableFrom": "item_layout",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1378,12 +1218,8 @@
"name": "item_layout_layout_id_layout_id_fk",
"tableFrom": "item_layout",
"tableTo": "layout",
"columnsFrom": [
"layout_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["layout_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1391,11 +1227,7 @@
"compositePrimaryKeys": {
"item_layout_item_id_section_id_layout_id_pk": {
"name": "item_layout_item_id_section_id_layout_id_pk",
"columns": [
"item_id",
"section_id",
"layout_id"
]
"columns": ["item_id", "section_id", "layout_id"]
}
},
"uniqueConstraints": {},
@@ -1448,12 +1280,8 @@
"name": "item_board_id_board_id_fk",
"tableFrom": "item",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1461,9 +1289,7 @@
"compositePrimaryKeys": {
"item_id": {
"name": "item_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -1515,12 +1341,8 @@
"name": "layout_board_id_board_id_fk",
"tableFrom": "layout",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1528,9 +1350,7 @@
"compositePrimaryKeys": {
"layout_id": {
"name": "layout_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -1596,12 +1416,8 @@
"name": "media_creator_id_user_id_fk",
"tableFrom": "media",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -1609,9 +1425,7 @@
"compositePrimaryKeys": {
"media_id": {
"name": "media_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -1647,9 +1461,7 @@
"compositePrimaryKeys": {
"onboarding_id": {
"name": "onboarding_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -1722,12 +1534,8 @@
"name": "search_engine_integration_id_integration_id_fk",
"tableFrom": "search_engine",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1735,17 +1543,13 @@
"compositePrimaryKeys": {
"search_engine_id": {
"name": "search_engine_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {
"search_engine_short_unique": {
"name": "search_engine_short_unique",
"columns": [
"short"
]
"columns": ["short"]
}
},
"checkConstraint": {}
@@ -1782,12 +1586,8 @@
"name": "section_collapse_state_user_id_user_id_fk",
"tableFrom": "section_collapse_state",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1795,12 +1595,8 @@
"name": "section_collapse_state_section_id_section_id_fk",
"tableFrom": "section_collapse_state",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1808,10 +1604,7 @@
"compositePrimaryKeys": {
"section_collapse_state_user_id_section_id_pk": {
"name": "section_collapse_state_user_id_section_id_pk",
"columns": [
"user_id",
"section_id"
]
"columns": ["user_id", "section_id"]
}
},
"uniqueConstraints": {},
@@ -1876,12 +1669,8 @@
"name": "section_layout_section_id_section_id_fk",
"tableFrom": "section_layout",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1889,12 +1678,8 @@
"name": "section_layout_layout_id_layout_id_fk",
"tableFrom": "section_layout",
"tableTo": "layout",
"columnsFrom": [
"layout_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["layout_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1902,12 +1687,8 @@
"name": "section_layout_parent_section_id_section_id_fk",
"tableFrom": "section_layout",
"tableTo": "section",
"columnsFrom": [
"parent_section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["parent_section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1915,10 +1696,7 @@
"compositePrimaryKeys": {
"section_layout_section_id_layout_id_pk": {
"name": "section_layout_section_id_layout_id_pk",
"columns": [
"section_id",
"layout_id"
]
"columns": ["section_id", "layout_id"]
}
},
"uniqueConstraints": {},
@@ -1984,12 +1762,8 @@
"name": "section_board_id_board_id_fk",
"tableFrom": "section",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1997,9 +1771,7 @@
"compositePrimaryKeys": {
"section_id": {
"name": "section_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -2029,17 +1801,13 @@
"compositePrimaryKeys": {
"serverSetting_setting_key": {
"name": "serverSetting_setting_key",
"columns": [
"setting_key"
]
"columns": ["setting_key"]
}
},
"uniqueConstraints": {
"serverSetting_settingKey_unique": {
"name": "serverSetting_settingKey_unique",
"columns": [
"setting_key"
]
"columns": ["setting_key"]
}
},
"checkConstraint": {}
@@ -2072,9 +1840,7 @@
"indexes": {
"user_id_idx": {
"name": "user_id_idx",
"columns": [
"user_id"
],
"columns": ["user_id"],
"isUnique": false
}
},
@@ -2083,12 +1849,8 @@
"name": "session_user_id_user_id_fk",
"tableFrom": "session",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -2096,9 +1858,7 @@
"compositePrimaryKeys": {
"session_session_token": {
"name": "session_session_token",
"columns": [
"session_token"
]
"columns": ["session_token"]
}
},
"uniqueConstraints": {},
@@ -2225,12 +1985,8 @@
"name": "user_home_board_id_board_id_fk",
"tableFrom": "user",
"tableTo": "board",
"columnsFrom": [
"home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -2238,12 +1994,8 @@
"name": "user_mobile_home_board_id_board_id_fk",
"tableFrom": "user",
"tableTo": "board",
"columnsFrom": [
"mobile_home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["mobile_home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -2251,12 +2003,8 @@
"name": "user_default_search_engine_id_search_engine_id_fk",
"tableFrom": "user",
"tableTo": "search_engine",
"columnsFrom": [
"default_search_engine_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["default_search_engine_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -2264,9 +2012,7 @@
"compositePrimaryKeys": {
"user_id": {
"name": "user_id",
"columns": [
"id"
]
"columns": ["id"]
}
},
"uniqueConstraints": {},
@@ -2302,10 +2048,7 @@
"compositePrimaryKeys": {
"verificationToken_identifier_token_pk": {
"name": "verificationToken_identifier_token_pk",
"columns": [
"identifier",
"token"
]
"columns": ["identifier", "token"]
}
},
"uniqueConstraints": {},
@@ -2341,10 +2084,7 @@
"compositePrimaryKeys": {
"trusted_certificate_hostname_hostname_thumbprint_pk": {
"name": "trusted_certificate_hostname_hostname_thumbprint_pk",
"columns": [
"hostname",
"thumbprint"
]
"columns": ["hostname", "thumbprint"]
}
},
"uniqueConstraints": {},
@@ -2361,4 +2101,4 @@
"tables": {},
"indexes": {}
}
}
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -1 +0,0 @@
ALTER TABLE "assistant_configuration" ADD COLUMN "web_search_enabled" boolean DEFAULT false NOT NULL;
@@ -97,12 +97,8 @@
"name": "account_user_id_user_id_fk",
"tableFrom": "account",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -110,10 +106,7 @@
"compositePrimaryKeys": {
"account_provider_provider_account_id_pk": {
"name": "account_provider_provider_account_id_pk",
"columns": [
"provider",
"provider_account_id"
]
"columns": ["provider", "provider_account_id"]
}
},
"uniqueConstraints": {},
@@ -150,12 +143,8 @@
"name": "apiKey_user_id_user_id_fk",
"tableFrom": "apiKey",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -244,12 +233,8 @@
"name": "boardGroupPermission_board_id_board_id_fk",
"tableFrom": "boardGroupPermission",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -257,12 +242,8 @@
"name": "boardGroupPermission_group_id_group_id_fk",
"tableFrom": "boardGroupPermission",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -270,11 +251,7 @@
"compositePrimaryKeys": {
"boardGroupPermission_board_id_group_id_permission_pk": {
"name": "boardGroupPermission_board_id_group_id_permission_pk",
"columns": [
"board_id",
"group_id",
"permission"
]
"columns": ["board_id", "group_id", "permission"]
}
},
"uniqueConstraints": {},
@@ -311,12 +288,8 @@
"name": "boardUserPermission_board_id_board_id_fk",
"tableFrom": "boardUserPermission",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -324,12 +297,8 @@
"name": "boardUserPermission_user_id_user_id_fk",
"tableFrom": "boardUserPermission",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -337,11 +306,7 @@
"compositePrimaryKeys": {
"boardUserPermission_board_id_user_id_permission_pk": {
"name": "boardUserPermission_board_id_user_id_permission_pk",
"columns": [
"board_id",
"user_id",
"permission"
]
"columns": ["board_id", "user_id", "permission"]
}
},
"uniqueConstraints": {},
@@ -483,12 +448,8 @@
"name": "board_creator_id_user_id_fk",
"tableFrom": "board",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -498,9 +459,7 @@
"board_name_unique": {
"name": "board_name_unique",
"nullsNotDistinct": false,
"columns": [
"name"
]
"columns": ["name"]
}
},
"policies": {},
@@ -646,12 +605,8 @@
"name": "custom_widget_definition_creator_id_user_id_fk",
"tableFrom": "custom_widget_definition",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -697,12 +652,8 @@
"name": "custom_widget_secret_definition_id_custom_widget_definition_id_fk",
"tableFrom": "custom_widget_secret",
"tableTo": "custom_widget_definition",
"columnsFrom": [
"definition_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["definition_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -710,10 +661,7 @@
"compositePrimaryKeys": {
"custom_widget_secret_definition_id_kind_pk": {
"name": "custom_widget_secret_definition_id_kind_pk",
"columns": [
"definition_id",
"kind"
]
"columns": ["definition_id", "kind"]
}
},
"uniqueConstraints": {},
@@ -744,12 +692,8 @@
"name": "groupMember_group_id_group_id_fk",
"tableFrom": "groupMember",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -757,12 +701,8 @@
"name": "groupMember_user_id_user_id_fk",
"tableFrom": "groupMember",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -770,10 +710,7 @@
"compositePrimaryKeys": {
"groupMember_group_id_user_id_pk": {
"name": "groupMember_group_id_user_id_pk",
"columns": [
"group_id",
"user_id"
]
"columns": ["group_id", "user_id"]
}
},
"uniqueConstraints": {},
@@ -804,12 +741,8 @@
"name": "groupPermission_group_id_group_id_fk",
"tableFrom": "groupPermission",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -867,12 +800,8 @@
"name": "group_owner_id_user_id_fk",
"tableFrom": "group",
"tableTo": "user",
"columnsFrom": [
"owner_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["owner_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -880,12 +809,8 @@
"name": "group_home_board_id_board_id_fk",
"tableFrom": "group",
"tableTo": "board",
"columnsFrom": [
"home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -893,12 +818,8 @@
"name": "group_mobile_home_board_id_board_id_fk",
"tableFrom": "group",
"tableTo": "board",
"columnsFrom": [
"mobile_home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["mobile_home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -908,9 +829,7 @@
"group_name_unique": {
"name": "group_name_unique",
"nullsNotDistinct": false,
"columns": [
"name"
]
"columns": ["name"]
}
},
"policies": {},
@@ -983,12 +902,8 @@
"name": "icon_icon_repository_id_iconRepository_id_fk",
"tableFrom": "icon",
"tableTo": "iconRepository",
"columnsFrom": [
"icon_repository_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["icon_repository_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1028,12 +943,8 @@
"name": "integrationGroupPermissions_integration_id_integration_id_fk",
"tableFrom": "integrationGroupPermissions",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1041,12 +952,8 @@
"name": "integrationGroupPermissions_group_id_group_id_fk",
"tableFrom": "integrationGroupPermissions",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1054,11 +961,7 @@
"compositePrimaryKeys": {
"integration_group_permission__pk": {
"name": "integration_group_permission__pk",
"columns": [
"integration_id",
"group_id",
"permission"
]
"columns": ["integration_id", "group_id", "permission"]
}
},
"uniqueConstraints": {},
@@ -1089,12 +992,8 @@
"name": "integration_item_item_id_item_id_fk",
"tableFrom": "integration_item",
"tableTo": "item",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["item_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1102,12 +1001,8 @@
"name": "integration_item_integration_id_integration_id_fk",
"tableFrom": "integration_item",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1115,10 +1010,7 @@
"compositePrimaryKeys": {
"integration_item_item_id_integration_id_pk": {
"name": "integration_item_item_id_integration_id_pk",
"columns": [
"item_id",
"integration_id"
]
"columns": ["item_id", "integration_id"]
}
},
"uniqueConstraints": {},
@@ -1192,12 +1084,8 @@
"name": "integrationSecret_integration_id_integration_id_fk",
"tableFrom": "integrationSecret",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1205,10 +1093,7 @@
"compositePrimaryKeys": {
"integrationSecret_integration_id_kind_pk": {
"name": "integrationSecret_integration_id_kind_pk",
"columns": [
"integration_id",
"kind"
]
"columns": ["integration_id", "kind"]
}
},
"uniqueConstraints": {},
@@ -1245,12 +1130,8 @@
"name": "integrationUserPermission_integration_id_integration_id_fk",
"tableFrom": "integrationUserPermission",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1258,12 +1139,8 @@
"name": "integrationUserPermission_user_id_user_id_fk",
"tableFrom": "integrationUserPermission",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1271,11 +1148,7 @@
"compositePrimaryKeys": {
"integrationUserPermission_integration_id_user_id_permission_pk": {
"name": "integrationUserPermission_integration_id_user_id_permission_pk",
"columns": [
"integration_id",
"user_id",
"permission"
]
"columns": ["integration_id", "user_id", "permission"]
}
},
"uniqueConstraints": {},
@@ -1340,12 +1213,8 @@
"name": "integration_app_id_app_id_fk",
"tableFrom": "integration",
"tableTo": "app",
"columnsFrom": [
"app_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["app_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -1391,12 +1260,8 @@
"name": "invite_creator_id_user_id_fk",
"tableFrom": "invite",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1406,9 +1271,7 @@
"invite_token_unique": {
"name": "invite_token_unique",
"nullsNotDistinct": false,
"columns": [
"token"
]
"columns": ["token"]
}
},
"policies": {},
@@ -1468,12 +1331,8 @@
"name": "item_layout_item_id_item_id_fk",
"tableFrom": "item_layout",
"tableTo": "item",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["item_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1481,12 +1340,8 @@
"name": "item_layout_section_id_section_id_fk",
"tableFrom": "item_layout",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1494,12 +1349,8 @@
"name": "item_layout_layout_id_layout_id_fk",
"tableFrom": "item_layout",
"tableTo": "layout",
"columnsFrom": [
"layout_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["layout_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1507,11 +1358,7 @@
"compositePrimaryKeys": {
"item_layout_item_id_section_id_layout_id_pk": {
"name": "item_layout_item_id_section_id_layout_id_pk",
"columns": [
"item_id",
"section_id",
"layout_id"
]
"columns": ["item_id", "section_id", "layout_id"]
}
},
"uniqueConstraints": {},
@@ -1562,12 +1409,8 @@
"name": "item_board_id_board_id_fk",
"tableFrom": "item",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1620,12 +1463,8 @@
"name": "layout_board_id_board_id_fk",
"tableFrom": "layout",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1690,12 +1529,8 @@
"name": "media_creator_id_user_id_fk",
"tableFrom": "media",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -1797,12 +1632,8 @@
"name": "search_engine_integration_id_integration_id_fk",
"tableFrom": "search_engine",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1812,9 +1643,7 @@
"search_engine_short_unique": {
"name": "search_engine_short_unique",
"nullsNotDistinct": false,
"columns": [
"short"
]
"columns": ["short"]
}
},
"policies": {},
@@ -1851,12 +1680,8 @@
"name": "section_collapse_state_user_id_user_id_fk",
"tableFrom": "section_collapse_state",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1864,12 +1689,8 @@
"name": "section_collapse_state_section_id_section_id_fk",
"tableFrom": "section_collapse_state",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1877,10 +1698,7 @@
"compositePrimaryKeys": {
"section_collapse_state_user_id_section_id_pk": {
"name": "section_collapse_state_user_id_section_id_pk",
"columns": [
"user_id",
"section_id"
]
"columns": ["user_id", "section_id"]
}
},
"uniqueConstraints": {},
@@ -1941,12 +1759,8 @@
"name": "section_layout_section_id_section_id_fk",
"tableFrom": "section_layout",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1954,12 +1768,8 @@
"name": "section_layout_layout_id_layout_id_fk",
"tableFrom": "section_layout",
"tableTo": "layout",
"columnsFrom": [
"layout_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["layout_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1967,12 +1777,8 @@
"name": "section_layout_parent_section_id_section_id_fk",
"tableFrom": "section_layout",
"tableTo": "section",
"columnsFrom": [
"parent_section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["parent_section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1980,10 +1786,7 @@
"compositePrimaryKeys": {
"section_layout_section_id_layout_id_pk": {
"name": "section_layout_section_id_layout_id_pk",
"columns": [
"section_id",
"layout_id"
]
"columns": ["section_id", "layout_id"]
}
},
"uniqueConstraints": {},
@@ -2045,12 +1848,8 @@
"name": "section_board_id_board_id_fk",
"tableFrom": "section",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -2086,9 +1885,7 @@
"serverSetting_settingKey_unique": {
"name": "serverSetting_settingKey_unique",
"nullsNotDistinct": false,
"columns": [
"setting_key"
]
"columns": ["setting_key"]
}
},
"policies": {},
@@ -2140,12 +1937,8 @@
"name": "session_user_id_user_id_fk",
"tableFrom": "session",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -2277,12 +2070,8 @@
"name": "user_home_board_id_board_id_fk",
"tableFrom": "user",
"tableTo": "board",
"columnsFrom": [
"home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -2290,12 +2079,8 @@
"name": "user_mobile_home_board_id_board_id_fk",
"tableFrom": "user",
"tableTo": "board",
"columnsFrom": [
"mobile_home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["mobile_home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -2303,12 +2088,8 @@
"name": "user_default_search_engine_id_search_engine_id_fk",
"tableFrom": "user",
"tableTo": "search_engine",
"columnsFrom": [
"default_search_engine_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["default_search_engine_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -2347,10 +2128,7 @@
"compositePrimaryKeys": {
"verificationToken_identifier_token_pk": {
"name": "verificationToken_identifier_token_pk",
"columns": [
"identifier",
"token"
]
"columns": ["identifier", "token"]
}
},
"uniqueConstraints": {},
@@ -2386,10 +2164,7 @@
"compositePrimaryKeys": {
"trusted_certificate_hostname_hostname_thumbprint_pk": {
"name": "trusted_certificate_hostname_hostname_thumbprint_pk",
"columns": [
"hostname",
"thumbprint"
]
"columns": ["hostname", "thumbprint"]
}
},
"uniqueConstraints": {},
@@ -2409,4 +2184,4 @@
"schemas": {},
"tables": {}
}
}
}
@@ -97,12 +97,8 @@
"name": "account_user_id_user_id_fk",
"tableFrom": "account",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -110,10 +106,7 @@
"compositePrimaryKeys": {
"account_provider_provider_account_id_pk": {
"name": "account_provider_provider_account_id_pk",
"columns": [
"provider",
"provider_account_id"
]
"columns": ["provider", "provider_account_id"]
}
},
"uniqueConstraints": {},
@@ -150,12 +143,8 @@
"name": "apiKey_user_id_user_id_fk",
"tableFrom": "apiKey",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -244,12 +233,8 @@
"name": "boardGroupPermission_board_id_board_id_fk",
"tableFrom": "boardGroupPermission",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -257,12 +242,8 @@
"name": "boardGroupPermission_group_id_group_id_fk",
"tableFrom": "boardGroupPermission",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -270,11 +251,7 @@
"compositePrimaryKeys": {
"boardGroupPermission_board_id_group_id_permission_pk": {
"name": "boardGroupPermission_board_id_group_id_permission_pk",
"columns": [
"board_id",
"group_id",
"permission"
]
"columns": ["board_id", "group_id", "permission"]
}
},
"uniqueConstraints": {},
@@ -311,12 +288,8 @@
"name": "boardUserPermission_board_id_board_id_fk",
"tableFrom": "boardUserPermission",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -324,12 +297,8 @@
"name": "boardUserPermission_user_id_user_id_fk",
"tableFrom": "boardUserPermission",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -337,11 +306,7 @@
"compositePrimaryKeys": {
"boardUserPermission_board_id_user_id_permission_pk": {
"name": "boardUserPermission_board_id_user_id_permission_pk",
"columns": [
"board_id",
"user_id",
"permission"
]
"columns": ["board_id", "user_id", "permission"]
}
},
"uniqueConstraints": {},
@@ -483,12 +448,8 @@
"name": "board_creator_id_user_id_fk",
"tableFrom": "board",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -498,9 +459,7 @@
"board_name_unique": {
"name": "board_name_unique",
"nullsNotDistinct": false,
"columns": [
"name"
]
"columns": ["name"]
}
},
"policies": {},
@@ -647,12 +606,8 @@
"name": "custom_widget_definition_creator_id_user_id_fk",
"tableFrom": "custom_widget_definition",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -698,12 +653,8 @@
"name": "custom_widget_secret_definition_id_custom_widget_definition_id_fk",
"tableFrom": "custom_widget_secret",
"tableTo": "custom_widget_definition",
"columnsFrom": [
"definition_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["definition_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -711,10 +662,7 @@
"compositePrimaryKeys": {
"custom_widget_secret_definition_id_kind_pk": {
"name": "custom_widget_secret_definition_id_kind_pk",
"columns": [
"definition_id",
"kind"
]
"columns": ["definition_id", "kind"]
}
},
"uniqueConstraints": {},
@@ -745,12 +693,8 @@
"name": "groupMember_group_id_group_id_fk",
"tableFrom": "groupMember",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -758,12 +702,8 @@
"name": "groupMember_user_id_user_id_fk",
"tableFrom": "groupMember",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -771,10 +711,7 @@
"compositePrimaryKeys": {
"groupMember_group_id_user_id_pk": {
"name": "groupMember_group_id_user_id_pk",
"columns": [
"group_id",
"user_id"
]
"columns": ["group_id", "user_id"]
}
},
"uniqueConstraints": {},
@@ -805,12 +742,8 @@
"name": "groupPermission_group_id_group_id_fk",
"tableFrom": "groupPermission",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -868,12 +801,8 @@
"name": "group_owner_id_user_id_fk",
"tableFrom": "group",
"tableTo": "user",
"columnsFrom": [
"owner_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["owner_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -881,12 +810,8 @@
"name": "group_home_board_id_board_id_fk",
"tableFrom": "group",
"tableTo": "board",
"columnsFrom": [
"home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -894,12 +819,8 @@
"name": "group_mobile_home_board_id_board_id_fk",
"tableFrom": "group",
"tableTo": "board",
"columnsFrom": [
"mobile_home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["mobile_home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -909,9 +830,7 @@
"group_name_unique": {
"name": "group_name_unique",
"nullsNotDistinct": false,
"columns": [
"name"
]
"columns": ["name"]
}
},
"policies": {},
@@ -984,12 +903,8 @@
"name": "icon_icon_repository_id_iconRepository_id_fk",
"tableFrom": "icon",
"tableTo": "iconRepository",
"columnsFrom": [
"icon_repository_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["icon_repository_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1029,12 +944,8 @@
"name": "integrationGroupPermissions_integration_id_integration_id_fk",
"tableFrom": "integrationGroupPermissions",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1042,12 +953,8 @@
"name": "integrationGroupPermissions_group_id_group_id_fk",
"tableFrom": "integrationGroupPermissions",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1055,11 +962,7 @@
"compositePrimaryKeys": {
"integration_group_permission__pk": {
"name": "integration_group_permission__pk",
"columns": [
"integration_id",
"group_id",
"permission"
]
"columns": ["integration_id", "group_id", "permission"]
}
},
"uniqueConstraints": {},
@@ -1090,12 +993,8 @@
"name": "integration_item_item_id_item_id_fk",
"tableFrom": "integration_item",
"tableTo": "item",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["item_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1103,12 +1002,8 @@
"name": "integration_item_integration_id_integration_id_fk",
"tableFrom": "integration_item",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1116,10 +1011,7 @@
"compositePrimaryKeys": {
"integration_item_item_id_integration_id_pk": {
"name": "integration_item_item_id_integration_id_pk",
"columns": [
"item_id",
"integration_id"
]
"columns": ["item_id", "integration_id"]
}
},
"uniqueConstraints": {},
@@ -1193,12 +1085,8 @@
"name": "integrationSecret_integration_id_integration_id_fk",
"tableFrom": "integrationSecret",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1206,10 +1094,7 @@
"compositePrimaryKeys": {
"integrationSecret_integration_id_kind_pk": {
"name": "integrationSecret_integration_id_kind_pk",
"columns": [
"integration_id",
"kind"
]
"columns": ["integration_id", "kind"]
}
},
"uniqueConstraints": {},
@@ -1246,12 +1131,8 @@
"name": "integrationUserPermission_integration_id_integration_id_fk",
"tableFrom": "integrationUserPermission",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1259,12 +1140,8 @@
"name": "integrationUserPermission_user_id_user_id_fk",
"tableFrom": "integrationUserPermission",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1272,11 +1149,7 @@
"compositePrimaryKeys": {
"integrationUserPermission_integration_id_user_id_permission_pk": {
"name": "integrationUserPermission_integration_id_user_id_permission_pk",
"columns": [
"integration_id",
"user_id",
"permission"
]
"columns": ["integration_id", "user_id", "permission"]
}
},
"uniqueConstraints": {},
@@ -1341,12 +1214,8 @@
"name": "integration_app_id_app_id_fk",
"tableFrom": "integration",
"tableTo": "app",
"columnsFrom": [
"app_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["app_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -1392,12 +1261,8 @@
"name": "invite_creator_id_user_id_fk",
"tableFrom": "invite",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1407,9 +1272,7 @@
"invite_token_unique": {
"name": "invite_token_unique",
"nullsNotDistinct": false,
"columns": [
"token"
]
"columns": ["token"]
}
},
"policies": {},
@@ -1469,12 +1332,8 @@
"name": "item_layout_item_id_item_id_fk",
"tableFrom": "item_layout",
"tableTo": "item",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["item_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1482,12 +1341,8 @@
"name": "item_layout_section_id_section_id_fk",
"tableFrom": "item_layout",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1495,12 +1350,8 @@
"name": "item_layout_layout_id_layout_id_fk",
"tableFrom": "item_layout",
"tableTo": "layout",
"columnsFrom": [
"layout_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["layout_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1508,11 +1359,7 @@
"compositePrimaryKeys": {
"item_layout_item_id_section_id_layout_id_pk": {
"name": "item_layout_item_id_section_id_layout_id_pk",
"columns": [
"item_id",
"section_id",
"layout_id"
]
"columns": ["item_id", "section_id", "layout_id"]
}
},
"uniqueConstraints": {},
@@ -1563,12 +1410,8 @@
"name": "item_board_id_board_id_fk",
"tableFrom": "item",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1621,12 +1464,8 @@
"name": "layout_board_id_board_id_fk",
"tableFrom": "layout",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1691,12 +1530,8 @@
"name": "media_creator_id_user_id_fk",
"tableFrom": "media",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -1798,12 +1633,8 @@
"name": "search_engine_integration_id_integration_id_fk",
"tableFrom": "search_engine",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1813,9 +1644,7 @@
"search_engine_short_unique": {
"name": "search_engine_short_unique",
"nullsNotDistinct": false,
"columns": [
"short"
]
"columns": ["short"]
}
},
"policies": {},
@@ -1852,12 +1681,8 @@
"name": "section_collapse_state_user_id_user_id_fk",
"tableFrom": "section_collapse_state",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1865,12 +1690,8 @@
"name": "section_collapse_state_section_id_section_id_fk",
"tableFrom": "section_collapse_state",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1878,10 +1699,7 @@
"compositePrimaryKeys": {
"section_collapse_state_user_id_section_id_pk": {
"name": "section_collapse_state_user_id_section_id_pk",
"columns": [
"user_id",
"section_id"
]
"columns": ["user_id", "section_id"]
}
},
"uniqueConstraints": {},
@@ -1942,12 +1760,8 @@
"name": "section_layout_section_id_section_id_fk",
"tableFrom": "section_layout",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1955,12 +1769,8 @@
"name": "section_layout_layout_id_layout_id_fk",
"tableFrom": "section_layout",
"tableTo": "layout",
"columnsFrom": [
"layout_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["layout_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1968,12 +1778,8 @@
"name": "section_layout_parent_section_id_section_id_fk",
"tableFrom": "section_layout",
"tableTo": "section",
"columnsFrom": [
"parent_section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["parent_section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1981,10 +1787,7 @@
"compositePrimaryKeys": {
"section_layout_section_id_layout_id_pk": {
"name": "section_layout_section_id_layout_id_pk",
"columns": [
"section_id",
"layout_id"
]
"columns": ["section_id", "layout_id"]
}
},
"uniqueConstraints": {},
@@ -2046,12 +1849,8 @@
"name": "section_board_id_board_id_fk",
"tableFrom": "section",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -2087,9 +1886,7 @@
"serverSetting_settingKey_unique": {
"name": "serverSetting_settingKey_unique",
"nullsNotDistinct": false,
"columns": [
"setting_key"
]
"columns": ["setting_key"]
}
},
"policies": {},
@@ -2141,12 +1938,8 @@
"name": "session_user_id_user_id_fk",
"tableFrom": "session",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -2278,12 +2071,8 @@
"name": "user_home_board_id_board_id_fk",
"tableFrom": "user",
"tableTo": "board",
"columnsFrom": [
"home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -2291,12 +2080,8 @@
"name": "user_mobile_home_board_id_board_id_fk",
"tableFrom": "user",
"tableTo": "board",
"columnsFrom": [
"mobile_home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["mobile_home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -2304,12 +2089,8 @@
"name": "user_default_search_engine_id_search_engine_id_fk",
"tableFrom": "user",
"tableTo": "search_engine",
"columnsFrom": [
"default_search_engine_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["default_search_engine_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -2348,10 +2129,7 @@
"compositePrimaryKeys": {
"verificationToken_identifier_token_pk": {
"name": "verificationToken_identifier_token_pk",
"columns": [
"identifier",
"token"
]
"columns": ["identifier", "token"]
}
},
"uniqueConstraints": {},
@@ -2387,10 +2165,7 @@
"compositePrimaryKeys": {
"trusted_certificate_hostname_hostname_thumbprint_pk": {
"name": "trusted_certificate_hostname_hostname_thumbprint_pk",
"columns": [
"hostname",
"thumbprint"
]
"columns": ["hostname", "thumbprint"]
}
},
"uniqueConstraints": {},
@@ -97,12 +97,8 @@
"name": "account_user_id_user_id_fk",
"tableFrom": "account",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -110,10 +106,7 @@
"compositePrimaryKeys": {
"account_provider_provider_account_id_pk": {
"name": "account_provider_provider_account_id_pk",
"columns": [
"provider",
"provider_account_id"
]
"columns": ["provider", "provider_account_id"]
}
},
"uniqueConstraints": {},
@@ -150,12 +143,8 @@
"name": "apiKey_user_id_user_id_fk",
"tableFrom": "apiKey",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -244,12 +233,8 @@
"name": "boardGroupPermission_board_id_board_id_fk",
"tableFrom": "boardGroupPermission",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -257,12 +242,8 @@
"name": "boardGroupPermission_group_id_group_id_fk",
"tableFrom": "boardGroupPermission",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -270,11 +251,7 @@
"compositePrimaryKeys": {
"boardGroupPermission_board_id_group_id_permission_pk": {
"name": "boardGroupPermission_board_id_group_id_permission_pk",
"columns": [
"board_id",
"group_id",
"permission"
]
"columns": ["board_id", "group_id", "permission"]
}
},
"uniqueConstraints": {},
@@ -311,12 +288,8 @@
"name": "boardUserPermission_board_id_board_id_fk",
"tableFrom": "boardUserPermission",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -324,12 +297,8 @@
"name": "boardUserPermission_user_id_user_id_fk",
"tableFrom": "boardUserPermission",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -337,11 +306,7 @@
"compositePrimaryKeys": {
"boardUserPermission_board_id_user_id_permission_pk": {
"name": "boardUserPermission_board_id_user_id_permission_pk",
"columns": [
"board_id",
"user_id",
"permission"
]
"columns": ["board_id", "user_id", "permission"]
}
},
"uniqueConstraints": {},
@@ -483,12 +448,8 @@
"name": "board_creator_id_user_id_fk",
"tableFrom": "board",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -498,9 +459,7 @@
"board_name_unique": {
"name": "board_name_unique",
"nullsNotDistinct": false,
"columns": [
"name"
]
"columns": ["name"]
}
},
"policies": {},
@@ -647,12 +606,8 @@
"name": "custom_widget_definition_creator_id_user_id_fk",
"tableFrom": "custom_widget_definition",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -698,12 +653,8 @@
"name": "custom_widget_secret_definition_id_custom_widget_definition_id_fk",
"tableFrom": "custom_widget_secret",
"tableTo": "custom_widget_definition",
"columnsFrom": [
"definition_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["definition_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -711,10 +662,7 @@
"compositePrimaryKeys": {
"custom_widget_secret_definition_id_kind_pk": {
"name": "custom_widget_secret_definition_id_kind_pk",
"columns": [
"definition_id",
"kind"
]
"columns": ["definition_id", "kind"]
}
},
"uniqueConstraints": {},
@@ -745,12 +693,8 @@
"name": "groupMember_group_id_group_id_fk",
"tableFrom": "groupMember",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -758,12 +702,8 @@
"name": "groupMember_user_id_user_id_fk",
"tableFrom": "groupMember",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -771,10 +711,7 @@
"compositePrimaryKeys": {
"groupMember_group_id_user_id_pk": {
"name": "groupMember_group_id_user_id_pk",
"columns": [
"group_id",
"user_id"
]
"columns": ["group_id", "user_id"]
}
},
"uniqueConstraints": {},
@@ -805,12 +742,8 @@
"name": "groupPermission_group_id_group_id_fk",
"tableFrom": "groupPermission",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -868,12 +801,8 @@
"name": "group_owner_id_user_id_fk",
"tableFrom": "group",
"tableTo": "user",
"columnsFrom": [
"owner_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["owner_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -881,12 +810,8 @@
"name": "group_home_board_id_board_id_fk",
"tableFrom": "group",
"tableTo": "board",
"columnsFrom": [
"home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -894,12 +819,8 @@
"name": "group_mobile_home_board_id_board_id_fk",
"tableFrom": "group",
"tableTo": "board",
"columnsFrom": [
"mobile_home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["mobile_home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -909,9 +830,7 @@
"group_name_unique": {
"name": "group_name_unique",
"nullsNotDistinct": false,
"columns": [
"name"
]
"columns": ["name"]
}
},
"policies": {},
@@ -984,12 +903,8 @@
"name": "icon_icon_repository_id_iconRepository_id_fk",
"tableFrom": "icon",
"tableTo": "iconRepository",
"columnsFrom": [
"icon_repository_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["icon_repository_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1029,12 +944,8 @@
"name": "integrationGroupPermissions_integration_id_integration_id_fk",
"tableFrom": "integrationGroupPermissions",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1042,12 +953,8 @@
"name": "integrationGroupPermissions_group_id_group_id_fk",
"tableFrom": "integrationGroupPermissions",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1055,11 +962,7 @@
"compositePrimaryKeys": {
"integration_group_permission__pk": {
"name": "integration_group_permission__pk",
"columns": [
"integration_id",
"group_id",
"permission"
]
"columns": ["integration_id", "group_id", "permission"]
}
},
"uniqueConstraints": {},
@@ -1090,12 +993,8 @@
"name": "integration_item_item_id_item_id_fk",
"tableFrom": "integration_item",
"tableTo": "item",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["item_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1103,12 +1002,8 @@
"name": "integration_item_integration_id_integration_id_fk",
"tableFrom": "integration_item",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1116,10 +1011,7 @@
"compositePrimaryKeys": {
"integration_item_item_id_integration_id_pk": {
"name": "integration_item_item_id_integration_id_pk",
"columns": [
"item_id",
"integration_id"
]
"columns": ["item_id", "integration_id"]
}
},
"uniqueConstraints": {},
@@ -1193,12 +1085,8 @@
"name": "integrationSecret_integration_id_integration_id_fk",
"tableFrom": "integrationSecret",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1206,10 +1094,7 @@
"compositePrimaryKeys": {
"integrationSecret_integration_id_kind_pk": {
"name": "integrationSecret_integration_id_kind_pk",
"columns": [
"integration_id",
"kind"
]
"columns": ["integration_id", "kind"]
}
},
"uniqueConstraints": {},
@@ -1246,12 +1131,8 @@
"name": "integrationUserPermission_integration_id_integration_id_fk",
"tableFrom": "integrationUserPermission",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1259,12 +1140,8 @@
"name": "integrationUserPermission_user_id_user_id_fk",
"tableFrom": "integrationUserPermission",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1272,11 +1149,7 @@
"compositePrimaryKeys": {
"integrationUserPermission_integration_id_user_id_permission_pk": {
"name": "integrationUserPermission_integration_id_user_id_permission_pk",
"columns": [
"integration_id",
"user_id",
"permission"
]
"columns": ["integration_id", "user_id", "permission"]
}
},
"uniqueConstraints": {},
@@ -1341,12 +1214,8 @@
"name": "integration_app_id_app_id_fk",
"tableFrom": "integration",
"tableTo": "app",
"columnsFrom": [
"app_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["app_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -1392,12 +1261,8 @@
"name": "invite_creator_id_user_id_fk",
"tableFrom": "invite",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1407,9 +1272,7 @@
"invite_token_unique": {
"name": "invite_token_unique",
"nullsNotDistinct": false,
"columns": [
"token"
]
"columns": ["token"]
}
},
"policies": {},
@@ -1469,12 +1332,8 @@
"name": "item_layout_item_id_item_id_fk",
"tableFrom": "item_layout",
"tableTo": "item",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["item_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1482,12 +1341,8 @@
"name": "item_layout_section_id_section_id_fk",
"tableFrom": "item_layout",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1495,12 +1350,8 @@
"name": "item_layout_layout_id_layout_id_fk",
"tableFrom": "item_layout",
"tableTo": "layout",
"columnsFrom": [
"layout_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["layout_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1508,11 +1359,7 @@
"compositePrimaryKeys": {
"item_layout_item_id_section_id_layout_id_pk": {
"name": "item_layout_item_id_section_id_layout_id_pk",
"columns": [
"item_id",
"section_id",
"layout_id"
]
"columns": ["item_id", "section_id", "layout_id"]
}
},
"uniqueConstraints": {},
@@ -1563,12 +1410,8 @@
"name": "item_board_id_board_id_fk",
"tableFrom": "item",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1621,12 +1464,8 @@
"name": "layout_board_id_board_id_fk",
"tableFrom": "layout",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1691,12 +1530,8 @@
"name": "media_creator_id_user_id_fk",
"tableFrom": "media",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -1798,12 +1633,8 @@
"name": "search_engine_integration_id_integration_id_fk",
"tableFrom": "search_engine",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1813,9 +1644,7 @@
"search_engine_short_unique": {
"name": "search_engine_short_unique",
"nullsNotDistinct": false,
"columns": [
"short"
]
"columns": ["short"]
}
},
"policies": {},
@@ -1852,12 +1681,8 @@
"name": "section_collapse_state_user_id_user_id_fk",
"tableFrom": "section_collapse_state",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1865,12 +1690,8 @@
"name": "section_collapse_state_section_id_section_id_fk",
"tableFrom": "section_collapse_state",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1878,10 +1699,7 @@
"compositePrimaryKeys": {
"section_collapse_state_user_id_section_id_pk": {
"name": "section_collapse_state_user_id_section_id_pk",
"columns": [
"user_id",
"section_id"
]
"columns": ["user_id", "section_id"]
}
},
"uniqueConstraints": {},
@@ -1942,12 +1760,8 @@
"name": "section_layout_section_id_section_id_fk",
"tableFrom": "section_layout",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1955,12 +1769,8 @@
"name": "section_layout_layout_id_layout_id_fk",
"tableFrom": "section_layout",
"tableTo": "layout",
"columnsFrom": [
"layout_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["layout_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1968,12 +1778,8 @@
"name": "section_layout_parent_section_id_section_id_fk",
"tableFrom": "section_layout",
"tableTo": "section",
"columnsFrom": [
"parent_section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["parent_section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1981,10 +1787,7 @@
"compositePrimaryKeys": {
"section_layout_section_id_layout_id_pk": {
"name": "section_layout_section_id_layout_id_pk",
"columns": [
"section_id",
"layout_id"
]
"columns": ["section_id", "layout_id"]
}
},
"uniqueConstraints": {},
@@ -2046,12 +1849,8 @@
"name": "section_board_id_board_id_fk",
"tableFrom": "section",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -2087,9 +1886,7 @@
"serverSetting_settingKey_unique": {
"name": "serverSetting_settingKey_unique",
"nullsNotDistinct": false,
"columns": [
"setting_key"
]
"columns": ["setting_key"]
}
},
"policies": {},
@@ -2141,12 +1938,8 @@
"name": "session_user_id_user_id_fk",
"tableFrom": "session",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -2278,12 +2071,8 @@
"name": "user_home_board_id_board_id_fk",
"tableFrom": "user",
"tableTo": "board",
"columnsFrom": [
"home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -2291,12 +2080,8 @@
"name": "user_mobile_home_board_id_board_id_fk",
"tableFrom": "user",
"tableTo": "board",
"columnsFrom": [
"mobile_home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["mobile_home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -2304,12 +2089,8 @@
"name": "user_default_search_engine_id_search_engine_id_fk",
"tableFrom": "user",
"tableTo": "search_engine",
"columnsFrom": [
"default_search_engine_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["default_search_engine_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -2348,10 +2129,7 @@
"compositePrimaryKeys": {
"verificationToken_identifier_token_pk": {
"name": "verificationToken_identifier_token_pk",
"columns": [
"identifier",
"token"
]
"columns": ["identifier", "token"]
}
},
"uniqueConstraints": {},
@@ -2387,10 +2165,7 @@
"compositePrimaryKeys": {
"trusted_certificate_hostname_hostname_thumbprint_pk": {
"name": "trusted_certificate_hostname_hostname_thumbprint_pk",
"columns": [
"hostname",
"thumbprint"
]
"columns": ["hostname", "thumbprint"]
}
},
"uniqueConstraints": {},
@@ -2434,22 +2209,15 @@
"tableFrom": "widget_secret",
"tableTo": "item",
"schemaTo": "public",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["item_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"widget_secret_item_id_kind_pk": {
"columns": [
"item_id",
"kind"
],
"columns": ["item_id", "kind"],
"name": "widget_secret_item_id_kind_pk"
}
},
File diff suppressed because it is too large. Load diff
@@ -1 +0,0 @@
ALTER TABLE `layout` ADD `role` text DEFAULT 'custom' NOT NULL;
@@ -1 +0,0 @@
ALTER TABLE `assistant_configuration` ADD `web_search_enabled` integer DEFAULT false NOT NULL;
@@ -88,9 +88,7 @@
"indexes": {
"userId_idx": {
"name": "userId_idx",
"columns": [
"user_id"
],
"columns": ["user_id"],
"isUnique": false
}
},
@@ -99,22 +97,15 @@
"name": "account_user_id_user_id_fk",
"tableFrom": "account",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"account_provider_provider_account_id_pk": {
"columns": [
"provider",
"provider_account_id"
],
"columns": ["provider", "provider_account_id"],
"name": "account_provider_provider_account_id_pk"
}
},
@@ -152,12 +143,8 @@
"name": "apiKey_user_id_user_id_fk",
"tableFrom": "apiKey",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -249,12 +236,8 @@
"name": "boardGroupPermission_board_id_board_id_fk",
"tableFrom": "boardGroupPermission",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -262,23 +245,15 @@
"name": "boardGroupPermission_group_id_group_id_fk",
"tableFrom": "boardGroupPermission",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"boardGroupPermission_board_id_group_id_permission_pk": {
"columns": [
"board_id",
"group_id",
"permission"
],
"columns": ["board_id", "group_id", "permission"],
"name": "boardGroupPermission_board_id_group_id_permission_pk"
}
},
@@ -316,12 +291,8 @@
"name": "boardUserPermission_board_id_board_id_fk",
"tableFrom": "boardUserPermission",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -329,23 +300,15 @@
"name": "boardUserPermission_user_id_user_id_fk",
"tableFrom": "boardUserPermission",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"boardUserPermission_board_id_user_id_permission_pk": {
"columns": [
"board_id",
"user_id",
"permission"
],
"columns": ["board_id", "user_id", "permission"],
"name": "boardUserPermission_board_id_user_id_permission_pk"
}
},
@@ -501,9 +464,7 @@
"indexes": {
"board_name_unique": {
"name": "board_name_unique",
"columns": [
"name"
],
"columns": ["name"],
"isUnique": true
}
},
@@ -512,12 +473,8 @@
"name": "board_creator_id_user_id_fk",
"tableFrom": "board",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -679,12 +636,8 @@
"name": "custom_widget_definition_creator_id_user_id_fk",
"tableFrom": "custom_widget_definition",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -731,22 +684,15 @@
"name": "custom_widget_secret_definition_id_custom_widget_definition_id_fk",
"tableFrom": "custom_widget_secret",
"tableTo": "custom_widget_definition",
"columnsFrom": [
"definition_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["definition_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"custom_widget_secret_definition_id_kind_pk": {
"columns": [
"definition_id",
"kind"
],
"columns": ["definition_id", "kind"],
"name": "custom_widget_secret_definition_id_kind_pk"
}
},
@@ -777,12 +723,8 @@
"name": "groupMember_group_id_group_id_fk",
"tableFrom": "groupMember",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -790,22 +732,15 @@
"name": "groupMember_user_id_user_id_fk",
"tableFrom": "groupMember",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"groupMember_group_id_user_id_pk": {
"columns": [
"group_id",
"user_id"
],
"columns": ["group_id", "user_id"],
"name": "groupMember_group_id_user_id_pk"
}
},
@@ -836,12 +771,8 @@
"name": "groupPermission_group_id_group_id_fk",
"tableFrom": "groupPermission",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -899,9 +830,7 @@
"indexes": {
"group_name_unique": {
"name": "group_name_unique",
"columns": [
"name"
],
"columns": ["name"],
"isUnique": true
}
},
@@ -910,12 +839,8 @@
"name": "group_owner_id_user_id_fk",
"tableFrom": "group",
"tableTo": "user",
"columnsFrom": [
"owner_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["owner_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -923,12 +848,8 @@
"name": "group_home_board_id_board_id_fk",
"tableFrom": "group",
"tableTo": "board",
"columnsFrom": [
"home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -936,12 +857,8 @@
"name": "group_mobile_home_board_id_board_id_fk",
"tableFrom": "group",
"tableTo": "board",
"columnsFrom": [
"mobile_home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["mobile_home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -1019,12 +936,8 @@
"name": "icon_icon_repository_id_iconRepository_id_fk",
"tableFrom": "icon",
"tableTo": "iconRepository",
"columnsFrom": [
"icon_repository_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["icon_repository_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1064,12 +977,8 @@
"name": "integrationGroupPermissions_integration_id_integration_id_fk",
"tableFrom": "integrationGroupPermissions",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1077,23 +986,15 @@
"name": "integrationGroupPermissions_group_id_group_id_fk",
"tableFrom": "integrationGroupPermissions",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"integrationGroupPermissions_integration_id_group_id_permission_pk": {
"columns": [
"integration_id",
"group_id",
"permission"
],
"columns": ["integration_id", "group_id", "permission"],
"name": "integrationGroupPermissions_integration_id_group_id_permission_pk"
}
},
@@ -1124,12 +1025,8 @@
"name": "integration_item_item_id_item_id_fk",
"tableFrom": "integration_item",
"tableTo": "item",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["item_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1137,22 +1034,15 @@
"name": "integration_item_integration_id_integration_id_fk",
"tableFrom": "integration_item",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"integration_item_item_id_integration_id_pk": {
"columns": [
"item_id",
"integration_id"
],
"columns": ["item_id", "integration_id"],
"name": "integration_item_item_id_integration_id_pk"
}
},
@@ -1194,16 +1084,12 @@
"indexes": {
"integration_secret__kind_idx": {
"name": "integration_secret__kind_idx",
"columns": [
"kind"
],
"columns": ["kind"],
"isUnique": false
},
"integration_secret__updated_at_idx": {
"name": "integration_secret__updated_at_idx",
"columns": [
"updated_at"
],
"columns": ["updated_at"],
"isUnique": false
}
},
@@ -1212,22 +1098,15 @@
"name": "integrationSecret_integration_id_integration_id_fk",
"tableFrom": "integrationSecret",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"integrationSecret_integration_id_kind_pk": {
"columns": [
"integration_id",
"kind"
],
"columns": ["integration_id", "kind"],
"name": "integrationSecret_integration_id_kind_pk"
}
},
@@ -1265,12 +1144,8 @@
"name": "integrationUserPermission_integration_id_integration_id_fk",
"tableFrom": "integrationUserPermission",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1278,23 +1153,15 @@
"name": "integrationUserPermission_user_id_user_id_fk",
"tableFrom": "integrationUserPermission",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"integrationUserPermission_integration_id_user_id_permission_pk": {
"columns": [
"integration_id",
"user_id",
"permission"
],
"columns": ["integration_id", "user_id", "permission"],
"name": "integrationUserPermission_integration_id_user_id_permission_pk"
}
},
@@ -1343,9 +1210,7 @@
"indexes": {
"integration__kind_idx": {
"name": "integration__kind_idx",
"columns": [
"kind"
],
"columns": ["kind"],
"isUnique": false
}
},
@@ -1354,12 +1219,8 @@
"name": "integration_app_id_app_id_fk",
"tableFrom": "integration",
"tableTo": "app",
"columnsFrom": [
"app_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["app_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -1403,9 +1264,7 @@
"indexes": {
"invite_token_unique": {
"name": "invite_token_unique",
"columns": [
"token"
],
"columns": ["token"],
"isUnique": true
}
},
@@ -1414,12 +1273,8 @@
"name": "invite_creator_id_user_id_fk",
"tableFrom": "invite",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1487,12 +1342,8 @@
"name": "item_layout_item_id_item_id_fk",
"tableFrom": "item_layout",
"tableTo": "item",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["item_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1500,12 +1351,8 @@
"name": "item_layout_section_id_section_id_fk",
"tableFrom": "item_layout",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1513,23 +1360,15 @@
"name": "item_layout_layout_id_layout_id_fk",
"tableFrom": "item_layout",
"tableTo": "layout",
"columnsFrom": [
"layout_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["layout_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"item_layout_item_id_section_id_layout_id_pk": {
"columns": [
"item_id",
"section_id",
"layout_id"
],
"columns": ["item_id", "section_id", "layout_id"],
"name": "item_layout_item_id_section_id_layout_id_pk"
}
},
@@ -1583,12 +1422,8 @@
"name": "item_board_id_board_id_fk",
"tableFrom": "item",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1643,12 +1478,8 @@
"name": "layout_board_id_board_id_fk",
"tableFrom": "layout",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1717,12 +1548,8 @@
"name": "media_creator_id_user_id_fk",
"tableFrom": "media",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -1826,9 +1653,7 @@
"indexes": {
"search_engine_short_unique": {
"name": "search_engine_short_unique",
"columns": [
"short"
],
"columns": ["short"],
"isUnique": true
}
},
@@ -1837,12 +1662,8 @@
"name": "search_engine_integration_id_integration_id_fk",
"tableFrom": "search_engine",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1883,12 +1704,8 @@
"name": "section_collapse_state_user_id_user_id_fk",
"tableFrom": "section_collapse_state",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1896,22 +1713,15 @@
"name": "section_collapse_state_section_id_section_id_fk",
"tableFrom": "section_collapse_state",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"section_collapse_state_user_id_section_id_pk": {
"columns": [
"user_id",
"section_id"
],
"columns": ["user_id", "section_id"],
"name": "section_collapse_state_user_id_section_id_pk"
}
},
@@ -1977,12 +1787,8 @@
"name": "section_layout_section_id_section_id_fk",
"tableFrom": "section_layout",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1990,12 +1796,8 @@
"name": "section_layout_layout_id_layout_id_fk",
"tableFrom": "section_layout",
"tableTo": "layout",
"columnsFrom": [
"layout_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["layout_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -2003,22 +1805,15 @@
"name": "section_layout_parent_section_id_section_id_fk",
"tableFrom": "section_layout",
"tableTo": "section",
"columnsFrom": [
"parent_section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["parent_section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"section_layout_section_id_layout_id_pk": {
"columns": [
"section_id",
"layout_id"
],
"columns": ["section_id", "layout_id"],
"name": "section_layout_section_id_layout_id_pk"
}
},
@@ -2085,12 +1880,8 @@
"name": "section_board_id_board_id_fk",
"tableFrom": "section",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -2121,9 +1912,7 @@
"indexes": {
"serverSetting_settingKey_unique": {
"name": "serverSetting_settingKey_unique",
"columns": [
"setting_key"
],
"columns": ["setting_key"],
"isUnique": true
}
},
@@ -2160,9 +1949,7 @@
"indexes": {
"user_id_idx": {
"name": "user_id_idx",
"columns": [
"user_id"
],
"columns": ["user_id"],
"isUnique": false
}
},
@@ -2171,12 +1958,8 @@
"name": "session_user_id_user_id_fk",
"tableFrom": "session",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -2214,10 +1997,7 @@
"foreignKeys": {},
"compositePrimaryKeys": {
"trusted_certificate_hostname_hostname_thumbprint_pk": {
"columns": [
"hostname",
"thumbprint"
],
"columns": ["hostname", "thumbprint"],
"name": "trusted_certificate_hostname_hostname_thumbprint_pk"
}
},
@@ -2361,12 +2141,8 @@
"name": "user_home_board_id_board_id_fk",
"tableFrom": "user",
"tableTo": "board",
"columnsFrom": [
"home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -2374,12 +2150,8 @@
"name": "user_mobile_home_board_id_board_id_fk",
"tableFrom": "user",
"tableTo": "board",
"columnsFrom": [
"mobile_home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["mobile_home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -2387,12 +2159,8 @@
"name": "user_default_search_engine_id_search_engine_id_fk",
"tableFrom": "user",
"tableTo": "search_engine",
"columnsFrom": [
"default_search_engine_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["default_search_engine_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -2430,10 +2198,7 @@
"foreignKeys": {},
"compositePrimaryKeys": {
"verificationToken_identifier_token_pk": {
"columns": [
"identifier",
"token"
],
"columns": ["identifier", "token"],
"name": "verificationToken_identifier_token_pk"
}
},
@@ -2451,4 +2216,4 @@
"internal": {
"indexes": {}
}
}
}
@@ -88,9 +88,7 @@
"indexes": {
"userId_idx": {
"name": "userId_idx",
"columns": [
"user_id"
],
"columns": ["user_id"],
"isUnique": false
}
},
@@ -99,22 +97,15 @@
"name": "account_user_id_user_id_fk",
"tableFrom": "account",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"account_provider_provider_account_id_pk": {
"columns": [
"provider",
"provider_account_id"
],
"columns": ["provider", "provider_account_id"],
"name": "account_provider_provider_account_id_pk"
}
},
@@ -152,12 +143,8 @@
"name": "apiKey_user_id_user_id_fk",
"tableFrom": "apiKey",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -249,12 +236,8 @@
"name": "boardGroupPermission_board_id_board_id_fk",
"tableFrom": "boardGroupPermission",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -262,23 +245,15 @@
"name": "boardGroupPermission_group_id_group_id_fk",
"tableFrom": "boardGroupPermission",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"boardGroupPermission_board_id_group_id_permission_pk": {
"columns": [
"board_id",
"group_id",
"permission"
],
"columns": ["board_id", "group_id", "permission"],
"name": "boardGroupPermission_board_id_group_id_permission_pk"
}
},
@@ -316,12 +291,8 @@
"name": "boardUserPermission_board_id_board_id_fk",
"tableFrom": "boardUserPermission",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -329,23 +300,15 @@
"name": "boardUserPermission_user_id_user_id_fk",
"tableFrom": "boardUserPermission",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"boardUserPermission_board_id_user_id_permission_pk": {
"columns": [
"board_id",
"user_id",
"permission"
],
"columns": ["board_id", "user_id", "permission"],
"name": "boardUserPermission_board_id_user_id_permission_pk"
}
},
@@ -501,9 +464,7 @@
"indexes": {
"board_name_unique": {
"name": "board_name_unique",
"columns": [
"name"
],
"columns": ["name"],
"isUnique": true
}
},
@@ -512,12 +473,8 @@
"name": "board_creator_id_user_id_fk",
"tableFrom": "board",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -680,12 +637,8 @@
"name": "custom_widget_definition_creator_id_user_id_fk",
"tableFrom": "custom_widget_definition",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -732,22 +685,15 @@
"name": "custom_widget_secret_definition_id_custom_widget_definition_id_fk",
"tableFrom": "custom_widget_secret",
"tableTo": "custom_widget_definition",
"columnsFrom": [
"definition_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["definition_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"custom_widget_secret_definition_id_kind_pk": {
"columns": [
"definition_id",
"kind"
],
"columns": ["definition_id", "kind"],
"name": "custom_widget_secret_definition_id_kind_pk"
}
},
@@ -778,12 +724,8 @@
"name": "groupMember_group_id_group_id_fk",
"tableFrom": "groupMember",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -791,22 +733,15 @@
"name": "groupMember_user_id_user_id_fk",
"tableFrom": "groupMember",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"groupMember_group_id_user_id_pk": {
"columns": [
"group_id",
"user_id"
],
"columns": ["group_id", "user_id"],
"name": "groupMember_group_id_user_id_pk"
}
},
@@ -837,12 +772,8 @@
"name": "groupPermission_group_id_group_id_fk",
"tableFrom": "groupPermission",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -900,9 +831,7 @@
"indexes": {
"group_name_unique": {
"name": "group_name_unique",
"columns": [
"name"
],
"columns": ["name"],
"isUnique": true
}
},
@@ -911,12 +840,8 @@
"name": "group_owner_id_user_id_fk",
"tableFrom": "group",
"tableTo": "user",
"columnsFrom": [
"owner_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["owner_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -924,12 +849,8 @@
"name": "group_home_board_id_board_id_fk",
"tableFrom": "group",
"tableTo": "board",
"columnsFrom": [
"home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -937,12 +858,8 @@
"name": "group_mobile_home_board_id_board_id_fk",
"tableFrom": "group",
"tableTo": "board",
"columnsFrom": [
"mobile_home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["mobile_home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -1020,12 +937,8 @@
"name": "icon_icon_repository_id_iconRepository_id_fk",
"tableFrom": "icon",
"tableTo": "iconRepository",
"columnsFrom": [
"icon_repository_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["icon_repository_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1065,12 +978,8 @@
"name": "integrationGroupPermissions_integration_id_integration_id_fk",
"tableFrom": "integrationGroupPermissions",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1078,23 +987,15 @@
"name": "integrationGroupPermissions_group_id_group_id_fk",
"tableFrom": "integrationGroupPermissions",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"integrationGroupPermissions_integration_id_group_id_permission_pk": {
"columns": [
"integration_id",
"group_id",
"permission"
],
"columns": ["integration_id", "group_id", "permission"],
"name": "integrationGroupPermissions_integration_id_group_id_permission_pk"
}
},
@@ -1125,12 +1026,8 @@
"name": "integration_item_item_id_item_id_fk",
"tableFrom": "integration_item",
"tableTo": "item",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["item_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1138,22 +1035,15 @@
"name": "integration_item_integration_id_integration_id_fk",
"tableFrom": "integration_item",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"integration_item_item_id_integration_id_pk": {
"columns": [
"item_id",
"integration_id"
],
"columns": ["item_id", "integration_id"],
"name": "integration_item_item_id_integration_id_pk"
}
},
@@ -1195,16 +1085,12 @@
"indexes": {
"integration_secret__kind_idx": {
"name": "integration_secret__kind_idx",
"columns": [
"kind"
],
"columns": ["kind"],
"isUnique": false
},
"integration_secret__updated_at_idx": {
"name": "integration_secret__updated_at_idx",
"columns": [
"updated_at"
],
"columns": ["updated_at"],
"isUnique": false
}
},
@@ -1213,22 +1099,15 @@
"name": "integrationSecret_integration_id_integration_id_fk",
"tableFrom": "integrationSecret",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"integrationSecret_integration_id_kind_pk": {
"columns": [
"integration_id",
"kind"
],
"columns": ["integration_id", "kind"],
"name": "integrationSecret_integration_id_kind_pk"
}
},
@@ -1266,12 +1145,8 @@
"name": "integrationUserPermission_integration_id_integration_id_fk",
"tableFrom": "integrationUserPermission",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1279,23 +1154,15 @@
"name": "integrationUserPermission_user_id_user_id_fk",
"tableFrom": "integrationUserPermission",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"integrationUserPermission_integration_id_user_id_permission_pk": {
"columns": [
"integration_id",
"user_id",
"permission"
],
"columns": ["integration_id", "user_id", "permission"],
"name": "integrationUserPermission_integration_id_user_id_permission_pk"
}
},
@@ -1344,9 +1211,7 @@
"indexes": {
"integration__kind_idx": {
"name": "integration__kind_idx",
"columns": [
"kind"
],
"columns": ["kind"],
"isUnique": false
}
},
@@ -1355,12 +1220,8 @@
"name": "integration_app_id_app_id_fk",
"tableFrom": "integration",
"tableTo": "app",
"columnsFrom": [
"app_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["app_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -1404,9 +1265,7 @@
"indexes": {
"invite_token_unique": {
"name": "invite_token_unique",
"columns": [
"token"
],
"columns": ["token"],
"isUnique": true
}
},
@@ -1415,12 +1274,8 @@
"name": "invite_creator_id_user_id_fk",
"tableFrom": "invite",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1488,12 +1343,8 @@
"name": "item_layout_item_id_item_id_fk",
"tableFrom": "item_layout",
"tableTo": "item",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["item_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1501,12 +1352,8 @@
"name": "item_layout_section_id_section_id_fk",
"tableFrom": "item_layout",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1514,23 +1361,15 @@
"name": "item_layout_layout_id_layout_id_fk",
"tableFrom": "item_layout",
"tableTo": "layout",
"columnsFrom": [
"layout_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["layout_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"item_layout_item_id_section_id_layout_id_pk": {
"columns": [
"item_id",
"section_id",
"layout_id"
],
"columns": ["item_id", "section_id", "layout_id"],
"name": "item_layout_item_id_section_id_layout_id_pk"
}
},
@@ -1584,12 +1423,8 @@
"name": "item_board_id_board_id_fk",
"tableFrom": "item",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1644,12 +1479,8 @@
"name": "layout_board_id_board_id_fk",
"tableFrom": "layout",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1718,12 +1549,8 @@
"name": "media_creator_id_user_id_fk",
"tableFrom": "media",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -1827,9 +1654,7 @@
"indexes": {
"search_engine_short_unique": {
"name": "search_engine_short_unique",
"columns": [
"short"
],
"columns": ["short"],
"isUnique": true
}
},
@@ -1838,12 +1663,8 @@
"name": "search_engine_integration_id_integration_id_fk",
"tableFrom": "search_engine",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1884,12 +1705,8 @@
"name": "section_collapse_state_user_id_user_id_fk",
"tableFrom": "section_collapse_state",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1897,22 +1714,15 @@
"name": "section_collapse_state_section_id_section_id_fk",
"tableFrom": "section_collapse_state",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"section_collapse_state_user_id_section_id_pk": {
"columns": [
"user_id",
"section_id"
],
"columns": ["user_id", "section_id"],
"name": "section_collapse_state_user_id_section_id_pk"
}
},
@@ -1978,12 +1788,8 @@
"name": "section_layout_section_id_section_id_fk",
"tableFrom": "section_layout",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1991,12 +1797,8 @@
"name": "section_layout_layout_id_layout_id_fk",
"tableFrom": "section_layout",
"tableTo": "layout",
"columnsFrom": [
"layout_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["layout_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -2004,22 +1806,15 @@
"name": "section_layout_parent_section_id_section_id_fk",
"tableFrom": "section_layout",
"tableTo": "section",
"columnsFrom": [
"parent_section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["parent_section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"section_layout_section_id_layout_id_pk": {
"columns": [
"section_id",
"layout_id"
],
"columns": ["section_id", "layout_id"],
"name": "section_layout_section_id_layout_id_pk"
}
},
@@ -2086,12 +1881,8 @@
"name": "section_board_id_board_id_fk",
"tableFrom": "section",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -2122,9 +1913,7 @@
"indexes": {
"serverSetting_settingKey_unique": {
"name": "serverSetting_settingKey_unique",
"columns": [
"setting_key"
],
"columns": ["setting_key"],
"isUnique": true
}
},
@@ -2161,9 +1950,7 @@
"indexes": {
"user_id_idx": {
"name": "user_id_idx",
"columns": [
"user_id"
],
"columns": ["user_id"],
"isUnique": false
}
},
@@ -2172,12 +1959,8 @@
"name": "session_user_id_user_id_fk",
"tableFrom": "session",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -2215,10 +1998,7 @@
"foreignKeys": {},
"compositePrimaryKeys": {
"trusted_certificate_hostname_hostname_thumbprint_pk": {
"columns": [
"hostname",
"thumbprint"
],
"columns": ["hostname", "thumbprint"],
"name": "trusted_certificate_hostname_hostname_thumbprint_pk"
}
},
@@ -2362,12 +2142,8 @@
"name": "user_home_board_id_board_id_fk",
"tableFrom": "user",
"tableTo": "board",
"columnsFrom": [
"home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -2375,12 +2151,8 @@
"name": "user_mobile_home_board_id_board_id_fk",
"tableFrom": "user",
"tableTo": "board",
"columnsFrom": [
"mobile_home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["mobile_home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -2388,12 +2160,8 @@
"name": "user_default_search_engine_id_search_engine_id_fk",
"tableFrom": "user",
"tableTo": "search_engine",
"columnsFrom": [
"default_search_engine_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["default_search_engine_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -2431,10 +2199,7 @@
"foreignKeys": {},
"compositePrimaryKeys": {
"verificationToken_identifier_token_pk": {
"columns": [
"identifier",
"token"
],
"columns": ["identifier", "token"],
"name": "verificationToken_identifier_token_pk"
}
},
@@ -88,9 +88,7 @@
"indexes": {
"userId_idx": {
"name": "userId_idx",
"columns": [
"user_id"
],
"columns": ["user_id"],
"isUnique": false
}
},
@@ -99,22 +97,15 @@
"name": "account_user_id_user_id_fk",
"tableFrom": "account",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"account_provider_provider_account_id_pk": {
"columns": [
"provider",
"provider_account_id"
],
"columns": ["provider", "provider_account_id"],
"name": "account_provider_provider_account_id_pk"
}
},
@@ -152,12 +143,8 @@
"name": "apiKey_user_id_user_id_fk",
"tableFrom": "apiKey",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -249,12 +236,8 @@
"name": "boardGroupPermission_board_id_board_id_fk",
"tableFrom": "boardGroupPermission",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -262,23 +245,15 @@
"name": "boardGroupPermission_group_id_group_id_fk",
"tableFrom": "boardGroupPermission",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"boardGroupPermission_board_id_group_id_permission_pk": {
"columns": [
"board_id",
"group_id",
"permission"
],
"columns": ["board_id", "group_id", "permission"],
"name": "boardGroupPermission_board_id_group_id_permission_pk"
}
},
@@ -316,12 +291,8 @@
"name": "boardUserPermission_board_id_board_id_fk",
"tableFrom": "boardUserPermission",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -329,23 +300,15 @@
"name": "boardUserPermission_user_id_user_id_fk",
"tableFrom": "boardUserPermission",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"boardUserPermission_board_id_user_id_permission_pk": {
"columns": [
"board_id",
"user_id",
"permission"
],
"columns": ["board_id", "user_id", "permission"],
"name": "boardUserPermission_board_id_user_id_permission_pk"
}
},
@@ -501,9 +464,7 @@
"indexes": {
"board_name_unique": {
"name": "board_name_unique",
"columns": [
"name"
],
"columns": ["name"],
"isUnique": true
}
},
@@ -512,12 +473,8 @@
"name": "board_creator_id_user_id_fk",
"tableFrom": "board",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -680,12 +637,8 @@
"name": "custom_widget_definition_creator_id_user_id_fk",
"tableFrom": "custom_widget_definition",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -732,22 +685,15 @@
"name": "custom_widget_secret_definition_id_custom_widget_definition_id_fk",
"tableFrom": "custom_widget_secret",
"tableTo": "custom_widget_definition",
"columnsFrom": [
"definition_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["definition_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"custom_widget_secret_definition_id_kind_pk": {
"columns": [
"definition_id",
"kind"
],
"columns": ["definition_id", "kind"],
"name": "custom_widget_secret_definition_id_kind_pk"
}
},
@@ -778,12 +724,8 @@
"name": "groupMember_group_id_group_id_fk",
"tableFrom": "groupMember",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -791,22 +733,15 @@
"name": "groupMember_user_id_user_id_fk",
"tableFrom": "groupMember",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"groupMember_group_id_user_id_pk": {
"columns": [
"group_id",
"user_id"
],
"columns": ["group_id", "user_id"],
"name": "groupMember_group_id_user_id_pk"
}
},
@@ -837,12 +772,8 @@
"name": "groupPermission_group_id_group_id_fk",
"tableFrom": "groupPermission",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -900,9 +831,7 @@
"indexes": {
"group_name_unique": {
"name": "group_name_unique",
"columns": [
"name"
],
"columns": ["name"],
"isUnique": true
}
},
@@ -911,12 +840,8 @@
"name": "group_owner_id_user_id_fk",
"tableFrom": "group",
"tableTo": "user",
"columnsFrom": [
"owner_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["owner_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -924,12 +849,8 @@
"name": "group_home_board_id_board_id_fk",
"tableFrom": "group",
"tableTo": "board",
"columnsFrom": [
"home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -937,12 +858,8 @@
"name": "group_mobile_home_board_id_board_id_fk",
"tableFrom": "group",
"tableTo": "board",
"columnsFrom": [
"mobile_home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["mobile_home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -1020,12 +937,8 @@
"name": "icon_icon_repository_id_iconRepository_id_fk",
"tableFrom": "icon",
"tableTo": "iconRepository",
"columnsFrom": [
"icon_repository_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["icon_repository_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1065,12 +978,8 @@
"name": "integrationGroupPermissions_integration_id_integration_id_fk",
"tableFrom": "integrationGroupPermissions",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1078,23 +987,15 @@
"name": "integrationGroupPermissions_group_id_group_id_fk",
"tableFrom": "integrationGroupPermissions",
"tableTo": "group",
"columnsFrom": [
"group_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["group_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"integrationGroupPermissions_integration_id_group_id_permission_pk": {
"columns": [
"integration_id",
"group_id",
"permission"
],
"columns": ["integration_id", "group_id", "permission"],
"name": "integrationGroupPermissions_integration_id_group_id_permission_pk"
}
},
@@ -1125,12 +1026,8 @@
"name": "integration_item_item_id_item_id_fk",
"tableFrom": "integration_item",
"tableTo": "item",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["item_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1138,22 +1035,15 @@
"name": "integration_item_integration_id_integration_id_fk",
"tableFrom": "integration_item",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"integration_item_item_id_integration_id_pk": {
"columns": [
"item_id",
"integration_id"
],
"columns": ["item_id", "integration_id"],
"name": "integration_item_item_id_integration_id_pk"
}
},
@@ -1195,16 +1085,12 @@
"indexes": {
"integration_secret__kind_idx": {
"name": "integration_secret__kind_idx",
"columns": [
"kind"
],
"columns": ["kind"],
"isUnique": false
},
"integration_secret__updated_at_idx": {
"name": "integration_secret__updated_at_idx",
"columns": [
"updated_at"
],
"columns": ["updated_at"],
"isUnique": false
}
},
@@ -1213,22 +1099,15 @@
"name": "integrationSecret_integration_id_integration_id_fk",
"tableFrom": "integrationSecret",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"integrationSecret_integration_id_kind_pk": {
"columns": [
"integration_id",
"kind"
],
"columns": ["integration_id", "kind"],
"name": "integrationSecret_integration_id_kind_pk"
}
},
@@ -1266,12 +1145,8 @@
"name": "integrationUserPermission_integration_id_integration_id_fk",
"tableFrom": "integrationUserPermission",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1279,23 +1154,15 @@
"name": "integrationUserPermission_user_id_user_id_fk",
"tableFrom": "integrationUserPermission",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"integrationUserPermission_integration_id_user_id_permission_pk": {
"columns": [
"integration_id",
"user_id",
"permission"
],
"columns": ["integration_id", "user_id", "permission"],
"name": "integrationUserPermission_integration_id_user_id_permission_pk"
}
},
@@ -1344,9 +1211,7 @@
"indexes": {
"integration__kind_idx": {
"name": "integration__kind_idx",
"columns": [
"kind"
],
"columns": ["kind"],
"isUnique": false
}
},
@@ -1355,12 +1220,8 @@
"name": "integration_app_id_app_id_fk",
"tableFrom": "integration",
"tableTo": "app",
"columnsFrom": [
"app_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["app_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -1404,9 +1265,7 @@
"indexes": {
"invite_token_unique": {
"name": "invite_token_unique",
"columns": [
"token"
],
"columns": ["token"],
"isUnique": true
}
},
@@ -1415,12 +1274,8 @@
"name": "invite_creator_id_user_id_fk",
"tableFrom": "invite",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1488,12 +1343,8 @@
"name": "item_layout_item_id_item_id_fk",
"tableFrom": "item_layout",
"tableTo": "item",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["item_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1501,12 +1352,8 @@
"name": "item_layout_section_id_section_id_fk",
"tableFrom": "item_layout",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1514,23 +1361,15 @@
"name": "item_layout_layout_id_layout_id_fk",
"tableFrom": "item_layout",
"tableTo": "layout",
"columnsFrom": [
"layout_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["layout_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"item_layout_item_id_section_id_layout_id_pk": {
"columns": [
"item_id",
"section_id",
"layout_id"
],
"columns": ["item_id", "section_id", "layout_id"],
"name": "item_layout_item_id_section_id_layout_id_pk"
}
},
@@ -1584,12 +1423,8 @@
"name": "item_board_id_board_id_fk",
"tableFrom": "item",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1644,12 +1479,8 @@
"name": "layout_board_id_board_id_fk",
"tableFrom": "layout",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1718,12 +1549,8 @@
"name": "media_creator_id_user_id_fk",
"tableFrom": "media",
"tableTo": "user",
"columnsFrom": [
"creator_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["creator_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -1827,9 +1654,7 @@
"indexes": {
"search_engine_short_unique": {
"name": "search_engine_short_unique",
"columns": [
"short"
],
"columns": ["short"],
"isUnique": true
}
},
@@ -1838,12 +1663,8 @@
"name": "search_engine_integration_id_integration_id_fk",
"tableFrom": "search_engine",
"tableTo": "integration",
"columnsFrom": [
"integration_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -1884,12 +1705,8 @@
"name": "section_collapse_state_user_id_user_id_fk",
"tableFrom": "section_collapse_state",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1897,22 +1714,15 @@
"name": "section_collapse_state_section_id_section_id_fk",
"tableFrom": "section_collapse_state",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"section_collapse_state_user_id_section_id_pk": {
"columns": [
"user_id",
"section_id"
],
"columns": ["user_id", "section_id"],
"name": "section_collapse_state_user_id_section_id_pk"
}
},
@@ -1978,12 +1788,8 @@
"name": "section_layout_section_id_section_id_fk",
"tableFrom": "section_layout",
"tableTo": "section",
"columnsFrom": [
"section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -1991,12 +1797,8 @@
"name": "section_layout_layout_id_layout_id_fk",
"tableFrom": "section_layout",
"tableTo": "layout",
"columnsFrom": [
"layout_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["layout_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -2004,22 +1806,15 @@
"name": "section_layout_parent_section_id_section_id_fk",
"tableFrom": "section_layout",
"tableTo": "section",
"columnsFrom": [
"parent_section_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["parent_section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"section_layout_section_id_layout_id_pk": {
"columns": [
"section_id",
"layout_id"
],
"columns": ["section_id", "layout_id"],
"name": "section_layout_section_id_layout_id_pk"
}
},
@@ -2086,12 +1881,8 @@
"name": "section_board_id_board_id_fk",
"tableFrom": "section",
"tableTo": "board",
"columnsFrom": [
"board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -2122,9 +1913,7 @@
"indexes": {
"serverSetting_settingKey_unique": {
"name": "serverSetting_settingKey_unique",
"columns": [
"setting_key"
],
"columns": ["setting_key"],
"isUnique": true
}
},
@@ -2161,9 +1950,7 @@
"indexes": {
"user_id_idx": {
"name": "user_id_idx",
"columns": [
"user_id"
],
"columns": ["user_id"],
"isUnique": false
}
},
@@ -2172,12 +1959,8 @@
"name": "session_user_id_user_id_fk",
"tableFrom": "session",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -2215,10 +1998,7 @@
"foreignKeys": {},
"compositePrimaryKeys": {
"trusted_certificate_hostname_hostname_thumbprint_pk": {
"columns": [
"hostname",
"thumbprint"
],
"columns": ["hostname", "thumbprint"],
"name": "trusted_certificate_hostname_hostname_thumbprint_pk"
}
},
@@ -2362,12 +2142,8 @@
"name": "user_home_board_id_board_id_fk",
"tableFrom": "user",
"tableTo": "board",
"columnsFrom": [
"home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -2375,12 +2151,8 @@
"name": "user_mobile_home_board_id_board_id_fk",
"tableFrom": "user",
"tableTo": "board",
"columnsFrom": [
"mobile_home_board_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["mobile_home_board_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
},
@@ -2388,12 +2160,8 @@
"name": "user_default_search_engine_id_search_engine_id_fk",
"tableFrom": "user",
"tableTo": "search_engine",
"columnsFrom": [
"default_search_engine_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["default_search_engine_id"],
"columnsTo": ["id"],
"onDelete": "set null",
"onUpdate": "no action"
}
@@ -2431,10 +2199,7 @@
"foreignKeys": {},
"compositePrimaryKeys": {
"verificationToken_identifier_token_pk": {
"columns": [
"identifier",
"token"
],
"columns": ["identifier", "token"],
"name": "verificationToken_identifier_token_pk"
}
},
@@ -2479,22 +2244,15 @@
"name": "widget_secret_item_id_item_id_fk",
"tableFrom": "widget_secret",
"tableTo": "item",
"columnsFrom": [
"item_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["item_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"widget_secret_item_id_kind_pk": {
"columns": [
"item_id",
"kind"
],
"columns": ["item_id", "kind"],
"name": "widget_secret_item_id_kind_pk"
}
},
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -536,7 +536,7 @@ export const assistantMessages = pgTable(
.references(() => assistantThreads.id, { onDelete: "cascade" }),
parentId: varchar({ length: 128 }),
format: varchar({ length: 64 }).notNull().default("ai-sdk/v6"),
content: text().default(emptySuperJSON).notNull(),
content: text().notNull(),
createdAt: timestamp().notNull().defaultNow(),
},
(message) => ({
+1 -1
View File
@@ -527,7 +527,7 @@ export const assistantMessages = sqliteTable(
.references(() => assistantThreads.id, { onDelete: "cascade" }),
parentId: text(),
format: text().notNull().default("ai-sdk/v6"),
content: text().default(emptySuperJSON).notNull(),
content: text().notNull(),
createdAt: int({ mode: "timestamp" })
.notNull()
.default(sql`(unixepoch())`),
@@ -97,8 +97,8 @@ export class PlexIntegration extends Integration implements IMediaServerIntegrat
const isAudioDirect = isStreamDirect(transcodeElement?.$.audioDecision);
const containerChanged = Boolean(
transcodeElement?.$.container &&
mediaInfoElement?.$.container &&
transcodeElement.$.container !== mediaInfoElement.$.container,
mediaInfoElement?.$.container &&
transcodeElement.$.container !== mediaInfoElement.$.container,
);
const bitrateKbps =
parseOptionalNumber(sessionElement?.$.bandwidth) ?? parseOptionalNumber(mediaInfoElement?.$.bitrate);
+254 -488
View File
@@ -688,211 +688,6 @@
"add": ""
}
},
"customWidget": {
"page": {
"list": {
"title": "",
"noResults": "",
"loading": ""
},
"create": {
"title": "",
"subtitle": ""
},
"edit": {
"title": ""
}
},
"action": {
"create": "",
"import": "",
"save": "",
"delete": "",
"deleteConfirm": "",
"export": "",
"addMapping": "",
"addColumn": "",
"edit": "",
"removeMapping": "",
"removeColumn": "",
"addItem": "",
"removeItem": "",
"addBar": "",
"duplicate": "",
"copyAiPrompt": "",
"enable": "",
"disable": "",
"menu": ""
},
"field": {
"name": "",
"description": "",
"iconUrl": "",
"url": "",
"authType": "",
"headerName": "",
"method": "",
"requestBody": "",
"displayType": "",
"jsonPath": "",
"jsonPathHint": "",
"label": "",
"unit": "",
"mappings": "",
"tablePath": "",
"tablePathHint": "",
"columns": "",
"header": "",
"items": "",
"gridColumns": "",
"cardStyle": "",
"bars": "",
"valuePath": "",
"maxPath": "",
"showPercentage": "",
"barSize": "",
"goodValues": "",
"dotSize": "",
"valueSize": "",
"labelPosition": "",
"kvLayout": "",
"striped": "",
"compact": "",
"maxHeight": "",
"color": "",
"buttonLabel": "",
"buttonColor": "",
"confirmText": "",
"confirmTextHint": "",
"successMessage": "",
"successMessageHint": "",
"enabled": "",
"template": {
"label": "",
"description": ""
}
},
"placeholder": {
"exampleLabel": "",
"exampleLabelShort": "",
"exampleHeader": "",
"exampleUnit": "",
"iconUrl": "",
"url": "",
"headerName": "",
"jsonPath": "",
"tablePath": "",
"columnJsonPath": "",
"valuePath": "",
"maxPath": "",
"goodValues": "",
"color": ""
},
"cardStyleOption": {
"filled": "",
"outline": "",
"subtle": ""
},
"layoutOption": {
"list": "",
"grid": ""
},
"sizeOption": {
"sm": "",
"md": "",
"lg": "",
"xl": ""
},
"labelPositionOption": {
"above": "",
"below": ""
},
"fieldset": {
"general": "",
"connection": "",
"display": ""
},
"displayTypeDescription": {
"singleValue": "",
"keyValue": "",
"table": "",
"statGrid": "",
"progressBars": "",
"statusIndicator": "",
"countGrid": "",
"raw": "",
"actionButton": "",
"customJsx": ""
},
"method": {
"GET": "",
"POST": "",
"PUT": "",
"DELETE": "",
"PATCH": ""
},
"authType": {
"none": "",
"bearer": "",
"basic": "",
"apiKeyHeader": "",
"apiKeyQuery": ""
},
"displayType": {
"singleValue": "",
"keyValue": "",
"table": "",
"statGrid": "",
"progressBars": "",
"statusIndicator": "",
"countGrid": "",
"raw": "",
"actionButton": "",
"customJsx": ""
},
"secret": {
"apiKey": "",
"username": "",
"password": "",
"savedPlaceholder": ""
},
"preview": {
"title": "",
"test": "",
"hint": "",
"rawResponse": ""
},
"notification": {
"created": "",
"updated": "",
"deleted": "",
"imported": "",
"aiPromptCopied": "",
"aiPromptDescription": "",
"aiPromptCopy": "",
"aiPromptNoResponse": "",
"aiPromptCopyError": "",
"createError": "",
"updateError": "",
"importError": "",
"exportError": "",
"duplicated": "",
"duplicateError": "",
"toggleError": "",
"deleteError": "",
"previewError": "",
"executed": "",
"executeError": ""
},
"table": {
"name": "",
"url": "",
"display": ""
},
"widget": {
"disabled": ""
}
},
"integration": {
"page": {
"list": {
@@ -2828,193 +2623,6 @@
"internalServerError": ""
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": {
"name": "",
"description": "",
@@ -3387,35 +2995,6 @@
}
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": {
"name": "Fonts RSS",
"description": "Monitoritzeu i mostreu una o més fonts RSS, ATOM o JSON genèriques",
@@ -3744,40 +3323,6 @@
"internalServerError": ""
}
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": {
"name": "",
"description": "",
@@ -3901,26 +3446,6 @@
"unhealthy": ""
}
},
"customApi": {
"name": "",
"description": "",
"option": {
"definitionId": {
"label": ""
},
"refreshInterval": {
"label": "",
"description": ""
}
},
"noDefinition": "",
"definitionNotFound": "",
"noDisplayOutput": "",
"executeConfirm": "",
"executing": "",
"executeSuccess": "",
"executeFailed": ""
},
"beszelSystemTable": {
"name": "",
"description": "",
@@ -4171,6 +3696,256 @@
"subtitle": ""
}
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
}
},
"widgetPreview": {
@@ -4551,11 +4326,11 @@
},
"navbar": {
"items": {
"workshop": "Workshop",
"home": "Inici",
"boards": "Taulers",
"apps": "Aplicacions",
"integrations": "Integracions",
"customWidgets": "",
"searchEngies": "Motors de cerca",
"medias": "Multimèdia",
"users": {
@@ -5694,6 +5469,9 @@
},
"navigationStructure": {
"manage": {
"workshop": {
"label": "Workshop"
},
"label": "Gestiona",
"boards": {
"label": "Taulers"
@@ -5728,18 +5506,6 @@
"label": "Edita"
}
},
"custom-widgets": {
"label": "",
"new": {
"label": ""
},
"edit": {
"label": "",
"flow": {
"label": ""
}
}
},
"users": {
"label": "Usuaris",
"create": {
+254 -488
View File
@@ -688,211 +688,6 @@
"add": "Přidat aplikaci"
}
},
"customWidget": {
"page": {
"list": {
"title": "",
"noResults": "",
"loading": "Načítání..."
},
"create": {
"title": "",
"subtitle": ""
},
"edit": {
"title": ""
}
},
"action": {
"create": "Vytvořit",
"import": "Import",
"save": "Uložit",
"delete": "",
"deleteConfirm": "",
"export": "Export",
"addMapping": "",
"addColumn": "",
"edit": "Upravit",
"removeMapping": "",
"removeColumn": "",
"addItem": "Přidat položku",
"removeItem": "Odebrat položku",
"addBar": "Přidat lištu",
"duplicate": "",
"copyAiPrompt": "",
"enable": "Povolit",
"disable": "Zakázat",
"menu": "Akce"
},
"field": {
"name": "Název",
"description": "Popis",
"iconUrl": "URL ikony",
"url": "URL",
"authType": "Typ ověření",
"headerName": "",
"method": "Metoda",
"requestBody": "",
"displayType": "",
"jsonPath": "",
"jsonPathHint": "",
"label": "",
"unit": "",
"mappings": "",
"tablePath": "",
"tablePathHint": "",
"columns": "",
"header": "",
"items": "",
"gridColumns": "",
"cardStyle": "",
"bars": "",
"valuePath": "",
"maxPath": "",
"showPercentage": "",
"barSize": "",
"goodValues": "",
"dotSize": "",
"valueSize": "",
"labelPosition": "",
"kvLayout": "",
"striped": "",
"compact": "",
"maxHeight": "",
"color": "",
"buttonLabel": "",
"buttonColor": "",
"confirmText": "",
"confirmTextHint": "",
"successMessage": "",
"successMessageHint": "",
"enabled": "",
"template": {
"label": "",
"description": ""
}
},
"placeholder": {
"exampleLabel": "Teplota CPU",
"exampleLabelShort": "Teplota CPU",
"exampleHeader": "Název",
"exampleUnit": "°C",
"iconUrl": "https://...",
"url": "https://api.example.com/api/v1/status",
"headerName": "X-API klíč",
"jsonPath": "$.data.value",
"tablePath": "$.data.items",
"columnJsonPath": "$.jméno",
"valuePath": "$.data.used",
"maxPath": "$.data.total",
"goodValues": "",
"color": ""
},
"cardStyleOption": {
"filled": "",
"outline": "",
"subtle": ""
},
"layoutOption": {
"list": "",
"grid": ""
},
"sizeOption": {
"sm": "Malé",
"md": "Střední",
"lg": "Velké",
"xl": "Extra velké"
},
"labelPositionOption": {
"above": "Nad",
"below": "Pod"
},
"fieldset": {
"general": "Obecné",
"connection": "API propojení",
"display": ""
},
"displayTypeDescription": {
"singleValue": "",
"keyValue": "",
"table": "",
"statGrid": "",
"progressBars": "",
"statusIndicator": "",
"countGrid": "",
"raw": "",
"actionButton": "",
"customJsx": ""
},
"method": {
"GET": "GET",
"POST": "POST",
"PUT": "PUT",
"DELETE": "",
"PATCH": ""
},
"authType": {
"none": "",
"bearer": "",
"basic": "",
"apiKeyHeader": "Klíč API (záhlaví)",
"apiKeyQuery": "Klíč API (dotazy)"
},
"displayType": {
"singleValue": "",
"keyValue": "",
"table": "",
"statGrid": "",
"progressBars": "",
"statusIndicator": "",
"countGrid": "",
"raw": "",
"actionButton": "",
"customJsx": ""
},
"secret": {
"apiKey": "",
"username": "Uživatelské jméno",
"password": "Heslo",
"savedPlaceholder": "••••••• (uloženo, ponechte prázdné pro zachování)"
},
"preview": {
"title": "Náhled",
"test": "Test",
"hint": "",
"rawResponse": ""
},
"notification": {
"created": "",
"updated": "",
"deleted": "",
"imported": "",
"aiPromptCopied": "",
"aiPromptDescription": "",
"aiPromptCopy": "",
"aiPromptNoResponse": "",
"aiPromptCopyError": "",
"createError": "",
"updateError": "",
"importError": "",
"exportError": "",
"duplicated": "",
"duplicateError": "",
"toggleError": "",
"deleteError": "",
"previewError": "",
"executed": "",
"executeError": ""
},
"table": {
"name": "",
"url": "URL",
"display": ""
},
"widget": {
"disabled": ""
}
},
"integration": {
"page": {
"list": {
@@ -2828,193 +2623,6 @@
"internalServerError": ""
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": {
"name": "",
"description": "",
@@ -3387,35 +2995,6 @@
}
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": {
"name": "",
"description": "",
@@ -3744,40 +3323,6 @@
"internalServerError": ""
}
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": {
"name": "",
"description": "",
@@ -3901,26 +3446,6 @@
"unhealthy": ""
}
},
"customApi": {
"name": "",
"description": "",
"option": {
"definitionId": {
"label": ""
},
"refreshInterval": {
"label": "",
"description": ""
}
},
"noDefinition": "",
"definitionNotFound": "",
"noDisplayOutput": "",
"executeConfirm": "",
"executing": "",
"executeSuccess": "",
"executeFailed": ""
},
"beszelSystemTable": {
"name": "Systémy Beszel (tabulka)",
"description": "Tabulkový přehled všech monitorovaných systémů Beszel s řaditelnými sloupci a indikátory stavu",
@@ -4171,6 +3696,256 @@
"subtitle": ""
}
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
}
},
"widgetPreview": {
@@ -4551,11 +4326,11 @@
},
"navbar": {
"items": {
"workshop": "Workshop",
"home": "Domovská stránka",
"boards": "Plochy",
"apps": "Aplikace",
"integrations": "",
"customWidgets": "",
"searchEngies": "",
"medias": "",
"users": {
@@ -5694,6 +5469,9 @@
},
"navigationStructure": {
"manage": {
"workshop": {
"label": "Workshop"
},
"label": "Spravovat",
"boards": {
"label": "Plochy"
@@ -5728,18 +5506,6 @@
"label": "Upravit"
}
},
"custom-widgets": {
"label": "",
"new": {
"label": ""
},
"edit": {
"label": "",
"flow": {
"label": ""
}
}
},
"users": {
"label": "Uživatelé",
"create": {
+254 -488
View File
@@ -688,211 +688,6 @@
"add": ""
}
},
"customWidget": {
"page": {
"list": {
"title": "Προσαρμοσμένα Widgets",
"noResults": "Δεν υπάρχουν ακόμα προσαρμοσμένα widgets. Δημιουργήστε το πρώτο σας!",
"loading": "Φόρτωση..."
},
"create": {
"title": "Δημιουργία Προσαρμοσμένου Widget",
"subtitle": "Ορίστε μια διεύθυνση URL API, πιστοποίηση και τον τρόπο εμφάνισης των δεδομένων απόκρισης."
},
"edit": {
"title": "Επεξεργασία Προσαρμοσμένου Widget"
}
},
"action": {
"create": "Δημιουργία",
"import": "Εισαγωγή",
"save": "Αποθήκευση",
"delete": "Διαγραφή Προσαρμοσμένου Widget",
"deleteConfirm": "Είστε βέβαιοι ότι θέλετε να διαγράψετε το \"{name}\"; Αυτή η ενέργεια δεν μπορεί να αναιρεθεί.",
"export": "Εξαγωγή",
"addMapping": "Προσθήκη Αντιστοίχισης",
"addColumn": "Προσθήκη Στήλης",
"edit": "Επεξεργασία",
"removeMapping": "Αφαίρεση αντιστοίχισης",
"removeColumn": "Αφαίρεση στήλης",
"addItem": "Προσθήκη Στοιχείου",
"removeItem": "Αφαίρεση στοιχείου",
"addBar": "Προσθήκη Μπάρας",
"duplicate": "Αντιγραφή",
"copyAiPrompt": "Αντιγραφή προτροπής AI",
"enable": "Ενεργοποίηση",
"disable": "Απενεργοποίηση",
"menu": "Ενέργειες"
},
"field": {
"name": "Όνομα",
"description": "Περιγραφή",
"iconUrl": "URL Εικονιδίου",
"url": "URL",
"authType": "Τύπος Πιστοποίησης",
"headerName": "Όνομα Παραμέτρου Κεφαλίδας/Ερωτήματος",
"method": "Μέθοδος",
"requestBody": "Σώμα Αιτήματος",
"displayType": "Τύπος Εμφάνισης",
"jsonPath": "Διαδρομή JSON",
"jsonPathHint": "Χρησιμοποιήστε σύνταξη JSONPath για εξαγωγή τιμών, π.χ. $.data.temperature ή $.items[0].name",
"label": "Ετικέτα",
"unit": "Μονάδα",
"mappings": "Αντιστοιχίσεις",
"tablePath": "Διαδρομή JSON Πίνακα",
"tablePathHint": "Διαδρομή προς τον πίνακα στην απόκριση, π.χ. $.data.items",
"columns": "Στήλες",
"header": "Κεφαλίδα",
"items": "Στοιχεία",
"gridColumns": "Στήλες Πλέγματος",
"cardStyle": "Στυλ Κάρτας",
"bars": "Μπάρες",
"valuePath": "Διαδρομή JSON Τιμής",
"maxPath": "Διαδρομή JSON Μέγιστης Τιμής",
"showPercentage": "Εμφάνιση Ποσοστού",
"barSize": "Μέγεθος Μπάρας",
"goodValues": "Καλές Τιμές (διαχωρισμένες με κόμμα)",
"dotSize": "Μέγεθος Κουκκίδας",
"valueSize": "Μέγεθος Τιμής",
"labelPosition": "Θέση Ετικέτας",
"kvLayout": "Διάταξη",
"striped": "Ριγωτές Γραμμές",
"compact": "Συμπαγής Λειτουργία",
"maxHeight": "Μέγιστο Ύψος (px)",
"color": "Χρώμα",
"buttonLabel": "",
"buttonColor": "",
"confirmText": "",
"confirmTextHint": "",
"successMessage": "",
"successMessageHint": "",
"enabled": "",
"template": {
"label": "",
"description": ""
}
},
"placeholder": {
"exampleLabel": "",
"exampleLabelShort": "",
"exampleHeader": "",
"exampleUnit": "",
"iconUrl": "",
"url": "",
"headerName": "",
"jsonPath": "",
"tablePath": "",
"columnJsonPath": "",
"valuePath": "",
"maxPath": "",
"goodValues": "",
"color": ""
},
"cardStyleOption": {
"filled": "",
"outline": "",
"subtle": ""
},
"layoutOption": {
"list": "",
"grid": ""
},
"sizeOption": {
"sm": "",
"md": "",
"lg": "",
"xl": ""
},
"labelPositionOption": {
"above": "",
"below": ""
},
"fieldset": {
"general": "",
"connection": "",
"display": ""
},
"displayTypeDescription": {
"singleValue": "",
"keyValue": "",
"table": "",
"statGrid": "",
"progressBars": "",
"statusIndicator": "",
"countGrid": "",
"raw": "",
"actionButton": "",
"customJsx": ""
},
"method": {
"GET": "",
"POST": "",
"PUT": "",
"DELETE": "",
"PATCH": ""
},
"authType": {
"none": "",
"bearer": "",
"basic": "",
"apiKeyHeader": "",
"apiKeyQuery": ""
},
"displayType": {
"singleValue": "",
"keyValue": "",
"table": "",
"statGrid": "",
"progressBars": "",
"statusIndicator": "",
"countGrid": "",
"raw": "",
"actionButton": "",
"customJsx": ""
},
"secret": {
"apiKey": "",
"username": "",
"password": "",
"savedPlaceholder": ""
},
"preview": {
"title": "",
"test": "",
"hint": "",
"rawResponse": ""
},
"notification": {
"created": "",
"updated": "",
"deleted": "",
"imported": "",
"aiPromptCopied": "",
"aiPromptDescription": "",
"aiPromptCopy": "",
"aiPromptNoResponse": "",
"aiPromptCopyError": "",
"createError": "",
"updateError": "",
"importError": "",
"exportError": "",
"duplicated": "",
"duplicateError": "",
"toggleError": "",
"deleteError": "",
"previewError": "",
"executed": "",
"executeError": ""
},
"table": {
"name": "",
"url": "",
"display": ""
},
"widget": {
"disabled": ""
}
},
"integration": {
"page": {
"list": {
@@ -2828,193 +2623,6 @@
"internalServerError": "Αποτυχία λήψης δεδομένων Paperless-ngx"
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": {
"name": "",
"description": "",
@@ -3387,35 +2995,6 @@
}
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": {
"name": "",
"description": "",
@@ -3744,40 +3323,6 @@
"internalServerError": "Αποτυχία λήψης δεδομένων διαθεσιμότητας"
}
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": {
"name": "Στατιστικά Ήχου",
"description": "Στατιστικά βιβλιοθήκης και αναπαραγωγής από Navidrome ή Audiobookshelf",
@@ -3901,26 +3446,6 @@
"unhealthy": ""
}
},
"customApi": {
"name": "",
"description": "",
"option": {
"definitionId": {
"label": ""
},
"refreshInterval": {
"label": "",
"description": ""
}
},
"noDefinition": "",
"definitionNotFound": "",
"noDisplayOutput": "",
"executeConfirm": "",
"executing": "",
"executeSuccess": "",
"executeFailed": ""
},
"beszelSystemTable": {
"name": "Beszel Συστήματα (Πίνακας)",
"description": "Προβολή πίνακα όλων των συστημάτων που παρακολουθούνται από το Beszel με ταξινομήσιμες στήλες και δείκτες κατάστασης",
@@ -4171,6 +3696,256 @@
"subtitle": "Κίνηση δικτύου των docker containers"
}
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
}
},
"widgetPreview": {
@@ -4551,11 +4326,11 @@
},
"navbar": {
"items": {
"workshop": "Workshop",
"home": "Αρχική",
"boards": "Πίνακες",
"apps": "Εφαρμογές",
"integrations": "",
"customWidgets": "",
"searchEngies": "",
"medias": "",
"users": {
@@ -5694,6 +5469,9 @@
},
"navigationStructure": {
"manage": {
"workshop": {
"label": "Workshop"
},
"label": "Διαχείριση",
"boards": {
"label": "Πίνακες"
@@ -5728,18 +5506,6 @@
"label": "Επεξεργασία"
}
},
"custom-widgets": {
"label": "",
"new": {
"label": ""
},
"edit": {
"label": "",
"flow": {
"label": ""
}
}
},
"users": {
"label": "Χρήστες",
"create": {
+74 -6
View File
@@ -2680,6 +2680,12 @@
"noProjectSelected": "No project selected",
"runnerStatus": "Runner: {status}",
"updatedAt": "Updated {date}",
"projectId": "Project: {id}",
"sessionReceived": "Session received: {value}",
"sessionSent": "Session sent: {value}",
"sessionId": "Session: {id}",
"startedAt": "Started {date}",
"emptyItems": "No active or recent jobs in this snapshot",
"metric": {
"running": "Running",
"completed": "Done",
@@ -3082,6 +3088,7 @@
},
"advanced": {
"entityId": "Entity ID: {id}",
"lastChanged": "Changed {date}",
"lastUpdated": "Updated {date}",
"attribute": {
"unit": "Unit",
@@ -3110,7 +3117,9 @@
},
"advanced": {
"lastExecuted": "Last run at {time}",
"automationId": "Automation ID: {id}"
"automationId": "Automation ID: {id}",
"ready": "Ready to run",
"noPermission": "No permission to run this automation"
},
"status": {
"running": "Running automation",
@@ -3123,6 +3132,14 @@
"stockPrice": {
"name": "Stock Price",
"description": "Displays the current stock price of a company",
"advanced": {
"currentPrice": "Current price",
"previousClose": "Previous close",
"change": "Change",
"changePercentage": "Change (%)",
"minimum": "Minimum",
"maximum": "Maximum"
},
"option": {
"stock": {
"label": "Stock symbol"
@@ -3311,6 +3328,11 @@
},
"title": "Indexer manager",
"testAll": "Test all",
"status": {
"healthy": "Healthy",
"unhealthy": "Unhealthy",
"disabled": "Disabled"
},
"error": {
"internalServerError": "Failed to fetch indexers status"
}
@@ -3368,7 +3390,10 @@
"minutes": "{count} minutes",
"used": "Used",
"available": "Available",
"lastSeen": "Last status update: {lastSeen}"
"lastSeen": "Last status update: {lastSeen}",
"updatesAvailable": "{count, plural, one {# update available} other {# updates available}}",
"rebootRequired": "Reboot required",
"rebootNotRequired": "No reboot required"
},
"memory": {},
"error": {
@@ -3487,7 +3512,13 @@
},
"server": {
"buildServer": "Build",
"resourceCounts": "{applications, plural, one {# app} other {# apps}} / {services, plural, one {# service} other {# services}}"
"resourceCounts": "{applications, plural, one {# app} other {# apps}} / {services, plural, one {# service} other {# services}}",
"reachability": "Reachability",
"usability": "Usability"
},
"source": {
"url": "Source: {url}",
"unavailable": "{source}: unavailable"
},
"instances": {
"title": "Instances"
@@ -3506,7 +3537,11 @@
"restarting": "Restarting",
"unknown": "Unknown",
"online": "Online",
"offline": "Offline"
"offline": "Offline",
"reachable": "Reachable",
"unreachable": "Unreachable",
"usable": "Usable",
"unusable": "Unusable"
}
},
"vpn": {
@@ -4042,6 +4077,9 @@
"movies": "Missing Movies",
"providers": "Provider Issues",
"status": "Health Issues",
"sonarrSignalr": "Sonarr SignalR",
"radarrSignalr": "Radarr SignalR",
"announcements": "Announcements",
"option": {
"showMissingEpisodes": {
"label": "Show missing episodes",
@@ -4640,6 +4678,16 @@
},
"networkControllerSummary": {
"option": {},
"advanced": {
"updated": "Updated",
"metric": {
"latency": "Latency",
"ping": "Ping",
"uptime": "Uptime",
"users": "Users",
"guests": "Guests"
}
},
"card": {
"vpn": {
"countConnected": "{count, plural, one {# connected} other {# connected}}",
@@ -4658,6 +4706,9 @@
"description": "Displays the summary of a Network Controller (like UniFi Controller)"
},
"networkControllerStatus": {
"advanced": {
"updatedAt": "Updated {date}"
},
"card": {
"variants": {
"wired": {
@@ -4789,7 +4840,8 @@
"range": {
"twelveHours": "12h",
"oneDay": "24h",
"all": "All"
"all": "All",
"lastThirty": "Last 30"
}
},
"uptimeKuma": {
@@ -5004,7 +5056,9 @@
}
},
"status": {
"unhealthy": "Unhealthy"
"unhealthy": "Unhealthy",
"smart": "SMART",
"free": "{percentage}% free"
}
},
"customApi": {
@@ -5125,6 +5179,12 @@
},
"column": {
"system": "System",
"source": "Source",
"hostname": "Hostname",
"os": "OS",
"cpuModel": "CPU model",
"cores": "Cores",
"memoryTotal": "Memory total",
"cpu": "CPU",
"memory": "Memory",
"disk": "Disk",
@@ -5185,6 +5245,14 @@
"empty": {
"noSystems": "No systems found"
},
"metadata": {
"hostname": "Hostname",
"os": "OS",
"cpuModel": "CPU model",
"cores": "Cores",
"memoryTotal": "Memory total",
"source": "Source"
},
"metric": {
"cpu": "CPU",
"memory": "Memory",
+254 -488
View File
@@ -688,211 +688,6 @@
"add": ""
}
},
"customWidget": {
"page": {
"list": {
"title": "",
"noResults": "",
"loading": ""
},
"create": {
"title": "",
"subtitle": ""
},
"edit": {
"title": ""
}
},
"action": {
"create": "",
"import": "",
"save": "",
"delete": "",
"deleteConfirm": "",
"export": "",
"addMapping": "",
"addColumn": "",
"edit": "",
"removeMapping": "",
"removeColumn": "",
"addItem": "",
"removeItem": "",
"addBar": "",
"duplicate": "",
"copyAiPrompt": "",
"enable": "",
"disable": "",
"menu": ""
},
"field": {
"name": "",
"description": "",
"iconUrl": "",
"url": "",
"authType": "",
"headerName": "",
"method": "",
"requestBody": "",
"displayType": "",
"jsonPath": "",
"jsonPathHint": "",
"label": "",
"unit": "",
"mappings": "",
"tablePath": "",
"tablePathHint": "",
"columns": "",
"header": "",
"items": "",
"gridColumns": "",
"cardStyle": "",
"bars": "",
"valuePath": "",
"maxPath": "",
"showPercentage": "",
"barSize": "",
"goodValues": "",
"dotSize": "",
"valueSize": "",
"labelPosition": "",
"kvLayout": "",
"striped": "",
"compact": "",
"maxHeight": "",
"color": "",
"buttonLabel": "",
"buttonColor": "",
"confirmText": "",
"confirmTextHint": "",
"successMessage": "",
"successMessageHint": "",
"enabled": "",
"template": {
"label": "",
"description": ""
}
},
"placeholder": {
"exampleLabel": "",
"exampleLabelShort": "",
"exampleHeader": "",
"exampleUnit": "",
"iconUrl": "",
"url": "",
"headerName": "",
"jsonPath": "",
"tablePath": "",
"columnJsonPath": "",
"valuePath": "",
"maxPath": "",
"goodValues": "",
"color": ""
},
"cardStyleOption": {
"filled": "",
"outline": "",
"subtle": ""
},
"layoutOption": {
"list": "",
"grid": ""
},
"sizeOption": {
"sm": "",
"md": "",
"lg": "",
"xl": ""
},
"labelPositionOption": {
"above": "",
"below": ""
},
"fieldset": {
"general": "",
"connection": "",
"display": ""
},
"displayTypeDescription": {
"singleValue": "",
"keyValue": "",
"table": "",
"statGrid": "",
"progressBars": "",
"statusIndicator": "",
"countGrid": "",
"raw": "",
"actionButton": "",
"customJsx": ""
},
"method": {
"GET": "",
"POST": "",
"PUT": "",
"DELETE": "",
"PATCH": ""
},
"authType": {
"none": "",
"bearer": "",
"basic": "",
"apiKeyHeader": "",
"apiKeyQuery": ""
},
"displayType": {
"singleValue": "",
"keyValue": "",
"table": "",
"statGrid": "",
"progressBars": "",
"statusIndicator": "",
"countGrid": "",
"raw": "",
"actionButton": "",
"customJsx": ""
},
"secret": {
"apiKey": "",
"username": "",
"password": "",
"savedPlaceholder": ""
},
"preview": {
"title": "",
"test": "",
"hint": "",
"rawResponse": ""
},
"notification": {
"created": "",
"updated": "",
"deleted": "",
"imported": "",
"aiPromptCopied": "",
"aiPromptDescription": "",
"aiPromptCopy": "",
"aiPromptNoResponse": "",
"aiPromptCopyError": "",
"createError": "",
"updateError": "",
"importError": "",
"exportError": "",
"duplicated": "",
"duplicateError": "",
"toggleError": "",
"deleteError": "",
"previewError": "",
"executed": "",
"executeError": ""
},
"table": {
"name": "",
"url": "",
"display": ""
},
"widget": {
"disabled": ""
}
},
"integration": {
"page": {
"list": {
@@ -2828,193 +2623,6 @@
"internalServerError": ""
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": {
"name": "",
"description": "",
@@ -3387,35 +2995,6 @@
}
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": {
"name": "RSS-voogud",
"description": "Jälgi ja kuva üht või enamat üldist RSS-, ATOM- või JSON-voogu",
@@ -3744,40 +3323,6 @@
"internalServerError": ""
}
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": {
"name": "",
"description": "",
@@ -3901,26 +3446,6 @@
"unhealthy": ""
}
},
"customApi": {
"name": "",
"description": "",
"option": {
"definitionId": {
"label": ""
},
"refreshInterval": {
"label": "",
"description": ""
}
},
"noDefinition": "",
"definitionNotFound": "",
"noDisplayOutput": "",
"executeConfirm": "",
"executing": "",
"executeSuccess": "",
"executeFailed": ""
},
"beszelSystemTable": {
"name": "",
"description": "",
@@ -4171,6 +3696,256 @@
"subtitle": ""
}
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
}
},
"widgetPreview": {
@@ -4551,11 +4326,11 @@
},
"navbar": {
"items": {
"workshop": "Workshop",
"home": "Kodu",
"boards": "Töölauad",
"apps": "Rakendused",
"integrations": "Integratsioonid",
"customWidgets": "",
"searchEngies": "Otsingumootorid",
"medias": "Meedia",
"users": {
@@ -5694,6 +5469,9 @@
},
"navigationStructure": {
"manage": {
"workshop": {
"label": "Workshop"
},
"label": "",
"boards": {
"label": ""
@@ -5728,18 +5506,6 @@
"label": ""
}
},
"custom-widgets": {
"label": "",
"new": {
"label": ""
},
"edit": {
"label": "",
"flow": {
"label": ""
}
}
},
"users": {
"label": "",
"create": {
+254 -488
View File
@@ -688,211 +688,6 @@
"add": "Lisää sovellus"
}
},
"customWidget": {
"page": {
"list": {
"title": "Mukautetut widgetit",
"noResults": "Ei vielä mukautettuja widgettejä. Luo ensimmäinen!",
"loading": "Ladataan..."
},
"create": {
"title": "Luo mukautettu widget",
"subtitle": "Määritä API-URL, todennus ja miten vastaustiedot näytetään."
},
"edit": {
"title": "Muokkaa mukautettua widgettiä"
}
},
"action": {
"create": "Luo",
"import": "Tuo",
"save": "Tallenna",
"delete": "Poista mukautettu widget",
"deleteConfirm": "Haluatko varmasti poistaa \"{name}\"? Tätä toimintoa ei voi peruuttaa.",
"export": "Vie",
"addMapping": "Lisää kartoitus",
"addColumn": "Lisää sarake",
"edit": "Muokkaa",
"removeMapping": "Poista kartoitus",
"removeColumn": "Poista sarake",
"addItem": "Lisää kohde",
"removeItem": "Poista kohde",
"addBar": "Lisää palkki",
"duplicate": "Monista",
"copyAiPrompt": "Kopioi AI-kehoteprompt",
"enable": "Ota käyttöön",
"disable": "Poista käytöstä",
"menu": "Toiminnot"
},
"field": {
"name": "Nimi",
"description": "Kuvaus",
"iconUrl": "Kuvakkeen URL-osoite",
"url": "URL",
"authType": "Tunnistautumistyyppi",
"headerName": "Otsikko/kyselyparametrin nimi",
"method": "Menetelmä",
"requestBody": "Pyynnön runko",
"displayType": "Näyttötyyppi",
"jsonPath": "JSON-polku",
"jsonPathHint": "Käytä JSONPath-syntaksia arvojen poimimiseen, esim. $.data.temperature tai $.items[0].name",
"label": "Tunniste",
"unit": "Yksikkö",
"mappings": "Kartoitukset",
"tablePath": "Taulukon JSON-polku",
"tablePathHint": "Polku vastauksen taulukkoon, esim. $.data.items",
"columns": "Sarakkeet",
"header": "Otsikko",
"items": "Kohteet",
"gridColumns": "Ruudukon sarakkeet",
"cardStyle": "Kortin tyyli",
"bars": "Palkit",
"valuePath": "Arvon JSON-polku",
"maxPath": "Maksimiarvon JSON-polku",
"showPercentage": "Näytä prosenttiosuus",
"barSize": "Palkin koko",
"goodValues": "Hyvät arvot (pilkuin eroteltuina)",
"dotSize": "Pisteen koko",
"valueSize": "Arvon koko",
"labelPosition": "Tunnisteen sijainti",
"kvLayout": "Asettelu",
"striped": "Raidalliset rivit",
"compact": "Tiivis tila",
"maxHeight": "Maksimikorkeus (px)",
"color": "Väri",
"buttonLabel": "Painikkeen teksti",
"buttonColor": "Painikkeen väri",
"confirmText": "Vahvistusteksti",
"confirmTextHint": "Jos asetettu, vahvistusvalintaikkuna tulee esiin ennen pyynnön suorittamista",
"successMessage": "Onnistumisviesti",
"successMessageHint": "Viesti, joka näytetään onnistuneen suorituksen jälkeen",
"enabled": "Käytössä",
"template": {
"label": "JSX-mallipohja",
"description": "Mantine JSX -mallipohja. Käytä vastauskenttiä datan sidonnoilla (esim. data.name). Käytä vain sallittuja komponentteja. Kielletyt: constructor, __proto__, eval, Function, window, document."
}
},
"placeholder": {
"exampleLabel": "CPU-lämpötila",
"exampleLabelShort": "CPU-lämpö",
"exampleHeader": "Nimi",
"exampleUnit": "°C",
"iconUrl": "https://...",
"url": "https://api.example.com/api/v1/status",
"headerName": "X-API-Key",
"jsonPath": "$.data.value",
"tablePath": "$.data.items",
"columnJsonPath": "$.nimi",
"valuePath": "$.data.used",
"maxPath": "$.data.total",
"goodValues": "online, true, up",
"color": "sininen"
},
"cardStyleOption": {
"filled": "Täytetty",
"outline": "Ääriviiva",
"subtle": "Hienovarainen"
},
"layoutOption": {
"list": "Luettelo",
"grid": "Ruudukko"
},
"sizeOption": {
"sm": "Pieni",
"md": "Keskikokoinen",
"lg": "Suuri",
"xl": "Erittäin suuri"
},
"labelPositionOption": {
"above": "Yläpuolella",
"below": "Alapuolella"
},
"fieldset": {
"general": "Yleiset",
"connection": "API-yhteys",
"display": "Näyttöasetukset"
},
"displayTypeDescription": {
"singleValue": "Näytä yksi poimittu arvo tunnisteella ja yksiköllä",
"keyValue": "Näytä useita tunnisteellisia arvoja vierekkäin",
"table": "Näytä tietorivit taulukkomuodossa",
"statGrid": "Värilliset tilastokortit ruudukossa – kuten Pi-Hole- tai Speedtest-widgetit",
"progressBars": "Edistymispalkit, jotka näyttävät käyttöasteen tai valmistumisen – levylle, muistille, kiintiöille",
"statusIndicator": "Värilliset tilapisteet, jotka näyttävät online/offline- tai terveydentilan",
"countGrid": "Tiiviit numero + tunniste -laskurit tiukassa ruudukossa",
"raw": "Muotoiltu JSON-tuloste vianetsintään",
"actionButton": "Painike, joka laukaisee pyynnön napsautettaessa",
"customJsx": "Mukautettu JSX-asettelu käyttäen sallittuja Mantine-komponentteja täydellä API-tietojen sidonnalla"
},
"method": {
"GET": "GET",
"POST": "POST",
"PUT": "PUT",
"DELETE": "DELETE",
"PATCH": "PATCH"
},
"authType": {
"none": "Ei mitään",
"bearer": "Bearer-tunniste",
"basic": "Basic-todennus",
"apiKeyHeader": "API-avain (otsikko)",
"apiKeyQuery": "API-avain (kysely)"
},
"displayType": {
"singleValue": "Yksittäinen arvo",
"keyValue": "Avain-arvo",
"table": "Taulukko",
"statGrid": "Tilastoruudukko",
"progressBars": "Edistymispalkit",
"statusIndicator": "Tilan ilmaisin",
"countGrid": "Laskuriruudukko",
"raw": "Raaka JSON",
"actionButton": "Toimintopainike",
"customJsx": "Mukautettu JSX"
},
"secret": {
"apiKey": "API-avain / token",
"username": "Käyttäjätunnus",
"password": "Salasana",
"savedPlaceholder": "••••••• (tallennettu, jätä tyhjäksi säilyttääksesi)"
},
"preview": {
"title": "Esikatselu",
"test": "Testaa",
"hint": "Napsauta Testaa nähdäksesi API-vastauksen nykyisillä asetuksillasi.",
"rawResponse": "Raaka JSON-vastaus"
},
"notification": {
"created": "Widget \"{name}\" luotiin onnistuneesti.",
"updated": "Widget \"{name}\" päivitettiin onnistuneesti.",
"deleted": "Widget \"{name}\" poistettiin.",
"imported": "Widget tuotiin onnistuneesti.",
"aiPromptCopied": "AI-kehoteprompt kopioitu leikepöydälle",
"aiPromptDescription": "Kopioi valmis kehoteprompt liitettäväksi mihin tahansa AI-chatbottiin (ChatGPT, Claude, Gemini...). Se sisältää täyden widget-skeeman ja API-vastauksesi, jotta AI voi luoda sinulle tuotavissa olevan JSON-asetuksen.",
"aiPromptCopy": "Kopioi leikepöydälle",
"aiPromptNoResponse": "Vinkki: Suorita testi ensin sisällyttääksesi API-vastauksesi kehotepromptiin parempien tulosten saamiseksi.",
"aiPromptCopyError": "Kehotepromptin kopiointi leikepöydälle epäonnistui. Selaimesi ei ehkä tue tätä ominaisuutta.",
"createError": "Widgetin luonti epäonnistui. Tarkista, että API-päätepisteesi on tavoitettavissa.",
"updateError": "Widgetin päivitys epäonnistui. Muutoksiasi ei tallennettu.",
"importError": "Widgetin tuonti epäonnistui. Varmista, että tiedosto on kelvollinen mukautetun widgetin JSON-vienti.",
"exportError": "Widgetin vienti epäonnistui.",
"duplicated": "Widget \"{name}\" kopioitiin.",
"duplicateError": "Widgetin kopiointi epäonnistui.",
"toggleError": "Widgetin tilan vaihto epäonnistui.",
"deleteError": "Widgetin poisto epäonnistui.",
"previewError": "Esikatselun nouto epäonnistui. Tarkista URL ja yritä uudelleen.",
"executed": "Toiminto suoritettu onnistuneesti.",
"executeError": "Toiminto epäonnistui: {error}"
},
"table": {
"name": "Nimi",
"url": "URL",
"display": "Näyttö"
},
"widget": {
"disabled": "Tämä widget on poistettu käytöstä"
}
},
"integration": {
"page": {
"list": {
@@ -2828,193 +2623,6 @@
"internalServerError": "Paperless-ngx-tietojen haku epäonnistui"
}
},
"patchmon": {
"name": "PatchMon",
"description": "Yleiskatsaus isäntien päivitystilanteesta PatchMonista",
"title": "PatchMon-tilastot",
"totalHosts": "Isännät yhteensä",
"hostsNeedingUpdates": "Päivitystä tarvitsevat",
"securityUpdates": "Tietoturvapäivitykset",
"upToDateHosts": "Ajan tasalla olevat isännät",
"hostsWithSecurityUpdates": "Isännät, joilla on tietoturvapäivityksiä",
"recentUpdates24h": "Päivitykset (24 h)",
"totalOutdatedPackages": "Vanhentuneet paketit",
"totalRepos": "Pakettivarastot",
"osDistribution": "Käyttöjärjestelmien jakauma",
"compliance": "Päivityskattavuus",
"complianceRatio": "{upToDate} / {total}",
"lastUpdated": "Päivitetty {time}",
"option": {
"showTotalHosts": {
"label": "Näytä isännät yhteensä",
"description": "Näytä valvottujen isäntien kokonaismäärä"
},
"showHostsNeedingUpdates": {
"label": "Näytä päivitystä tarvitsevat isännät",
"description": "Näytä isännät, joilla on vähintään yksi vanhentunut paketti"
},
"showSecurityUpdates": {
"label": "Näytä tietoturvapäivitykset",
"description": "Näytä saatavilla olevien tietoturvapäivitysten kokonaismäärä"
},
"showUpToDateHosts": {
"label": "Näytä ajan tasalla olevat isännät",
"description": "Näytä isännät, joissa ei ole vanhentuneita paketteja"
},
"showHostsWithSecurityUpdates": {
"label": "Näytä isännät, joilla on tietoturvapäivityksiä",
"description": "Näytä isännät, jotka tarvitsevat tietoturvakorjauksia"
},
"showRecentUpdates24h": {
"label": "Näytä viimeaikaiset päivitykset (24 h)",
"description": "Näytä viimeisen 24 tunnin aikana asennettujen päivitysten määrä"
},
"showTotalOutdatedPackages": {
"label": "Näytä vanhentuneet paketit",
"description": "Näytä vanhentuneiden pakettien kokonaismäärä kaikissa isännissä"
},
"showTotalRepos": {
"label": "Näytä repositoriot",
"description": "Näytä valvottavien aktiivisten repositorioiden määrä"
},
"enableThresholdColors": {
"label": "Ota käyttöön kynnysarvovärit",
"description": "Väritä tilastoarvot vihreäksi, keltaiseksi tai punaiseksi vakavuusesiasetusten perusteella"
},
"useCustomThresholds": {
"label": "Edistyneet kynnysarvot",
"description": "Mukauta varoitus- ja kriittiset kynnysarvot tilastoittain käyttäen absoluuttisia määriä tai prosenttiosuutta isäntien kokonaismäärästä"
},
"thresholdMode": {
"option": {
"absolute": "Absoluuttinen määrä",
"percent": "Prosenttia isäntien kokonaismäärästä"
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "Päivityksiä tarvitsevien kynnysarvotila",
"description": "Vertaa päivitystarpeiden määrää absoluuttisena arvona tai prosenttiosuutena isäntien kokonaismäärästä"
},
"hostsNeedingUpdatesWarningAt": {
"label": "Päivitystarpeiden varoituskynnysarvo",
"description": "Muuta keltaiseksi, kun arvo saavuttaa tämän kynnysarvon"
},
"hostsNeedingUpdatesCriticalAt": {
"label": "Päivitystarpeiden kriittinen kynnysarvo",
"description": "Muuta punaiseksi, kun arvo saavuttaa tämän kynnysarvon"
},
"securityUpdatesThresholdMode": {
"label": "Tietoturvapäivitysten kynnysarvotila",
"description": "Vertaa tietoturvapäivitysten määrää absoluuttisena arvona tai prosenttiosuutena isäntien kokonaismäärästä"
},
"securityUpdatesWarningAt": {
"label": "Tietoturvapäivitysten varoituskynnysarvo",
"description": "Muuta keltaiseksi, kun arvo saavuttaa tämän kynnysarvon"
},
"securityUpdatesCriticalAt": {
"label": "Tietoturvapäivitysten kriittinen kynnysarvo",
"description": "Muuta punaiseksi, kun arvo saavuttaa tämän kynnysarvon"
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "Tietoturvapäivityksiä sisältävien isäntien kynnysarvotila",
"description": "Vertaa isäntien määrää absoluuttisena arvona tai prosenttiosuutena isäntien kokonaismäärästä"
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "Tietoturvapäivityksiä sisältävien isäntien varoituskynnysarvo",
"description": "Muuta keltaiseksi, kun arvo saavuttaa tämän kynnysarvon"
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "Tietoturvapäivityksiä sisältävien isäntien kriittinen kynnysarvo",
"description": "Muuta punaiseksi, kun arvo saavuttaa tämän kynnysarvon"
},
"upToDateHostsThresholdMode": {
"label": "Ajan tasalla olevien isäntien kynnysarvotila",
"description": "Vertaa ajan tasalla olevien isäntien määrää absoluuttisena arvona tai prosenttiosuutena isäntien kokonaismäärästä"
},
"upToDateHostsWarningAt": {
"label": "Ajan tasalla olevien isäntien varoituskynnysarvo",
"description": "Muuta keltaiseksi, kun arvo on vähintään tämä kynnysarvo, mutta alle täyden kattavuuden"
},
"upToDateHostsCriticalAt": {
"label": "Ajan tasalla olevien isäntien kriittinen kynnysarvo",
"description": "Muuta punaiseksi, kun arvo laskee tämän kynnysarvon alle"
},
"totalOutdatedPackagesThresholdMode": {
"label": "Vanhentuneiden pakettien kynnysarvotila",
"description": "Vertaa vanhentuneiden pakettien määrää absoluuttisena arvona tai prosenttiosuutena isäntien kokonaismäärästä"
},
"totalOutdatedPackagesWarningAt": {
"label": "Vanhentuneiden pakettien varoituskynnysarvo",
"description": "Muuta keltaiseksi, kun arvo saavuttaa tämän kynnysarvon"
},
"totalOutdatedPackagesCriticalAt": {
"label": "Vanhentuneiden pakettien kriittinen kynnysarvo",
"description": "Muuta punaiseksi, kun arvo saavuttaa tämän kynnysarvon"
},
"showOsDistribution": {
"label": "Näytä käyttöjärjestelmäjakauma",
"description": "Näytä erittely valvotuista isännistä käyttöjärjestelmittäin"
},
"osDistributionLimit": {
"label": "Käyttöjärjestelmäjakauman rajoitus",
"description": "Näytettävien käyttöjärjestelmien enimmäismäärä",
"option": {
"3": "3 parasta",
"5": "5 parasta",
"10": "10 parasta",
"all": "Kaikki"
}
},
"showOsVersion": {
"label": "Näytä käyttöjärjestelmän versio",
"description": "Liitä käyttöjärjestelmän versio jokaiseen jakauman nimikkeeseen, kun se on saatavilla"
},
"showComplianceHero": {
"label": "Näytä compliance-hero",
"description": "Näytä vaatimustenmukaisuusrengas, joka näyttää ajan tasalla olevien isäntien prosenttiosuuden"
},
"osDisplayMode": {
"label": "Käyttöjärjestelmän näyttötila",
"description": "Valitse, miten käyttöjärjestelmän jakelu näytetään",
"option": {
"bars": "Vaakapalkit",
"donut": "Donitsikaavio"
}
}
},
"error": {
"internalServerError": "PatchMon-tietojen nouto epäonnistui"
}
},
"bazarr": {
"name": "Bazarr",
"description": "Yleiskatsaus puuttuvista tekstityksistä ja terveystilasta Bazarr-instanssistasi",
"episodes": "Puuttuvat jaksot",
"movies": "Puuttuvat elokuvat",
"providers": "Palveluntarjoajan ongelmat",
"status": "Terveysongelmat",
"option": {
"showMissingEpisodes": {
"label": "Näytä puuttuvat jaksot",
"description": "Näytä niiden jaksojen määrä, joista puuttuu tekstitys"
},
"showMissingMovies": {
"label": "Näytä puuttuvat elokuvat",
"description": "Näytä niiden elokuvien määrä, joista puuttuu tekstitykset"
},
"showProviderIssues": {
"label": "Näytä tarjoajien ongelmat",
"description": "Näytä ongelmallisten tekstitystarjoajien määrä"
},
"showHealthIssues": {
"label": "Näytä kunto-ongelmat",
"description": "Näytä Bazarrin kunto-ongelmien määrä"
}
},
"error": {
"internalServerError": "Bazarrin tietojen nouto epäonnistui"
}
},
"immich-serverStats": {
"name": "",
"description": "",
@@ -3387,35 +2995,6 @@
}
}
},
"mediaMissing": {
"name": "Puuttuva & jonossa oleva media",
"description": "Näyttää puuttuvat ja jonossa olevat elokuvat ja jaksot Radarr:sta ja Sonarr:sta",
"option": {
"showMissing": {
"label": "Näytä puuttuvat kohteet"
},
"showQueued": {
"label": "Näytä jonossa olevat kohteet"
},
"pageSize": {
"label": "Kohteita per sivu"
}
},
"tab": {
"missing": "Puuttuvat",
"queued": "Jonossa"
},
"type": {
"movie": "Elokuva",
"episode": "Jakso"
},
"empty": {
"missing": "Ei puuttuvia kohteita",
"queued": "Ei jonossa olevia kohteita",
"noTabsEnabled": "Ota käyttöön vähintään yksi välilehti widgetin asetuksissa"
},
"timeLeft": "Jäljellä oleva aika"
},
"rssFeed": {
"name": "",
"description": "",
@@ -3744,40 +3323,6 @@
"internalServerError": "Käytettävyystietojen haku epäonnistui"
}
},
"traefik": {
"name": "Traefik",
"description": "Yleiskatsaus Traefikin reitittimistä, palveluista, middlewareista ja sisääntulopisteistä",
"option": {
"showTcp": {
"label": "Näytä TCP"
},
"showUdp": {
"label": "Näytä UDP"
},
"showEntryPoints": {
"label": "Näytä sisääntulopisteet"
}
},
"instances": "Traefik-instanssit",
"versionUnknown": "Versio tuntematon",
"summary": {
"routers": "Reitittimet",
"entryPoints": "Sisääntulopisteet"
},
"resource": {
"routers": "Reitittimet",
"services": "Palvelut",
"middlewares": "Middlewaret"
},
"status": {
"healthy": "Terve",
"errors": "{count} virhettä",
"warnings": "{count} varoitusta"
},
"error": {
"internalServerError": "Traefikin tietojen nouto epäonnistui"
}
},
"audioStats": {
"name": "Äänitilastot",
"description": "Kirjasto- ja toistotilastot Navidromesta tai Audiobookshelfistä",
@@ -3901,26 +3446,6 @@
"unhealthy": ""
}
},
"customApi": {
"name": "Mukautettu API",
"description": "Näytä dataa mistä tahansa ulkoisesta API:sta mukautetuilla asetuksilla.",
"option": {
"definitionId": {
"label": "Määritelmän tunnus"
},
"refreshInterval": {
"label": "Päivitysväli",
"description": "Kuinka usein data haetaan uudelleen API:sta (sekunteina)"
}
},
"noDefinition": "Määritelmää ei valittu",
"definitionNotFound": "Widget-määritelmää ei löydy. Se on saatettu poistaa.",
"noDisplayOutput": "Ei näyttötulostetta",
"executeConfirm": "Haluatko varmasti suorittaa tämän toiminnon?",
"executing": "Suoritetaan...",
"executeSuccess": "Toiminto suoritettu onnistuneesti",
"executeFailed": "Toiminto epäonnistui. Tarkista widgetin asetukset."
},
"beszelSystemTable": {
"name": "Beszel-järjestelmät (taulukko)",
"description": "Taulukkonäkymä kaikista Beszel-valvotuista järjestelmistä, lajiteltavilla sarakkeilla ja tilaindikaattoreilla",
@@ -4171,6 +3696,256 @@
"subtitle": "Docker-konttien verkkoliikenne"
}
}
},
"patchmon": {
"name": "PatchMon",
"description": "Yleiskatsaus isäntien päivitystilanteesta PatchMonista",
"title": "PatchMon-tilastot",
"totalHosts": "Isännät yhteensä",
"hostsNeedingUpdates": "Päivitystä tarvitsevat",
"securityUpdates": "Tietoturvapäivitykset",
"upToDateHosts": "Ajan tasalla olevat isännät",
"hostsWithSecurityUpdates": "Isännät, joilla on tietoturvapäivityksiä",
"recentUpdates24h": "Päivitykset (24 h)",
"totalOutdatedPackages": "Vanhentuneet paketit",
"totalRepos": "Pakettivarastot",
"osDistribution": "Käyttöjärjestelmien jakauma",
"compliance": "Päivityskattavuus",
"complianceRatio": "{upToDate} / {total}",
"lastUpdated": "Päivitetty {time}",
"option": {
"showTotalHosts": {
"label": "Näytä isännät yhteensä",
"description": "Näytä valvottujen isäntien kokonaismäärä"
},
"showHostsNeedingUpdates": {
"label": "Näytä päivitystä tarvitsevat isännät",
"description": "Näytä isännät, joilla on vähintään yksi vanhentunut paketti"
},
"showSecurityUpdates": {
"label": "Näytä tietoturvapäivitykset",
"description": "Näytä saatavilla olevien tietoturvapäivitysten kokonaismäärä"
},
"showUpToDateHosts": {
"label": "Näytä ajan tasalla olevat isännät",
"description": "Näytä isännät, joissa ei ole vanhentuneita paketteja"
},
"showHostsWithSecurityUpdates": {
"label": "Näytä isännät, joilla on tietoturvapäivityksiä",
"description": "Näytä isännät, jotka tarvitsevat tietoturvakorjauksia"
},
"showRecentUpdates24h": {
"label": "Näytä viimeaikaiset päivitykset (24 h)",
"description": "Näytä viimeisen 24 tunnin aikana asennettujen päivitysten määrä"
},
"showTotalOutdatedPackages": {
"label": "Näytä vanhentuneet paketit",
"description": "Näytä vanhentuneiden pakettien kokonaismäärä kaikissa isännissä"
},
"showTotalRepos": {
"label": "Näytä repositoriot",
"description": "Näytä valvottavien aktiivisten repositorioiden määrä"
},
"enableThresholdColors": {
"label": "Ota käyttöön kynnysarvovärit",
"description": "Väritä tilastoarvot vihreäksi, keltaiseksi tai punaiseksi vakavuusesiasetusten perusteella"
},
"useCustomThresholds": {
"label": "Edistyneet kynnysarvot",
"description": "Mukauta varoitus- ja kriittiset kynnysarvot tilastoittain käyttäen absoluuttisia määriä tai prosenttiosuutta isäntien kokonaismäärästä"
},
"thresholdMode": {
"option": {
"absolute": "Absoluuttinen määrä",
"percent": "Prosenttia isäntien kokonaismäärästä"
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "Päivityksiä tarvitsevien kynnysarvotila",
"description": "Vertaa päivitystarpeiden määrää absoluuttisena arvona tai prosenttiosuutena isäntien kokonaismäärästä"
},
"hostsNeedingUpdatesWarningAt": {
"label": "Päivitystarpeiden varoituskynnysarvo",
"description": "Muuta keltaiseksi, kun arvo saavuttaa tämän kynnysarvon"
},
"hostsNeedingUpdatesCriticalAt": {
"label": "Päivitystarpeiden kriittinen kynnysarvo",
"description": "Muuta punaiseksi, kun arvo saavuttaa tämän kynnysarvon"
},
"securityUpdatesThresholdMode": {
"label": "Tietoturvapäivitysten kynnysarvotila",
"description": "Vertaa tietoturvapäivitysten määrää absoluuttisena arvona tai prosenttiosuutena isäntien kokonaismäärästä"
},
"securityUpdatesWarningAt": {
"label": "Tietoturvapäivitysten varoituskynnysarvo",
"description": "Muuta keltaiseksi, kun arvo saavuttaa tämän kynnysarvon"
},
"securityUpdatesCriticalAt": {
"label": "Tietoturvapäivitysten kriittinen kynnysarvo",
"description": "Muuta punaiseksi, kun arvo saavuttaa tämän kynnysarvon"
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "Tietoturvapäivityksiä sisältävien isäntien kynnysarvotila",
"description": "Vertaa isäntien määrää absoluuttisena arvona tai prosenttiosuutena isäntien kokonaismäärästä"
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "Tietoturvapäivityksiä sisältävien isäntien varoituskynnysarvo",
"description": "Muuta keltaiseksi, kun arvo saavuttaa tämän kynnysarvon"
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "Tietoturvapäivityksiä sisältävien isäntien kriittinen kynnysarvo",
"description": "Muuta punaiseksi, kun arvo saavuttaa tämän kynnysarvon"
},
"upToDateHostsThresholdMode": {
"label": "Ajan tasalla olevien isäntien kynnysarvotila",
"description": "Vertaa ajan tasalla olevien isäntien määrää absoluuttisena arvona tai prosenttiosuutena isäntien kokonaismäärästä"
},
"upToDateHostsWarningAt": {
"label": "Ajan tasalla olevien isäntien varoituskynnysarvo",
"description": "Muuta keltaiseksi, kun arvo on vähintään tämä kynnysarvo, mutta alle täyden kattavuuden"
},
"upToDateHostsCriticalAt": {
"label": "Ajan tasalla olevien isäntien kriittinen kynnysarvo",
"description": "Muuta punaiseksi, kun arvo laskee tämän kynnysarvon alle"
},
"totalOutdatedPackagesThresholdMode": {
"label": "Vanhentuneiden pakettien kynnysarvotila",
"description": "Vertaa vanhentuneiden pakettien määrää absoluuttisena arvona tai prosenttiosuutena isäntien kokonaismäärästä"
},
"totalOutdatedPackagesWarningAt": {
"label": "Vanhentuneiden pakettien varoituskynnysarvo",
"description": "Muuta keltaiseksi, kun arvo saavuttaa tämän kynnysarvon"
},
"totalOutdatedPackagesCriticalAt": {
"label": "Vanhentuneiden pakettien kriittinen kynnysarvo",
"description": "Muuta punaiseksi, kun arvo saavuttaa tämän kynnysarvon"
},
"showOsDistribution": {
"label": "Näytä käyttöjärjestelmäjakauma",
"description": "Näytä erittely valvotuista isännistä käyttöjärjestelmittäin"
},
"osDistributionLimit": {
"label": "Käyttöjärjestelmäjakauman rajoitus",
"description": "Näytettävien käyttöjärjestelmien enimmäismäärä",
"option": {
"3": "3 parasta",
"5": "5 parasta",
"10": "10 parasta",
"all": "Kaikki"
}
},
"showOsVersion": {
"label": "Näytä käyttöjärjestelmän versio",
"description": "Liitä käyttöjärjestelmän versio jokaiseen jakauman nimikkeeseen, kun se on saatavilla"
},
"showComplianceHero": {
"label": "Näytä compliance-hero",
"description": "Näytä vaatimustenmukaisuusrengas, joka näyttää ajan tasalla olevien isäntien prosenttiosuuden"
},
"osDisplayMode": {
"label": "Käyttöjärjestelmän näyttötila",
"description": "Valitse, miten käyttöjärjestelmän jakelu näytetään",
"option": {
"bars": "Vaakapalkit",
"donut": "Donitsikaavio"
}
}
},
"error": {
"internalServerError": "PatchMon-tietojen nouto epäonnistui"
}
},
"bazarr": {
"name": "Bazarr",
"description": "Yleiskatsaus puuttuvista tekstityksistä ja terveystilasta Bazarr-instanssistasi",
"episodes": "Puuttuvat jaksot",
"movies": "Puuttuvat elokuvat",
"providers": "Palveluntarjoajan ongelmat",
"status": "Terveysongelmat",
"option": {
"showMissingEpisodes": {
"label": "Näytä puuttuvat jaksot",
"description": "Näytä niiden jaksojen määrä, joista puuttuu tekstitys"
},
"showMissingMovies": {
"label": "Näytä puuttuvat elokuvat",
"description": "Näytä niiden elokuvien määrä, joista puuttuu tekstitykset"
},
"showProviderIssues": {
"label": "Näytä tarjoajien ongelmat",
"description": "Näytä ongelmallisten tekstitystarjoajien määrä"
},
"showHealthIssues": {
"label": "Näytä kunto-ongelmat",
"description": "Näytä Bazarrin kunto-ongelmien määrä"
}
},
"error": {
"internalServerError": "Bazarrin tietojen nouto epäonnistui"
}
},
"mediaMissing": {
"name": "Puuttuva & jonossa oleva media",
"description": "Näyttää puuttuvat ja jonossa olevat elokuvat ja jaksot Radarr:sta ja Sonarr:sta",
"option": {
"showMissing": {
"label": "Näytä puuttuvat kohteet"
},
"showQueued": {
"label": "Näytä jonossa olevat kohteet"
},
"pageSize": {
"label": "Kohteita per sivu"
}
},
"tab": {
"missing": "Puuttuvat",
"queued": "Jonossa"
},
"type": {
"movie": "Elokuva",
"episode": "Jakso"
},
"empty": {
"missing": "Ei puuttuvia kohteita",
"queued": "Ei jonossa olevia kohteita",
"noTabsEnabled": "Ota käyttöön vähintään yksi välilehti widgetin asetuksissa"
},
"timeLeft": "Jäljellä oleva aika"
},
"traefik": {
"name": "Traefik",
"description": "Yleiskatsaus Traefikin reitittimistä, palveluista, middlewareista ja sisääntulopisteistä",
"option": {
"showTcp": {
"label": "Näytä TCP"
},
"showUdp": {
"label": "Näytä UDP"
},
"showEntryPoints": {
"label": "Näytä sisääntulopisteet"
}
},
"instances": "Traefik-instanssit",
"versionUnknown": "Versio tuntematon",
"summary": {
"routers": "Reitittimet",
"entryPoints": "Sisääntulopisteet"
},
"resource": {
"routers": "Reitittimet",
"services": "Palvelut",
"middlewares": "Middlewaret"
},
"status": {
"healthy": "Terve",
"errors": "{count} virhettä",
"warnings": "{count} varoitusta"
},
"error": {
"internalServerError": "Traefikin tietojen nouto epäonnistui"
}
}
},
"widgetPreview": {
@@ -4551,11 +4326,11 @@
},
"navbar": {
"items": {
"workshop": "Workshop",
"home": "Aloitus",
"boards": "Paneelit",
"apps": "Sovellukset",
"integrations": "Integraatiot",
"customWidgets": "Mukautetut widgetit",
"searchEngies": "Hakukoneet",
"medias": "Mediatiedostot",
"users": {
@@ -5694,6 +5469,9 @@
},
"navigationStructure": {
"manage": {
"workshop": {
"label": "Workshop"
},
"label": "",
"boards": {
"label": "Paneelit"
@@ -5728,18 +5506,6 @@
"label": "Muokkaa"
}
},
"custom-widgets": {
"label": "Mukautetut widgetit",
"new": {
"label": "Uusi"
},
"edit": {
"label": "Muokkaa",
"flow": {
"label": "Kulku"
}
}
},
"users": {
"label": "Käyttäjät",
"create": {
+255 -436
View File
@@ -710,14 +710,7 @@
"delete": "Supprimer le widget personnalisé",
"deleteConfirm": "Êtes-vous sûr de vouloir supprimer \"{name}\" ? Cette action est irréversible.",
"export": "Exporter",
"addMapping": "Ajouter une correspondance",
"addColumn": "Ajouter une colonne",
"edit": "Modifier",
"removeMapping": "Supprimer la correspondance",
"removeColumn": "Supprimer la colonne",
"addItem": "Ajouter un élément",
"removeItem": "Supprimer l'élément",
"addBar": "Ajouter une barre",
"duplicate": "Dupliquer",
"copyAiPrompt": "Copier le prompt IA",
"enable": "Activer",
@@ -727,150 +720,13 @@
"field": {
"name": "Nom",
"description": "Description",
"iconUrl": "URL de l'icône",
"url": "URL",
"authType": "Type d’authentification",
"headerName": "Nom du paramètre de l'entête/requête",
"method": "Méthode",
"requestBody": "Corps de la requête",
"displayType": "Type d'affichage",
"jsonPath": "Chemin JSON",
"jsonPathHint": "Utiliser la syntaxe JSONPath pour extraire des valeurs, par exemple $.data.temperature ou $.items[0].name",
"label": "Étiquette",
"unit": "Unité",
"mappings": "Correspondances",
"tablePath": "",
"tablePathHint": "",
"columns": "Colonnes",
"header": "En-tête",
"items": "Objets",
"gridColumns": "Nombre de colonnes",
"cardStyle": "Style des cartes",
"bars": "Barres",
"valuePath": "",
"maxPath": "",
"showPercentage": "Afficher le pourcentage",
"barSize": "Taille de la barre",
"goodValues": "Bonnes valeurs (séparées par des virgules)",
"dotSize": "Taille des points",
"valueSize": "Taille",
"labelPosition": "Position du libellé",
"kvLayout": "",
"striped": "",
"compact": "Mode Compact",
"maxHeight": "",
"color": "Couleur",
"buttonLabel": "",
"buttonColor": "",
"confirmText": "Texte de confirmation",
"confirmTextHint": "",
"successMessage": "Message de réussite",
"successMessageHint": "",
"enabled": "Activé",
"template": {
"label": "Template JSX",
"description": ""
}
},
"placeholder": {
"exampleLabel": "Température du CPU",
"exampleLabelShort": "Température du CPU",
"exampleHeader": "Nom",
"exampleUnit": "°C",
"iconUrl": "https://...",
"url": "https://api.example.com/api/v1/status",
"headerName": "",
"jsonPath": "$.data.value",
"tablePath": "",
"columnJsonPath": "",
"valuePath": "",
"maxPath": "",
"goodValues": "",
"color": ""
},
"cardStyleOption": {
"filled": "",
"outline": "",
"subtle": ""
},
"layoutOption": {
"list": "",
"grid": ""
},
"sizeOption": {
"sm": "Petit",
"md": "Moyen",
"lg": "Grand",
"xl": "Très grand"
},
"labelPositionOption": {
"above": "Au-dessus",
"below": "En dessous"
},
"fieldset": {
"general": "Général",
"connection": "Connexion API",
"display": "Configuration de l'affichage"
},
"displayTypeDescription": {
"singleValue": "Afficher une valeur extraite avec une étiquette et une unité",
"keyValue": "Afficher plusieurs valeurs étiquetées côte à côte",
"table": "",
"statGrid": "",
"progressBars": "",
"statusIndicator": "Points d'état colorés montrant en ligne/hors ligne ou l'état de santé",
"countGrid": "",
"raw": "",
"actionButton": "Un bouton qui déclenche une requête lorsqu'elle est cliquée",
"customJsx": ""
},
"method": {
"GET": "GET",
"POST": "POST",
"PUT": "PUT",
"DELETE": "DELETE",
"PATCH": "PATCH"
},
"authType": {
"none": "Aucun",
"bearer": "Jeton Bearer",
"basic": "Authentification basique",
"apiKeyHeader": "Clé API (En-tête)",
"apiKeyQuery": "Clé API (requête)"
},
"displayType": {
"singleValue": "Valeur unique",
"keyValue": "Clé-Valeur",
"table": "Tableau",
"statGrid": "Grille de statistiques",
"progressBars": "Barre de progression",
"statusIndicator": "Indicateur de statut",
"countGrid": "Grille de valeurs",
"raw": "Raw JSON",
"actionButton": "Bouton d'action",
"customJsx": "JSX personnalisé"
},
"secret": {
"apiKey": "",
"username": "Nom d'utilisateur",
"password": "Mot de passe",
"savedPlaceholder": ""
},
"preview": {
"title": "Aperçu",
"test": "Tester",
"hint": "Cliquez sur Test pour prévisualiser la réponse API avec votre configuration actuelle.",
"rawResponse": ""
"iconUrl": "URL de l'icône"
},
"notification": {
"created": "Widget \"{name}\" créé avec succès.",
"updated": "Widget \"{name}\" mis à jour avec succès.",
"deleted": "Widget \"{name}\" supprimé.",
"imported": "Widget importé avec succès.",
"aiPromptCopied": "",
"aiPromptDescription": "",
"aiPromptCopy": "Copier dans le presse-papiers",
"aiPromptNoResponse": "",
"aiPromptCopyError": "Échec de la copie du prompt dans le presse-papiers. Votre navigateur peut ne pas prendre en charge cette fonctionnalité.",
"createError": "Impossible de créer le widget. Vérifiez que votre point de terminaison API est joignable.",
"updateError": "Impossible de mettre à jour le widget. Vos modifications n'ont pas été enregistrées.",
@@ -883,14 +739,6 @@
"previewError": "Impossible de récupérer l'aperçu. Vérifiez l'URL et réessayez.",
"executed": "Action exécutée avec succès.",
"executeError": "Échec de l'action: {error}"
},
"table": {
"name": "Nom",
"url": "URL",
"display": "Affichage"
},
"widget": {
"disabled": "Ce widget est désactivé"
}
},
"integration": {
@@ -2828,193 +2676,6 @@
"internalServerError": ""
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": {
"name": "Statistiques du serveur Immich",
"description": "Informations sur votre instance Immich",
@@ -3387,35 +3048,6 @@
}
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": {
"name": "Flux RSS",
"description": "Surveiller et afficher un ou plusieurs flux RSS, ATOM ou JSON génériques",
@@ -3744,40 +3376,6 @@
"internalServerError": "Impossible de récupérer les données de disponibilité"
}
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": {
"name": "Statistiques audio",
"description": "",
@@ -3901,26 +3499,6 @@
"unhealthy": "Dysfonctionnement"
}
},
"customApi": {
"name": "",
"description": "",
"option": {
"definitionId": {
"label": ""
},
"refreshInterval": {
"label": "",
"description": ""
}
},
"noDefinition": "",
"definitionNotFound": "",
"noDisplayOutput": "",
"executeConfirm": "",
"executing": "",
"executeSuccess": "",
"executeFailed": ""
},
"beszelSystemTable": {
"name": "Systèmes Beszel (Tableau)",
"description": "Vue en tableau de tous les systèmes surveillés par Beszel avec colonnes triables et indicateurs d'état",
@@ -4171,6 +3749,256 @@
"subtitle": ""
}
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
}
},
"widgetPreview": {
@@ -4551,11 +4379,11 @@
},
"navbar": {
"items": {
"workshop": "Workshop",
"home": "Accueil",
"boards": "Tableaux de bord",
"apps": "Applications",
"integrations": "Intégrations",
"customWidgets": "Widgets personnalisés",
"searchEngies": "Moteurs de recherche",
"medias": "Médias",
"users": {
@@ -5694,6 +5522,9 @@
},
"navigationStructure": {
"manage": {
"workshop": {
"label": "Workshop"
},
"label": "Gérer",
"boards": {
"label": "Tableaux de bord"
@@ -5728,18 +5559,6 @@
"label": "Modifier"
}
},
"custom-widgets": {
"label": "Widgets personnalisés",
"new": {
"label": "Nouveau"
},
"edit": {
"label": "",
"flow": {
"label": ""
}
}
},
"users": {
"label": "Utilisateurs",
"create": {
+254 -488
View File
@@ -688,211 +688,6 @@
"add": ""
}
},
"customWidget": {
"page": {
"list": {
"title": "",
"noResults": "",
"loading": ""
},
"create": {
"title": "",
"subtitle": ""
},
"edit": {
"title": ""
}
},
"action": {
"create": "",
"import": "",
"save": "",
"delete": "",
"deleteConfirm": "",
"export": "",
"addMapping": "",
"addColumn": "",
"edit": "",
"removeMapping": "",
"removeColumn": "",
"addItem": "",
"removeItem": "",
"addBar": "",
"duplicate": "",
"copyAiPrompt": "",
"enable": "",
"disable": "",
"menu": ""
},
"field": {
"name": "",
"description": "",
"iconUrl": "",
"url": "",
"authType": "",
"headerName": "",
"method": "",
"requestBody": "",
"displayType": "",
"jsonPath": "",
"jsonPathHint": "",
"label": "",
"unit": "",
"mappings": "",
"tablePath": "",
"tablePathHint": "",
"columns": "",
"header": "",
"items": "",
"gridColumns": "",
"cardStyle": "",
"bars": "",
"valuePath": "",
"maxPath": "",
"showPercentage": "",
"barSize": "",
"goodValues": "",
"dotSize": "",
"valueSize": "",
"labelPosition": "",
"kvLayout": "",
"striped": "",
"compact": "",
"maxHeight": "",
"color": "",
"buttonLabel": "",
"buttonColor": "",
"confirmText": "",
"confirmTextHint": "",
"successMessage": "",
"successMessageHint": "",
"enabled": "",
"template": {
"label": "",
"description": ""
}
},
"placeholder": {
"exampleLabel": "",
"exampleLabelShort": "",
"exampleHeader": "",
"exampleUnit": "",
"iconUrl": "",
"url": "",
"headerName": "",
"jsonPath": "",
"tablePath": "",
"columnJsonPath": "",
"valuePath": "",
"maxPath": "",
"goodValues": "",
"color": ""
},
"cardStyleOption": {
"filled": "",
"outline": "",
"subtle": ""
},
"layoutOption": {
"list": "",
"grid": ""
},
"sizeOption": {
"sm": "",
"md": "",
"lg": "",
"xl": ""
},
"labelPositionOption": {
"above": "",
"below": ""
},
"fieldset": {
"general": "",
"connection": "",
"display": ""
},
"displayTypeDescription": {
"singleValue": "",
"keyValue": "",
"table": "",
"statGrid": "",
"progressBars": "",
"statusIndicator": "",
"countGrid": "",
"raw": "",
"actionButton": "",
"customJsx": ""
},
"method": {
"GET": "",
"POST": "",
"PUT": "",
"DELETE": "",
"PATCH": ""
},
"authType": {
"none": "",
"bearer": "",
"basic": "",
"apiKeyHeader": "",
"apiKeyQuery": ""
},
"displayType": {
"singleValue": "",
"keyValue": "",
"table": "",
"statGrid": "",
"progressBars": "",
"statusIndicator": "",
"countGrid": "",
"raw": "",
"actionButton": "",
"customJsx": ""
},
"secret": {
"apiKey": "",
"username": "",
"password": "",
"savedPlaceholder": ""
},
"preview": {
"title": "",
"test": "",
"hint": "",
"rawResponse": ""
},
"notification": {
"created": "",
"updated": "",
"deleted": "",
"imported": "",
"aiPromptCopied": "",
"aiPromptDescription": "",
"aiPromptCopy": "",
"aiPromptNoResponse": "",
"aiPromptCopyError": "",
"createError": "",
"updateError": "",
"importError": "",
"exportError": "",
"duplicated": "",
"duplicateError": "",
"toggleError": "",
"deleteError": "",
"previewError": "",
"executed": "",
"executeError": ""
},
"table": {
"name": "",
"url": "",
"display": ""
},
"widget": {
"disabled": ""
}
},
"integration": {
"page": {
"list": {
@@ -2828,193 +2623,6 @@
"internalServerError": ""
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": {
"name": "",
"description": "",
@@ -3387,35 +2995,6 @@
}
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": {
"name": "RSS kanali",
"description": "Pratite i prikazujte jedan ili više općih RSS, ATOM ili JSON kanala",
@@ -3744,40 +3323,6 @@
"internalServerError": ""
}
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": {
"name": "",
"description": "",
@@ -3901,26 +3446,6 @@
"unhealthy": ""
}
},
"customApi": {
"name": "",
"description": "",
"option": {
"definitionId": {
"label": ""
},
"refreshInterval": {
"label": "",
"description": ""
}
},
"noDefinition": "",
"definitionNotFound": "",
"noDisplayOutput": "",
"executeConfirm": "",
"executing": "",
"executeSuccess": "",
"executeFailed": ""
},
"beszelSystemTable": {
"name": "Beszel sustavi (tablica)",
"description": "Tablični prikaz svih Beszel nadziranih sustava s sortabilnim stupcima i indikatorima statusa",
@@ -4171,6 +3696,256 @@
"subtitle": ""
}
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
}
},
"widgetPreview": {
@@ -4551,11 +4326,11 @@
},
"navbar": {
"items": {
"workshop": "Workshop",
"home": "Dom",
"boards": "Daske",
"apps": "aplikacije",
"integrations": "Integracije",
"customWidgets": "",
"searchEngies": "Tražilice",
"medias": "Mediji",
"users": {
@@ -5694,6 +5469,9 @@
},
"navigationStructure": {
"manage": {
"workshop": {
"label": "Workshop"
},
"label": "Upravljati",
"boards": {
"label": "Daske"
@@ -5728,18 +5506,6 @@
"label": "Uredi"
}
},
"custom-widgets": {
"label": "",
"new": {
"label": ""
},
"edit": {
"label": "",
"flow": {
"label": ""
}
}
},
"users": {
"label": "Korisnici",
"create": {
+254 -488
View File
@@ -688,211 +688,6 @@
"add": "Alkalmazás hozzáadása"
}
},
"customWidget": {
"page": {
"list": {
"title": "Egyéni widgetek",
"noResults": "Még nincsenek egyéni widgetek. Hozd létre az elsőt!",
"loading": "Töltés..."
},
"create": {
"title": "Egyéni widget létrehozása",
"subtitle": "Adj meg egy API URL-t, hitelesítést, és hogy hogyan jelenjenek meg a válaszadatok."
},
"edit": {
"title": "Egyéni widget szerkesztése"
}
},
"action": {
"create": "Létrehozás",
"import": "Importálás",
"save": "Mentés",
"delete": "Egyéni widget törlése",
"deleteConfirm": "Biztosan törölni szeretnéd \"{name}\" widgetet? Ez a művelet nem vonható vissza.",
"export": "Exportálás",
"addMapping": "Leképezés hozzáadása",
"addColumn": "Oszlop hozzáadása",
"edit": "Szerkesztés",
"removeMapping": "Leképezés eltávolítása",
"removeColumn": "Oszlop eltávolítása",
"addItem": "Elem hozzáadása",
"removeItem": "Elem eltávolítása",
"addBar": "Sáv hozzáadása",
"duplicate": "Duplikálás",
"copyAiPrompt": "AI prompt másolása",
"enable": "Engedélyezés",
"disable": "Letiltás",
"menu": "Műveletek"
},
"field": {
"name": "Név",
"description": "Leírás",
"iconUrl": "Ikon URL",
"url": "URL",
"authType": "Hitelesítés típusa",
"headerName": "Fejléc/lekérdezési paraméter neve",
"method": "Metódus",
"requestBody": "Kérelem törzse",
"displayType": "Megjelenítés típusa",
"jsonPath": "JSON elérési út",
"jsonPathHint": "Használd a JSONPath szintaxist az értékek kinyeréséhez, pl. $.data.temperature vagy $.items[0].name",
"label": "Címke",
"unit": "Mértékegység",
"mappings": "Leképezések",
"tablePath": "Tömb JSON elérési útja",
"tablePathHint": "A válaszban lévő tömb elérési útja, pl. $.data.items",
"columns": "Oszlopok",
"header": "Fejléc",
"items": "Elemek",
"gridColumns": "Rács oszlopok",
"cardStyle": "Kártya stílus",
"bars": "Sávok",
"valuePath": "Érték JSON elérési út",
"maxPath": "Maximális érték JSON elérési út",
"showPercentage": "Százalék megjelenítése",
"barSize": "Sáv mérete",
"goodValues": "Jó értékek (vesszővel elválasztva)",
"dotSize": "Pont mérete",
"valueSize": "Érték mérete",
"labelPosition": "Címke pozíciója",
"kvLayout": "Elrendezés",
"striped": "Csíkos sorok",
"compact": "Kompakt mód",
"maxHeight": "Maximális magasság (px)",
"color": "Szín",
"buttonLabel": "Gomb felirata",
"buttonColor": "Gomb színe",
"confirmText": "Megerősítő szöveg",
"confirmTextHint": "Ha be van állítva, egy megerősítő ablak jelenik meg a kérés végrehajtása előtt",
"successMessage": "Sikerüzenet",
"successMessageHint": "A sikeres végrehajtás után megjelenő üzenet",
"enabled": "Engedélyezve",
"template": {
"label": "JSX sablon",
"description": "Mantine JSX sablon. Az API válasz mezőit adatkötéseken keresztül éred el (pl. data.name). Csak engedélyezett komponenseket használj. Tilos: constructor, __proto__, eval, Function, window, document."
}
},
"placeholder": {
"exampleLabel": "CPU hőmérséklet",
"exampleLabelShort": "CPU hőm",
"exampleHeader": "Név",
"exampleUnit": "°C",
"iconUrl": "https://...",
"url": "https://api.example.com/api/v1/status",
"headerName": "X-API-Key",
"jsonPath": "$.data.value",
"tablePath": "$.data.items",
"columnJsonPath": "$.name",
"valuePath": "$.data.used",
"maxPath": "$.data.total",
"goodValues": "online, true, up",
"color": "kék"
},
"cardStyleOption": {
"filled": "Kitöltött",
"outline": "Körvonal",
"subtle": "Halvány"
},
"layoutOption": {
"list": "Lista",
"grid": "Rács"
},
"sizeOption": {
"sm": "Kicsi",
"md": "Közepes",
"lg": "Nagy",
"xl": "Extra nagy"
},
"labelPositionOption": {
"above": "Felette",
"below": "Alatta"
},
"fieldset": {
"general": "Általános",
"connection": "API kapcsolat",
"display": "Megjelenítési konfiguráció"
},
"displayTypeDescription": {
"singleValue": "Egy kinyert érték megjelenítése címkével és mértékegységgel",
"keyValue": "Több címkézett érték megjelenítése egymás mellett",
"table": "Adatsorok megjelenítése táblázatos formában",
"statGrid": "Színezett statisztikai kártyák rácsban – mint a Pi-Hole vagy Speedtest widgetek",
"progressBars": "Folyamatjelző sávok használat vagy készültség mutatására – lemez, memória, kvóta",
"statusIndicator": "Színezett állapotpontok, amelyek online/offline vagy egészségügyi állapotot mutatnak",
"countGrid": "Kompakt szám + címke számlálók sűrű rácsban",
"raw": "Szépen formázott JSON kimenet hibakereséshez",
"actionButton": "Egy gomb, ami kérés végrehajtását váltja ki kattintásra",
"customJsx": "Egyéni JSX elrendezés engedélyezett Mantine komponensekkel és teljes API adatkötéssel"
},
"method": {
"GET": "GET",
"POST": "POST",
"PUT": "PUT",
"DELETE": "DELETE",
"PATCH": "PATCH"
},
"authType": {
"none": "Nincs",
"bearer": "Bearer token",
"basic": "Basic Auth",
"apiKeyHeader": "API-kulcs (fejléc)",
"apiKeyQuery": "API-kulcs (lekérdezés)"
},
"displayType": {
"singleValue": "Egyedi érték",
"keyValue": "Kulcs-érték",
"table": "Táblázat",
"statGrid": "Statisztikai rács",
"progressBars": "Folyamatjelző sávok",
"statusIndicator": "Állapotjelző",
"countGrid": "Számláló rács",
"raw": "Nyers JSON",
"actionButton": "Műveleti gomb",
"customJsx": "Egyéni JSX"
},
"secret": {
"apiKey": "API kulcs / token",
"username": "Felhasználónév",
"password": "Jelszó",
"savedPlaceholder": "••••••• (mentve, üresen hagyva megtartja)"
},
"preview": {
"title": "Előnézet",
"test": "Teszt",
"hint": "Kattints a Teszt gombra az API válasz előnézetéhez a jelenlegi konfigurációval.",
"rawResponse": "Nyers JSON válasz"
},
"notification": {
"created": "\"{name}\" widget sikeresen létrehozva.",
"updated": "\"{name}\" widget sikeresen frissítve.",
"deleted": "\"{name}\" widget törölve.",
"imported": "",
"aiPromptCopied": "AI prompt a vágólapra másolva",
"aiPromptDescription": "Másolj egy előre elkészített promptot bármelyik AI chatbotba (ChatGPT, Claude, Gemini...). Tartalmazza a teljes widget sémát és az API választ, így az AI generálhat egy importálásra kész JSON konfigurációt.",
"aiPromptCopy": "Másolás a vágólapra",
"aiPromptNoResponse": "Tipp: Futtass egy tesztet először, hogy az API válasz is bekerüljön a promptba a jobb eredmények érdekében.",
"aiPromptCopyError": "A prompt vágólapra másolása sikertelen. Előfordulhat, hogy a böngésződ nem támogatja ezt a funkciót.",
"createError": "A widget létrehozása sikertelen. Ellenőrizd, hogy az API végpont elérhető-e.",
"updateError": "A widget frissítése sikertelen. A módosításaid nem lettek mentve.",
"importError": "A widget importálása sikertelen. Ellenőrizd, hogy a fájl érvényes egyéni widget JSON export-e.",
"exportError": "A widget exportálása sikertelen.",
"duplicated": "\"{name}\" widget duplikálva.",
"duplicateError": "A widget duplikálása sikertelen.",
"toggleError": "A widget állapotának átkapcsolása sikertelen.",
"deleteError": "A widget törlése sikertelen.",
"previewError": "Az előnézet lekérése sikertelen. Ellenőrizd az URL-t és próbáld újra.",
"executed": "A művelet sikeresen végrehajtva.",
"executeError": "A művelet sikertelen: {error}"
},
"table": {
"name": "Név",
"url": "URL",
"display": "Megjelenítés"
},
"widget": {
"disabled": "Ez a widget le van tiltva"
}
},
"integration": {
"page": {
"list": {
@@ -2828,193 +2623,6 @@
"internalServerError": "A Paperless-ngx adatok letöltése nem sikerült"
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": {
"name": "Immich szerver statisztikák",
"description": "Információk az Immich-példányodról",
@@ -3387,35 +2995,6 @@
}
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": {
"name": "RSS feedek",
"description": "Egy vagy több általános RSS-, ATOM- vagy JSON-hírcsatorna figyelése és megjelenítése",
@@ -3744,40 +3323,6 @@
"internalServerError": "Az üzemidőadatok letöltése nem sikerült"
}
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": {
"name": "Audió statisztikák",
"description": "Könyvtári és lejátszási statisztikák Navidrome-ból vagy Audiobookshelf-ből",
@@ -3901,26 +3446,6 @@
"unhealthy": "Hibás"
}
},
"customApi": {
"name": "Egyéni API",
"description": "Adatok megjelenítése bármely külső API-ból egyedi konfigurációval.",
"option": {
"definitionId": {
"label": "Definíció azonosító"
},
"refreshInterval": {
"label": "Frissítési időköz",
"description": "Milyen gyakran kérje le újra az adatokat az API-tól (másodpercben)"
}
},
"noDefinition": "Nincs definíció kiválasztva",
"definitionNotFound": "A widget definíció nem található. Lehet, hogy törölték.",
"noDisplayOutput": "Nincs megjelenítési kimenet",
"executeConfirm": "Biztosan végre szeretnéd hajtani ezt a műveletet?",
"executing": "Végrehajtás...",
"executeSuccess": "A művelet sikeresen végrehajtva",
"executeFailed": "A művelet sikertelen. Ellenőrizd a widget konfigurációját."
},
"beszelSystemTable": {
"name": "Beszel Rendszerek (Táblázat)",
"description": "Az összes Beszel által figyelt rendszer táblázatos nézete rendezhető oszlopokkal és állapotjelzőkkel",
@@ -4171,6 +3696,256 @@
"subtitle": "A Docker konténerek hálózati forgalma"
}
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
}
},
"widgetPreview": {
@@ -4551,11 +4326,11 @@
},
"navbar": {
"items": {
"workshop": "Workshop",
"home": "Nyitólap",
"boards": "Táblák",
"apps": "Alkalmazások",
"integrations": "Integrációk",
"customWidgets": "",
"searchEngies": "Keresőmotorok",
"medias": "Média",
"users": {
@@ -5694,6 +5469,9 @@
},
"navigationStructure": {
"manage": {
"workshop": {
"label": "Workshop"
},
"label": "Kezelés",
"boards": {
"label": "Táblák"
@@ -5728,18 +5506,6 @@
"label": "Szerkesztés"
}
},
"custom-widgets": {
"label": "",
"new": {
"label": ""
},
"edit": {
"label": "",
"flow": {
"label": ""
}
}
},
"users": {
"label": "Felhasználók",
"create": {
+255 -423
View File
@@ -710,14 +710,7 @@
"delete": "사용자 지정 위젯 삭제",
"deleteConfirm": "\"{name}\"을(를) 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.",
"export": "내보내기",
"addMapping": "매핑 추가",
"addColumn": "열 추가",
"edit": "편집",
"removeMapping": "매핑 제거",
"removeColumn": "열 제거",
"addItem": "항목 추가",
"removeItem": "항목 제거",
"addBar": "바 추가",
"duplicate": "복사",
"copyAiPrompt": "AI 프롬프트 복사",
"enable": "활성화",
@@ -727,140 +720,7 @@
"field": {
"name": "이름",
"description": "설명",
"iconUrl": "아이콘 URL",
"url": "URL",
"authType": "인증 유형",
"headerName": "헤더/쿼리 파라미터 이름",
"method": "메서드",
"requestBody": "요청 본문",
"displayType": "표시 유형",
"jsonPath": "JSON 경로",
"jsonPathHint": "JSONPath 문법으로 값을 추출하십시오. 예: $.data.temperature 또는 $.items[0].name",
"label": "레이블",
"unit": "단위",
"mappings": "매핑",
"tablePath": "JSON 경로 배열",
"tablePathHint": "응답에서 배열이 위치한 경로입니다. 예: $.data.items",
"columns": "열",
"header": "헤더",
"items": "항목",
"gridColumns": "그리드 열 개수",
"cardStyle": "카드 스타일",
"bars": "바",
"valuePath": "JSON 경로 값",
"maxPath": "JSON 경로 최댓값",
"showPercentage": "백분율 표시",
"barSize": "바 크기",
"goodValues": "정상 값(쉼표로 구분)",
"dotSize": "점 크기",
"valueSize": "값 크기",
"labelPosition": "레이블 위치",
"kvLayout": "레이아웃",
"striped": "줄무늬 행",
"compact": "컴팩트 모드",
"maxHeight": "최대 높이 (px)",
"color": "색상",
"buttonLabel": "버튼 명칭",
"buttonColor": "버튼 색상",
"confirmText": "확인 텍스트",
"confirmTextHint": "설정하면 요청을 실행하기 전에 확인 대화상자가 표시됩니다",
"successMessage": "성공 메세지",
"successMessageHint": "실행 성공 후 표시되는 메세지",
"enabled": "활성화됨",
"template": {
"label": "JSX 템플릿",
"description": "Mantine JSX 템플릿. 데이터 바인딩(예: data.name)을 통해 API 응답 필드에 액세스합니다. 허용된 구성 요소만 사용하십시오. 금지: constructor, __proto__, eval, Function, window, document."
}
},
"placeholder": {
"exampleLabel": "CPU 온도",
"exampleLabelShort": "CPU 온도",
"exampleHeader": "이름",
"exampleUnit": "°C",
"iconUrl": "https://...",
"url": "https://api.example.com/api/v1/status",
"headerName": "X-API-Key",
"jsonPath": "$.data.value",
"tablePath": "$.data.items",
"columnJsonPath": "$.name",
"valuePath": "$.data.used",
"maxPath": "$.data.total",
"goodValues": "online, true, up",
"color": "파랑"
},
"cardStyleOption": {
"filled": "채워짐",
"outline": "외곽선",
"subtle": "미묘한"
},
"layoutOption": {
"list": "리스트",
"grid": "그리드"
},
"sizeOption": {
"sm": "작음",
"md": "중간",
"lg": "큼",
"xl": "매우 큼"
},
"labelPositionOption": {
"above": "위",
"below": "아래"
},
"fieldset": {
"general": "일반",
"connection": "API 연결",
"display": "표시 설정"
},
"displayTypeDescription": {
"singleValue": "레이블과 단위가 있는 하나의 추출된 값을 표시합니다",
"keyValue": "여러 레이블이 지정된 값을 나란히 표시합니다",
"table": "테이블 형식으로 데이터 행을 표시합니다",
"statGrid": "그리드의 색상이 지정된 통계 카드 — Pi-Hole 또는 Speedtest 위젯과 유사",
"progressBars": "사용량 또는 완료율을 표시하는 진행률 표시줄 — 디스크, 메모리, 할당량용",
"statusIndicator": "온라인/오프라인 또는 상태를 표시하는 색상 상태 점",
"countGrid": "좁은 그리드에 작은 숫자 + 레이블 카운터",
"raw": "디버깅을 위한 예쁘게 출력된 JSON",
"actionButton": "클릭 시 요청을 트리거하는 버튼",
"customJsx": "전체 API 데이터 바인딩과 함께 허용된 Mantine 구성 요소를 사용하는 사용자 정의 JSX 레이아웃"
},
"method": {
"GET": "GET",
"POST": "POST",
"PUT": "PUT",
"DELETE": "DELETE",
"PATCH": "PATCH"
},
"authType": {
"none": "없음",
"bearer": "Bearer 토큰",
"basic": "기본 인증",
"apiKeyHeader": "API 키(헤더)",
"apiKeyQuery": "API 키(쿼리)"
},
"displayType": {
"singleValue": "단일 값",
"keyValue": "키-값",
"table": "테이블",
"statGrid": "스택 그리드",
"progressBars": "진행 바",
"statusIndicator": "상태 인디케이터",
"countGrid": "카운트 그리드",
"raw": "원시 JSON",
"actionButton": "동작 버튼",
"customJsx": "사용자 지정 JSX"
},
"secret": {
"apiKey": "API 키/토큰",
"username": "사용자명",
"password": "비밀번호",
"savedPlaceholder": "••••••• (저장됨, 유지하려면 공백)"
},
"preview": {
"title": "미리보기",
"test": "테스트",
"hint": "현재 설정으로 API 응답을 미리 보려면 테스트를 클릭하십시오.",
"rawResponse": "원본 JSON 응답"
"iconUrl": "아이콘 URL"
},
"notification": {
"created": "\"{name}\" 위젯 생성 완료.",
@@ -868,9 +728,6 @@
"deleted": "\"{name}\" 위젯 삭제 완료.",
"imported": "위젯 가져오기 완료.",
"aiPromptCopied": "AI 프롬프트 클립보드에 복사됨",
"aiPromptDescription": "사전 제작된 프롬프트를 복사하여 AI 챗봇(ChatGPT, Claude, Gemini 등)에 붙여넣습니다. 전체 위젯 스키마 및 API 응답이 포함되어 있으므로 즉시 가져올 수 있는 JSON 설정을 AI가 생성할 수 있습니다.",
"aiPromptCopy": "클립보드에 복사",
"aiPromptNoResponse": "팁: 더 나은 결과를 얻기 위해 먼저 테스트로 프롬프트에 API 응답을 포함하십시오.",
"aiPromptCopyError": "프롬프트 클립보드 복사 실패. 브라우저에서 이 기능을 지원하지 않을 수도 있습니다.",
"createError": "위젯 생성 실패. API 엔드포인트에 도달할 수 있는지 확인해 보십시오.",
"updateError": "위젯 업데이트 실패. 변경 사항이 저장되지 않습니다.",
@@ -883,14 +740,6 @@
"previewError": "미리보기 가져오기 실패. URL을 확인한 후 다시 시도해 주십시오.",
"executed": "작업 실행 완료.",
"executeError": "작업 실패: {error}"
},
"table": {
"name": "이름",
"url": "URL",
"display": "표시"
},
"widget": {
"disabled": "위젯 비활성화됨"
}
},
"integration": {
@@ -2828,193 +2677,6 @@
"internalServerError": "Paperless-ngx 데이터를 가져오지 못함"
}
},
"patchmon": {
"name": "PatchMon",
"description": "PatchMon의 호스트 패치 상태 개요",
"title": "PatchMon 통계",
"totalHosts": "총 호스트",
"hostsNeedingUpdates": "업데이트 필요",
"securityUpdates": "보안 업데이트",
"upToDateHosts": "최신 상태의 호스트",
"hostsWithSecurityUpdates": "보안 업데이트가 필요한 호스트",
"recentUpdates24h": "업데이트 (24시간)",
"totalOutdatedPackages": "오래된 패키지",
"totalRepos": "저장소",
"osDistribution": "OS 배포판",
"compliance": "패치 준수",
"complianceRatio": "{upToDate} / {total}",
"lastUpdated": "{time} 업데이트됨",
"option": {
"showTotalHosts": {
"label": "총 호스트 표시",
"description": "모니터링되는 총 호스트 수 표시"
},
"showHostsNeedingUpdates": {
"label": "업데이트가 필요한 호스트 표시",
"description": "하나 이상의 오래된 패키지가 있는 호스트 표시"
},
"showSecurityUpdates": {
"label": "보안 업데이트 표시",
"description": "사용 가능한 총 보안 업데이트 수 표시"
},
"showUpToDateHosts": {
"label": "최신 호스트 표시",
"description": "오래된 패키지가 없는 호스트 표시"
},
"showHostsWithSecurityUpdates": {
"label": "보안 업데이트가 필요한 호스트 표시",
"description": "보안 패치가 필요한 호스트 표시"
},
"showRecentUpdates24h": {
"label": "최근 업데이트 (24시간) 표시",
"description": "지난 24시간 동안 적용된 업데이트 수 표시"
},
"showTotalOutdatedPackages": {
"label": "오래된 패키지 표시",
"description": "모든 호스트에서의 총 오래된 패키지 수 표시"
},
"showTotalRepos": {
"label": "저장소 표시",
"description": "모니터링되는 활성 저장소 수 표시"
},
"enableThresholdColors": {
"label": "임계값 색상 활성화",
"description": "심각도 사전 설정에 따라 통계 값을 녹색, 노란색 또는 빨간색으로 표시"
},
"useCustomThresholds": {
"label": "고급 임계값",
"description": "절대 개수 또는 전체 호스트 대비 백분율을 사용하여 통계별 경고 및 위험 임계값 사용자 정의"
},
"thresholdMode": {
"option": {
"absolute": "절대 개수",
"percent": "전체 호스트 대비 백분율"
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "업데이트 필요 임계값 모드",
"description": "업데이트 필요 개수를 절대값 또는 전체 호스트 대비 백분율로 비교"
},
"hostsNeedingUpdatesWarningAt": {
"label": "업데이트 필요 경고 임계값",
"description": "이 임계값에 도달하면 노란색으로 표시"
},
"hostsNeedingUpdatesCriticalAt": {
"label": "업데이트 필요 위험 임계값",
"description": "이 임계값에 도달하면 빨간색으로 표시"
},
"securityUpdatesThresholdMode": {
"label": "보안 업데이트 임계값 모드",
"description": "보안 업데이트 개수를 절대값 또는 전체 호스트 대비 백분율로 비교"
},
"securityUpdatesWarningAt": {
"label": "보안 업데이트 경고 임계값",
"description": "이 임계값에 도달하면 노란색으로 표시"
},
"securityUpdatesCriticalAt": {
"label": "보안 업데이트 위험 임계값",
"description": "이 임계값에 도달하면 빨간색으로 표시"
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "보안 업데이트가 있는 호스트 임계값 모드",
"description": "호스트 개수를 절대값 또는 전체 호스트 대비 백분율로 비교"
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "보안 업데이트가 있는 호스트 경고 임계값",
"description": "이 임계값에 도달하면 노란색으로 표시"
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "보안 업데이트가 있는 호스트 위험 임계값",
"description": "이 임계값에 도달하면 빨간색으로 표시"
},
"upToDateHostsThresholdMode": {
"label": "최신 호스트 임계값 모드",
"description": "최신 호스트 개수를 절대값 또는 전체 호스트 대비 백분율로 비교"
},
"upToDateHostsWarningAt": {
"label": "최신 호스트 경고 임계값",
"description": "값이 이 임계값 이상이지만 전체 적용 범위 미만일 때 노란색으로 표시"
},
"upToDateHostsCriticalAt": {
"label": "최신 호스트 위험 임계값",
"description": "값이 이 임계값 미만으로 떨어지면 빨간색으로 표시"
},
"totalOutdatedPackagesThresholdMode": {
"label": "오래된 패키지 임계값 모드",
"description": "오래된 패키지 개수를 절대값 또는 전체 호스트 대비 백분율로 비교"
},
"totalOutdatedPackagesWarningAt": {
"label": "오래된 패키지 경고 임계값",
"description": "이 임계값에 도달하면 노란색으로 표시"
},
"totalOutdatedPackagesCriticalAt": {
"label": "오래된 패키지 위험 임계값",
"description": "이 임계값에 도달하면 빨간색으로 표시"
},
"showOsDistribution": {
"label": "OS 배포판 표시",
"description": "운영 체제별로 모니터링되는 호스트 분석 표시"
},
"osDistributionLimit": {
"label": "OS 배포판 제한",
"description": "표시할 최대 운영 체제 수",
"option": {
"3": "상위 3개",
"5": "상위 5개",
"10": "상위 10개",
"all": "모두"
}
},
"showOsVersion": {
"label": "OS 버전 표시",
"description": "사용 가능한 경우 각 배포판 레이블에 OS 버전 추가"
},
"showComplianceHero": {
"label": "준수 상태 표시",
"description": "최신 호스트의 백분율을 표시하는 준수 링 표시"
},
"osDisplayMode": {
"label": "OS 표시 모드",
"description": "운영 체제 배포판 표시 방법 선택",
"option": {
"bars": "가로 막대",
"donut": "도넛 차트"
}
}
},
"error": {
"internalServerError": "PatchMon 데이터를 가져오지 못했습니다"
}
},
"bazarr": {
"name": "Bazarr",
"description": "Bazarr 인스턴스의 누락된 자막 및 상태 개요",
"episodes": "누락된 에피소드",
"movies": "누락된 영화",
"providers": "제공자 문제",
"status": "상태 문제",
"option": {
"showMissingEpisodes": {
"label": "누락된 에피소드 표시",
"description": "누락된 자막이 있는 에피소드 수 표시"
},
"showMissingMovies": {
"label": "누락된 영화 표시",
"description": "누락된 자막이 있는 영화 수 표시"
},
"showProviderIssues": {
"label": "제공자 문제 표시",
"description": "문제가 있는 자막 제공자 수 표시"
},
"showHealthIssues": {
"label": "상태 문제 표시",
"description": "Bazarr 상태 문제 수 표시"
}
},
"error": {
"internalServerError": "Bazarr 데이터를 가져오지 못했습니다"
}
},
"immich-serverStats": {
"name": "Immich 서버 정보",
"description": "Immich 인스턴스에 대한 정보",
@@ -3387,35 +3049,6 @@
}
}
},
"mediaMissing": {
"name": "누락 및 대기 중인 미디어",
"description": "Radarr 및 Sonarr의 누락 및 대기 중인 영화와 에피소드 표시",
"option": {
"showMissing": {
"label": "누락된 항목 표시"
},
"showQueued": {
"label": "대기 중인 항목 표시"
},
"pageSize": {
"label": "페이지당 항목 수"
}
},
"tab": {
"missing": "누락",
"queued": "대기 중"
},
"type": {
"movie": "영화",
"episode": "에피소드"
},
"empty": {
"missing": "누락된 항목 없음",
"queued": "대기 중인 항목 없음",
"noTabsEnabled": "위젯 설정에서 최소한 하나의 탭을 활성화하세요"
},
"timeLeft": "남은 시간"
},
"rssFeed": {
"name": "RSS 피드",
"description": "하나 이상의 일반 RSS, ATOM 또는 JSON 피드를 모니터링하고 표시합니다",
@@ -3744,40 +3377,6 @@
"internalServerError": "가동 시간 데이터를 가져오지 못함"
}
},
"traefik": {
"name": "Traefik",
"description": "Traefik 라우터, 서비스, 미들웨어 및 진입점 개요",
"option": {
"showTcp": {
"label": "TCP 표시"
},
"showUdp": {
"label": "UDP 표시"
},
"showEntryPoints": {
"label": "진입점 표시"
}
},
"instances": "Traefik 인스턴스",
"versionUnknown": "버전 알 수 없음",
"summary": {
"routers": "라우터",
"entryPoints": "진입점"
},
"resource": {
"routers": "라우터",
"services": "서비스",
"middlewares": "미들웨어"
},
"status": {
"healthy": "정상",
"errors": "{count}개 오류",
"warnings": "{count}개 경고"
},
"error": {
"internalServerError": "Traefik 데이터를 가져오지 못함"
}
},
"audioStats": {
"name": "오디오 정보",
"description": "Navidrome 또는 Audiobookshelf의 라이브러리 및 재생 정보",
@@ -3901,26 +3500,6 @@
"unhealthy": "비정상"
}
},
"customApi": {
"name": "사용자 지정 API",
"description": "사용자 지정 설정으로 외부 API 데이터를 표시합니다.",
"option": {
"definitionId": {
"label": "정의 ID"
},
"refreshInterval": {
"label": "새로고침 간격",
"description": "API에서 데이터를 다시 가져오는 빈도 (초 단위)"
}
},
"noDefinition": "선택한 정의 없음",
"definitionNotFound": "위젯 정의를 찾을 수 없습니다. 삭제되었을 수 있습니다.",
"noDisplayOutput": "디스플레이 출력 없음",
"executeConfirm": "이 작업을 삭제하시겠습니까?",
"executing": "실행 중...",
"executeSuccess": "작업 실행 완료",
"executeFailed": "작업 실패. 위젯 설정을 확인하십시오."
},
"beszelSystemTable": {
"name": "Beszel 시스템 (표)",
"description": "정렬 가능한 열과 상태 표시기가 있는 모든 Beszel 모니터링 시스템의 표 보기",
@@ -4171,6 +3750,256 @@
"subtitle": "Docker 컨테이너의 네트워크 트래픽"
}
}
},
"patchmon": {
"name": "PatchMon",
"description": "PatchMon의 호스트 패치 상태 개요",
"title": "PatchMon 통계",
"totalHosts": "총 호스트",
"hostsNeedingUpdates": "업데이트 필요",
"securityUpdates": "보안 업데이트",
"upToDateHosts": "최신 상태의 호스트",
"hostsWithSecurityUpdates": "보안 업데이트가 필요한 호스트",
"recentUpdates24h": "업데이트 (24시간)",
"totalOutdatedPackages": "오래된 패키지",
"totalRepos": "저장소",
"osDistribution": "OS 배포판",
"compliance": "패치 준수",
"complianceRatio": "{upToDate} / {total}",
"lastUpdated": "{time} 업데이트됨",
"option": {
"showTotalHosts": {
"label": "총 호스트 표시",
"description": "모니터링되는 총 호스트 수 표시"
},
"showHostsNeedingUpdates": {
"label": "업데이트가 필요한 호스트 표시",
"description": "하나 이상의 오래된 패키지가 있는 호스트 표시"
},
"showSecurityUpdates": {
"label": "보안 업데이트 표시",
"description": "사용 가능한 총 보안 업데이트 수 표시"
},
"showUpToDateHosts": {
"label": "최신 호스트 표시",
"description": "오래된 패키지가 없는 호스트 표시"
},
"showHostsWithSecurityUpdates": {
"label": "보안 업데이트가 필요한 호스트 표시",
"description": "보안 패치가 필요한 호스트 표시"
},
"showRecentUpdates24h": {
"label": "최근 업데이트 (24시간) 표시",
"description": "지난 24시간 동안 적용된 업데이트 수 표시"
},
"showTotalOutdatedPackages": {
"label": "오래된 패키지 표시",
"description": "모든 호스트에서의 총 오래된 패키지 수 표시"
},
"showTotalRepos": {
"label": "저장소 표시",
"description": "모니터링되는 활성 저장소 수 표시"
},
"enableThresholdColors": {
"label": "임계값 색상 활성화",
"description": "심각도 사전 설정에 따라 통계 값을 녹색, 노란색 또는 빨간색으로 표시"
},
"useCustomThresholds": {
"label": "고급 임계값",
"description": "절대 개수 또는 전체 호스트 대비 백분율을 사용하여 통계별 경고 및 위험 임계값 사용자 정의"
},
"thresholdMode": {
"option": {
"absolute": "절대 개수",
"percent": "전체 호스트 대비 백분율"
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "업데이트 필요 임계값 모드",
"description": "업데이트 필요 개수를 절대값 또는 전체 호스트 대비 백분율로 비교"
},
"hostsNeedingUpdatesWarningAt": {
"label": "업데이트 필요 경고 임계값",
"description": "이 임계값에 도달하면 노란색으로 표시"
},
"hostsNeedingUpdatesCriticalAt": {
"label": "업데이트 필요 위험 임계값",
"description": "이 임계값에 도달하면 빨간색으로 표시"
},
"securityUpdatesThresholdMode": {
"label": "보안 업데이트 임계값 모드",
"description": "보안 업데이트 개수를 절대값 또는 전체 호스트 대비 백분율로 비교"
},
"securityUpdatesWarningAt": {
"label": "보안 업데이트 경고 임계값",
"description": "이 임계값에 도달하면 노란색으로 표시"
},
"securityUpdatesCriticalAt": {
"label": "보안 업데이트 위험 임계값",
"description": "이 임계값에 도달하면 빨간색으로 표시"
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "보안 업데이트가 있는 호스트 임계값 모드",
"description": "호스트 개수를 절대값 또는 전체 호스트 대비 백분율로 비교"
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "보안 업데이트가 있는 호스트 경고 임계값",
"description": "이 임계값에 도달하면 노란색으로 표시"
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "보안 업데이트가 있는 호스트 위험 임계값",
"description": "이 임계값에 도달하면 빨간색으로 표시"
},
"upToDateHostsThresholdMode": {
"label": "최신 호스트 임계값 모드",
"description": "최신 호스트 개수를 절대값 또는 전체 호스트 대비 백분율로 비교"
},
"upToDateHostsWarningAt": {
"label": "최신 호스트 경고 임계값",
"description": "값이 이 임계값 이상이지만 전체 적용 범위 미만일 때 노란색으로 표시"
},
"upToDateHostsCriticalAt": {
"label": "최신 호스트 위험 임계값",
"description": "값이 이 임계값 미만으로 떨어지면 빨간색으로 표시"
},
"totalOutdatedPackagesThresholdMode": {
"label": "오래된 패키지 임계값 모드",
"description": "오래된 패키지 개수를 절대값 또는 전체 호스트 대비 백분율로 비교"
},
"totalOutdatedPackagesWarningAt": {
"label": "오래된 패키지 경고 임계값",
"description": "이 임계값에 도달하면 노란색으로 표시"
},
"totalOutdatedPackagesCriticalAt": {
"label": "오래된 패키지 위험 임계값",
"description": "이 임계값에 도달하면 빨간색으로 표시"
},
"showOsDistribution": {
"label": "OS 배포판 표시",
"description": "운영 체제별로 모니터링되는 호스트 분석 표시"
},
"osDistributionLimit": {
"label": "OS 배포판 제한",
"description": "표시할 최대 운영 체제 수",
"option": {
"3": "상위 3개",
"5": "상위 5개",
"10": "상위 10개",
"all": "모두"
}
},
"showOsVersion": {
"label": "OS 버전 표시",
"description": "사용 가능한 경우 각 배포판 레이블에 OS 버전 추가"
},
"showComplianceHero": {
"label": "준수 상태 표시",
"description": "최신 호스트의 백분율을 표시하는 준수 링 표시"
},
"osDisplayMode": {
"label": "OS 표시 모드",
"description": "운영 체제 배포판 표시 방법 선택",
"option": {
"bars": "가로 막대",
"donut": "도넛 차트"
}
}
},
"error": {
"internalServerError": "PatchMon 데이터를 가져오지 못했습니다"
}
},
"bazarr": {
"name": "Bazarr",
"description": "Bazarr 인스턴스의 누락된 자막 및 상태 개요",
"episodes": "누락된 에피소드",
"movies": "누락된 영화",
"providers": "제공자 문제",
"status": "상태 문제",
"option": {
"showMissingEpisodes": {
"label": "누락된 에피소드 표시",
"description": "누락된 자막이 있는 에피소드 수 표시"
},
"showMissingMovies": {
"label": "누락된 영화 표시",
"description": "누락된 자막이 있는 영화 수 표시"
},
"showProviderIssues": {
"label": "제공자 문제 표시",
"description": "문제가 있는 자막 제공자 수 표시"
},
"showHealthIssues": {
"label": "상태 문제 표시",
"description": "Bazarr 상태 문제 수 표시"
}
},
"error": {
"internalServerError": "Bazarr 데이터를 가져오지 못했습니다"
}
},
"mediaMissing": {
"name": "누락 및 대기 중인 미디어",
"description": "Radarr 및 Sonarr의 누락 및 대기 중인 영화와 에피소드 표시",
"option": {
"showMissing": {
"label": "누락된 항목 표시"
},
"showQueued": {
"label": "대기 중인 항목 표시"
},
"pageSize": {
"label": "페이지당 항목 수"
}
},
"tab": {
"missing": "누락",
"queued": "대기 중"
},
"type": {
"movie": "영화",
"episode": "에피소드"
},
"empty": {
"missing": "누락된 항목 없음",
"queued": "대기 중인 항목 없음",
"noTabsEnabled": "위젯 설정에서 최소한 하나의 탭을 활성화하세요"
},
"timeLeft": "남은 시간"
},
"traefik": {
"name": "Traefik",
"description": "Traefik 라우터, 서비스, 미들웨어 및 진입점 개요",
"option": {
"showTcp": {
"label": "TCP 표시"
},
"showUdp": {
"label": "UDP 표시"
},
"showEntryPoints": {
"label": "진입점 표시"
}
},
"instances": "Traefik 인스턴스",
"versionUnknown": "버전 알 수 없음",
"summary": {
"routers": "라우터",
"entryPoints": "진입점"
},
"resource": {
"routers": "라우터",
"services": "서비스",
"middlewares": "미들웨어"
},
"status": {
"healthy": "정상",
"errors": "{count}개 오류",
"warnings": "{count}개 경고"
},
"error": {
"internalServerError": "Traefik 데이터를 가져오지 못함"
}
}
},
"widgetPreview": {
@@ -4551,11 +4380,11 @@
},
"navbar": {
"items": {
"workshop": "Workshop",
"home": "홈",
"boards": "보드",
"apps": "앱",
"integrations": "통합",
"customWidgets": "사용자 지정 위젯",
"searchEngies": "검색 엔진",
"medias": "미디어",
"users": {
@@ -5694,6 +5523,9 @@
},
"navigationStructure": {
"manage": {
"workshop": {
"label": "Workshop"
},
"label": "관리",
"boards": {
"label": "보드"
+254 -488
View File
@@ -688,211 +688,6 @@
"add": ""
}
},
"customWidget": {
"page": {
"list": {
"title": "",
"noResults": "",
"loading": ""
},
"create": {
"title": "",
"subtitle": ""
},
"edit": {
"title": ""
}
},
"action": {
"create": "",
"import": "",
"save": "",
"delete": "",
"deleteConfirm": "",
"export": "",
"addMapping": "",
"addColumn": "",
"edit": "",
"removeMapping": "",
"removeColumn": "",
"addItem": "",
"removeItem": "",
"addBar": "",
"duplicate": "",
"copyAiPrompt": "",
"enable": "",
"disable": "",
"menu": ""
},
"field": {
"name": "",
"description": "",
"iconUrl": "",
"url": "",
"authType": "",
"headerName": "",
"method": "",
"requestBody": "",
"displayType": "",
"jsonPath": "",
"jsonPathHint": "",
"label": "",
"unit": "",
"mappings": "",
"tablePath": "",
"tablePathHint": "",
"columns": "",
"header": "",
"items": "",
"gridColumns": "",
"cardStyle": "",
"bars": "",
"valuePath": "",
"maxPath": "",
"showPercentage": "",
"barSize": "",
"goodValues": "",
"dotSize": "",
"valueSize": "",
"labelPosition": "",
"kvLayout": "",
"striped": "",
"compact": "",
"maxHeight": "",
"color": "",
"buttonLabel": "",
"buttonColor": "",
"confirmText": "",
"confirmTextHint": "",
"successMessage": "",
"successMessageHint": "",
"enabled": "",
"template": {
"label": "",
"description": ""
}
},
"placeholder": {
"exampleLabel": "",
"exampleLabelShort": "",
"exampleHeader": "",
"exampleUnit": "",
"iconUrl": "",
"url": "",
"headerName": "",
"jsonPath": "",
"tablePath": "",
"columnJsonPath": "",
"valuePath": "",
"maxPath": "",
"goodValues": "",
"color": ""
},
"cardStyleOption": {
"filled": "",
"outline": "",
"subtle": ""
},
"layoutOption": {
"list": "",
"grid": ""
},
"sizeOption": {
"sm": "",
"md": "",
"lg": "",
"xl": ""
},
"labelPositionOption": {
"above": "",
"below": ""
},
"fieldset": {
"general": "",
"connection": "",
"display": ""
},
"displayTypeDescription": {
"singleValue": "",
"keyValue": "",
"table": "",
"statGrid": "",
"progressBars": "",
"statusIndicator": "",
"countGrid": "",
"raw": "",
"actionButton": "",
"customJsx": ""
},
"method": {
"GET": "",
"POST": "",
"PUT": "",
"DELETE": "",
"PATCH": ""
},
"authType": {
"none": "",
"bearer": "",
"basic": "",
"apiKeyHeader": "",
"apiKeyQuery": ""
},
"displayType": {
"singleValue": "",
"keyValue": "",
"table": "",
"statGrid": "",
"progressBars": "",
"statusIndicator": "",
"countGrid": "",
"raw": "",
"actionButton": "",
"customJsx": ""
},
"secret": {
"apiKey": "",
"username": "",
"password": "",
"savedPlaceholder": ""
},
"preview": {
"title": "",
"test": "",
"hint": "",
"rawResponse": ""
},
"notification": {
"created": "",
"updated": "",
"deleted": "",
"imported": "",
"aiPromptCopied": "",
"aiPromptDescription": "",
"aiPromptCopy": "",
"aiPromptNoResponse": "",
"aiPromptCopyError": "",
"createError": "",
"updateError": "",
"importError": "",
"exportError": "",
"duplicated": "",
"duplicateError": "",
"toggleError": "",
"deleteError": "",
"previewError": "",
"executed": "",
"executeError": ""
},
"table": {
"name": "",
"url": "",
"display": ""
},
"widget": {
"disabled": ""
}
},
"integration": {
"page": {
"list": {
@@ -2828,193 +2623,6 @@
"internalServerError": "Nepavyko gauti Paperless-ngx duomenų"
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": {
"name": "",
"description": "",
@@ -3387,35 +2995,6 @@
}
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": {
"name": "RSS srautai",
"description": "Stebėti ir rodyti vieną ar daugiau bendrų RSS, ATOM arba JSON srautų",
@@ -3744,40 +3323,6 @@
"internalServerError": "Nepavyko gauti veikimo duomenų"
}
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": {
"name": "Garso statistika",
"description": "Bibliotekos ir atkūrimo statistika iš Navidrome arba Audiobookshelf",
@@ -3901,26 +3446,6 @@
"unhealthy": ""
}
},
"customApi": {
"name": "",
"description": "",
"option": {
"definitionId": {
"label": ""
},
"refreshInterval": {
"label": "",
"description": ""
}
},
"noDefinition": "",
"definitionNotFound": "",
"noDisplayOutput": "",
"executeConfirm": "",
"executing": "",
"executeSuccess": "",
"executeFailed": ""
},
"beszelSystemTable": {
"name": "Beszel sistemos (lentelė)",
"description": "Visų Beszel stebimų sistemų lentelės vaizdas su rūšiuojamais stulpeliais ir būsenos indikatoriais",
@@ -4171,6 +3696,256 @@
"subtitle": "Docker konteinerių tinklo srautas"
}
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
}
},
"widgetPreview": {
@@ -4551,11 +4326,11 @@
},
"navbar": {
"items": {
"workshop": "Workshop",
"home": "Pagrindinis",
"boards": "Lentos",
"apps": "Programėlės",
"integrations": "Integracijos",
"customWidgets": "",
"searchEngies": "Paieškos sistemos",
"medias": "Medijos",
"users": {
@@ -5694,6 +5469,9 @@
},
"navigationStructure": {
"manage": {
"workshop": {
"label": "Workshop"
},
"label": "Valdyti",
"boards": {
"label": "Lentos"
@@ -5728,18 +5506,6 @@
"label": ""
}
},
"custom-widgets": {
"label": "",
"new": {
"label": ""
},
"edit": {
"label": "",
"flow": {
"label": ""
}
}
},
"users": {
"label": "Vartotojai",
"create": {
+255 -479
View File
@@ -691,206 +691,11 @@
"customWidget": {
"page": {
"list": {
"title": "Pielāgotie logrīki",
"noResults": "Vēl nav pielāgotu logrīku. Izveidojiet pirmo!",
"loading": "Notiek ielāde..."
},
"create": {
"title": "Izveidot pielāgotu logrīku",
"subtitle": "Definējiet API URL, autentifikāciju un to, kā attēlot atbildes datus."
},
"edit": {
"title": "Rediģēt pielāgoto logrīku"
}
},
"action": {
"create": "Izveidot",
"import": "Importēt",
"save": "Saglabāt",
"delete": "Dzēst pielāgoto logrīku",
"deleteConfirm": "Vai tiešām vēlaties dzēst \"{name}\"? Šo darbību nevar atsaukt.",
"export": "Eksportēt",
"addMapping": "Pievienot kartējumu",
"addColumn": "Pievienot kolonnu",
"edit": "Rediģēt",
"removeMapping": "Noņemt kartējumu",
"removeColumn": "Noņemt kolonnu",
"addItem": "",
"removeItem": "",
"addBar": "",
"duplicate": "",
"copyAiPrompt": "",
"enable": "",
"disable": "",
"menu": ""
},
"field": {
"name": "",
"description": "",
"iconUrl": "",
"url": "",
"authType": "",
"headerName": "",
"method": "",
"requestBody": "",
"displayType": "",
"jsonPath": "",
"jsonPathHint": "",
"label": "",
"unit": "",
"mappings": "",
"tablePath": "",
"tablePathHint": "",
"columns": "",
"header": "",
"items": "",
"gridColumns": "",
"cardStyle": "",
"bars": "",
"valuePath": "",
"maxPath": "",
"showPercentage": "",
"barSize": "",
"goodValues": "",
"dotSize": "",
"valueSize": "",
"labelPosition": "",
"kvLayout": "",
"striped": "",
"compact": "",
"maxHeight": "",
"color": "",
"buttonLabel": "",
"buttonColor": "",
"confirmText": "",
"confirmTextHint": "",
"successMessage": "",
"successMessageHint": "",
"enabled": "",
"template": {
"label": "",
"description": ""
}
},
"placeholder": {
"exampleLabel": "",
"exampleLabelShort": "",
"exampleHeader": "",
"exampleUnit": "",
"iconUrl": "",
"url": "",
"headerName": "",
"jsonPath": "",
"tablePath": "",
"columnJsonPath": "",
"valuePath": "",
"maxPath": "",
"goodValues": "",
"color": ""
},
"cardStyleOption": {
"filled": "",
"outline": "",
"subtle": ""
},
"layoutOption": {
"list": "",
"grid": ""
},
"sizeOption": {
"sm": "",
"md": "",
"lg": "",
"xl": ""
},
"labelPositionOption": {
"above": "",
"below": ""
},
"fieldset": {
"general": "",
"connection": "",
"display": ""
},
"displayTypeDescription": {
"singleValue": "",
"keyValue": "",
"table": "",
"statGrid": "",
"progressBars": "",
"statusIndicator": "",
"countGrid": "",
"raw": "",
"actionButton": "",
"customJsx": ""
},
"method": {
"GET": "",
"POST": "",
"PUT": "",
"DELETE": "",
"PATCH": ""
},
"authType": {
"none": "",
"bearer": "",
"basic": "",
"apiKeyHeader": "",
"apiKeyQuery": ""
},
"displayType": {
"singleValue": "",
"keyValue": "",
"table": "",
"statGrid": "",
"progressBars": "",
"statusIndicator": "",
"countGrid": "",
"raw": "",
"actionButton": "",
"customJsx": ""
},
"secret": {
"apiKey": "",
"username": "",
"password": "",
"savedPlaceholder": ""
},
"preview": {
"title": "",
"test": "",
"hint": "",
"rawResponse": ""
},
"notification": {
"created": "",
"updated": "",
"deleted": "",
"imported": "",
"aiPromptCopied": "",
"aiPromptDescription": "",
"aiPromptCopy": "",
"aiPromptNoResponse": "",
"aiPromptCopyError": "",
"createError": "",
"updateError": "",
"importError": "",
"exportError": "",
"duplicated": "",
"duplicateError": "",
"toggleError": "",
"deleteError": "",
"previewError": "",
"executed": "",
"executeError": ""
},
"table": {
"name": "",
"url": "",
"display": ""
},
"widget": {
"disabled": ""
"create": "Izveidot"
}
},
"integration": {
@@ -2828,193 +2633,6 @@
"internalServerError": "Neizdevās iegūt Paperless-ngx datus"
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": {
"name": "",
"description": "",
@@ -3387,35 +3005,6 @@
}
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": {
"name": "",
"description": "",
@@ -3744,40 +3333,6 @@
"internalServerError": "Neizdevās iegūt pieejamības datus"
}
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": {
"name": "Audio statistika",
"description": "Bibliotēkas un atskaņošanas statistika no Navidrome vai Audiobookshelf",
@@ -3901,26 +3456,6 @@
"unhealthy": ""
}
},
"customApi": {
"name": "",
"description": "",
"option": {
"definitionId": {
"label": ""
},
"refreshInterval": {
"label": "",
"description": ""
}
},
"noDefinition": "",
"definitionNotFound": "",
"noDisplayOutput": "",
"executeConfirm": "",
"executing": "",
"executeSuccess": "",
"executeFailed": ""
},
"beszelSystemTable": {
"name": "Beszel sistēmas (Tabula)",
"description": "Tabulas skats visām Beszel uzraudzītajām sistēmām ar kārtojamām kolonnām un statusa indikatoriem",
@@ -4171,6 +3706,256 @@
"subtitle": "Docker konteineru tīkla trafika"
}
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
}
},
"widgetPreview": {
@@ -4551,11 +4336,11 @@
},
"navbar": {
"items": {
"workshop": "Workshop",
"home": "Sākums",
"boards": "Dēļi",
"apps": "Lietotnes",
"integrations": "",
"customWidgets": "",
"searchEngies": "",
"medias": "",
"users": {
@@ -5694,6 +5479,9 @@
},
"navigationStructure": {
"manage": {
"workshop": {
"label": "Workshop"
},
"label": "Pārvaldīt",
"boards": {
"label": "Dēļi"
@@ -5728,18 +5516,6 @@
"label": "Rediģēt"
}
},
"custom-widgets": {
"label": "",
"new": {
"label": ""
},
"edit": {
"label": "",
"flow": {
"label": ""
}
}
},
"users": {
"label": "Lietotāji",
"create": {
+255 -437
View File
@@ -710,16 +710,8 @@
"delete": "Excluir widget personalizado",
"deleteConfirm": "Tem certeza de que deseja excluir \"{name}\"? Esta ação não pode ser desfeita.",
"export": "Exportar",
"addMapping": "Adicionar Mapeamento",
"addColumn": "Adicionar Coluna",
"edit": "Editar",
"removeMapping": "Remover Mapeamento",
"removeColumn": "Remover coluna",
"addItem": "Adicionar Item",
"removeItem": "Remover item",
"addBar": "Adicionar barra",
"duplicate": "Duplicar",
"copyAiPrompt": "Copiar prompt de IA",
"enable": "Habilitado",
"disable": "Desabilitado",
"menu": "Ações"
@@ -727,150 +719,13 @@
"field": {
"name": "Nome",
"description": "Descrição",
"iconUrl": "URL do ícone",
"url": "URL",
"authType": "Tipo de Autenticação",
"headerName": "Nome do parâmetro de cabeçalho/consulta",
"method": "Método",
"requestBody": "Corpo da requisição",
"displayType": "Tipo de exibição",
"jsonPath": "Caminho JSON",
"jsonPathHint": "Usar sintaxe JSONPath para extrair valores, por exemplo, $.data.temperature ou $.items[0].name",
"label": "Rótulo",
"unit": "Unidade",
"mappings": "Mapeamentos",
"tablePath": "Caminho Array JSON",
"tablePathHint": "Caminho para o array na resposta, por exemplo, $.data.items",
"columns": "Colunas",
"header": "Header (cabeçalho)",
"items": "Itens",
"gridColumns": "Colunas da grade",
"cardStyle": "Estilo de cartão",
"bars": "Barras",
"valuePath": "Caminho do valor JSON",
"maxPath": "Caminho do Max Valor JSON",
"showPercentage": "Mostrar porcentagem",
"barSize": "Tamanho da barra",
"goodValues": "Valores bons (separados por vírgula)",
"dotSize": "Tamanho do ponto",
"valueSize": "Tamanho do valor",
"labelPosition": "Posição do rótulo",
"kvLayout": "Layout",
"striped": "Linhas Listradas",
"compact": "Modo Compacto",
"maxHeight": "Altura máxima (px)",
"color": "Cor",
"buttonLabel": "Rótulo do botão",
"buttonColor": "Cor do botão",
"confirmText": "Texto de confirmação",
"confirmTextHint": "Se definido, um diálogo de confirmação irá aparecer antes de executar a solicitação",
"successMessage": "Mensagem de Sucesso",
"successMessageHint": "Mensagem mostrada após execução com sucesso",
"enabled": "Habilitado",
"template": {
"label": "Template JSX",
"description": ""
}
},
"placeholder": {
"exampleLabel": "Temperatura da CPU",
"exampleLabelShort": "Temp CPU",
"exampleHeader": "Nome",
"exampleUnit": "°C",
"iconUrl": "https://...",
"url": "https://api.exemplo.com/br/api/v1/status",
"headerName": "X-API-Key",
"jsonPath": "$.data.value",
"tablePath": "$.data.items",
"columnJsonPath": "$.nome",
"valuePath": "$.data.used",
"maxPath": "$.data.total",
"goodValues": "online, true, up",
"color": "azul"
},
"cardStyleOption": {
"filled": "Preenchido",
"outline": "Contorno",
"subtle": "Sutil"
},
"layoutOption": {
"list": "Lista",
"grid": "Grade"
},
"sizeOption": {
"sm": "Pequeno",
"md": "Médio",
"lg": "Grande",
"xl": "Extra grande"
},
"labelPositionOption": {
"above": "Acima",
"below": "Abaixo"
},
"fieldset": {
"general": "Geral",
"connection": "Conexão com API",
"display": "Configurações de tela"
},
"displayTypeDescription": {
"singleValue": "Exibir um valor extraído com rótulo e unidade",
"keyValue": "Exibir vários valores rotulados lado a lado",
"table": "Exibir linhas de dados em formato de tabela",
"statGrid": "Estatísticas coloridas em uma grade — como Pi-Hole ou Widgets Rápidos",
"progressBars": "Barras de progresso mostrando uso ou conclusão — para disco, memória, quotas",
"statusIndicator": "Pontos de status coloridos mostrando estados online/offline ou de saúde",
"countGrid": "Contadores compactos de número + rótulo em uma grade apertada",
"raw": "Saída JSON impressa para depuração",
"actionButton": "Um botão que aciona uma solicitação quando clicado",
"customJsx": "Layout JSX personalizado usando componentes Mantine na lista branca com ligação completa de dados de API"
},
"method": {
"GET": "GET",
"POST": "POST",
"PUT": "PUT",
"DELETE": "DELETE",
"PATCH": "PATCH"
},
"authType": {
"none": "Nenhum",
"bearer": "Token Bearer",
"basic": "Autenticação Básica",
"apiKeyHeader": "Chave API (Cabeçalho)",
"apiKeyQuery": "Chave API (Consulta)"
},
"displayType": {
"singleValue": "Valor Único",
"keyValue": "Chave-Valor",
"table": "Tabela",
"statGrid": "Grade de Estatísticas",
"progressBars": "Barras de Progresso",
"statusIndicator": "Indicador de Status",
"countGrid": "Grade de Contagem",
"raw": "JSON Bruto",
"actionButton": "Botão de Ação",
"customJsx": "JSX personalizado"
},
"secret": {
"apiKey": "Chave de API / Token",
"username": "Usuário",
"password": "Senha",
"savedPlaceholder": "••••••• (salvo, deixe em branco para manter)"
},
"preview": {
"title": "Pré-visualizar",
"test": "Testar",
"hint": "Clique em Testar para visualizar a resposta da API com sua configuração atual.",
"rawResponse": "Resposta JSON Bruta"
"iconUrl": "URL do ícone"
},
"notification": {
"created": "Widget \"{name}\" criado com sucesso.",
"updated": "Widget \"{name}atualizado com sucesso.",
"deleted": "Widget \"{name}excluído.",
"imported": "Widget importado com sucesso.",
"aiPromptCopied": "Prompt de IA copiado para a área de transferência",
"aiPromptDescription": "Copie um prompt pré-construído para colar qualquer chatbot de AI (ChatGPT, Claude, Gemini...). Ele inclui o esquema completo de widget e a sua resposta de API para que a AI possa gerar uma configuração JSON pronta para importar para você.",
"aiPromptCopy": "Copiar para área de transferência",
"aiPromptNoResponse": "Dica: Execute um teste primeiro para incluir a sua API de resposta no prompt para melhores resultados.",
"aiPromptCopyError": "Falha ao copiar prompt para área de transferência. O seu navegador pode não suportar este recurso.",
"createError": "Falha ao criar widget. Verifique se o endpoint API está acessível.",
"updateError": "Falha ao atualizar o widget. Suas alterações não foram salvas.",
@@ -883,14 +738,6 @@
"previewError": "Falha ao buscar a pré-visualização. Verifique a URL e tente novamente.",
"executed": "Ação executada com sucesso.",
"executeError": "A ação falhou: {error}"
},
"table": {
"name": "Nome",
"url": "URL",
"display": "Exibição"
},
"widget": {
"disabled": "Este widget está desabilitado"
}
},
"integration": {
@@ -2828,193 +2675,6 @@
"internalServerError": "Falha ao buscar dados do Paperless-ngx"
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": {
"name": "Estatísticas do Servidor Immich",
"description": "Informações sobre sua instância do Immich",
@@ -3387,35 +3047,6 @@
}
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": {
"name": "Feeds RSS",
"description": "Monitora e exibe um ou mais feeds RSS, ATOM ou JSON genéricos",
@@ -3744,40 +3375,6 @@
"internalServerError": "Falha ao buscar dados de tempo de atividade"
}
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": {
"name": "Estatísticas de áudio",
"description": "Estatísticas de biblioteca e reprodução do Navidrome ou Audiobookshelf",
@@ -3901,26 +3498,6 @@
"unhealthy": "Não saudável"
}
},
"customApi": {
"name": "API personalizada",
"description": "Exibir dados de qualquer API externa com configuração personalizada.",
"option": {
"definitionId": {
"label": "ID de definição"
},
"refreshInterval": {
"label": "Intervalo de atualização",
"description": "Com que frequência reobter dados da API (em segundos)"
}
},
"noDefinition": "Nenhuma definição selecionada",
"definitionNotFound": "Definição do widget não encontrada. Ela pode ter sido excluída.",
"noDisplayOutput": "Nenhuma saída de exibição",
"executeConfirm": "Tem certeza de que deseja executar esta ação?",
"executing": "Executando...",
"executeSuccess": "Ação executada com sucesso",
"executeFailed": "Ação falhou. Verifique a configuração do widget."
},
"beszelSystemTable": {
"name": "Sistemas Beszel (Tabela)",
"description": "Visualização em tabela de todos os sistemas monitorados pelo Beszel com colunas classificáveis e indicadores de status",
@@ -4171,6 +3748,256 @@
"subtitle": "Tráfego de rede dos contêineres Docker"
}
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
}
},
"widgetPreview": {
@@ -4551,11 +4378,11 @@
},
"navbar": {
"items": {
"workshop": "Workshop",
"home": "Início",
"boards": "Placas",
"apps": "Aplicativos",
"integrations": "Integrações",
"customWidgets": "Widgets Personalizados",
"searchEngies": "Mecanismos de busca",
"medias": "Mídias",
"users": {
@@ -5694,6 +5521,9 @@
},
"navigationStructure": {
"manage": {
"workshop": {
"label": "Workshop"
},
"label": "Gerenciar",
"boards": {
"label": "Placas"
@@ -5728,18 +5558,6 @@
"label": "Editar"
}
},
"custom-widgets": {
"label": "Widgets personalizados",
"new": {
"label": "Novo"
},
"edit": {
"label": "Editar",
"flow": {
"label": "Fluxo"
}
}
},
"users": {
"label": "Usuários",
"create": {
+254 -488
View File
@@ -688,211 +688,6 @@
"add": ""
}
},
"customWidget": {
"page": {
"list": {
"title": "",
"noResults": "",
"loading": ""
},
"create": {
"title": "",
"subtitle": ""
},
"edit": {
"title": ""
}
},
"action": {
"create": "",
"import": "",
"save": "",
"delete": "",
"deleteConfirm": "",
"export": "",
"addMapping": "",
"addColumn": "",
"edit": "",
"removeMapping": "",
"removeColumn": "",
"addItem": "",
"removeItem": "",
"addBar": "",
"duplicate": "",
"copyAiPrompt": "",
"enable": "",
"disable": "",
"menu": ""
},
"field": {
"name": "",
"description": "",
"iconUrl": "",
"url": "",
"authType": "",
"headerName": "",
"method": "",
"requestBody": "",
"displayType": "",
"jsonPath": "",
"jsonPathHint": "",
"label": "",
"unit": "",
"mappings": "",
"tablePath": "",
"tablePathHint": "",
"columns": "",
"header": "",
"items": "",
"gridColumns": "",
"cardStyle": "",
"bars": "",
"valuePath": "",
"maxPath": "",
"showPercentage": "",
"barSize": "",
"goodValues": "",
"dotSize": "",
"valueSize": "",
"labelPosition": "",
"kvLayout": "",
"striped": "",
"compact": "",
"maxHeight": "",
"color": "",
"buttonLabel": "",
"buttonColor": "",
"confirmText": "",
"confirmTextHint": "",
"successMessage": "",
"successMessageHint": "",
"enabled": "",
"template": {
"label": "",
"description": ""
}
},
"placeholder": {
"exampleLabel": "",
"exampleLabelShort": "",
"exampleHeader": "",
"exampleUnit": "",
"iconUrl": "",
"url": "",
"headerName": "",
"jsonPath": "",
"tablePath": "",
"columnJsonPath": "",
"valuePath": "",
"maxPath": "",
"goodValues": "",
"color": ""
},
"cardStyleOption": {
"filled": "",
"outline": "",
"subtle": ""
},
"layoutOption": {
"list": "",
"grid": ""
},
"sizeOption": {
"sm": "",
"md": "",
"lg": "",
"xl": ""
},
"labelPositionOption": {
"above": "",
"below": ""
},
"fieldset": {
"general": "",
"connection": "",
"display": ""
},
"displayTypeDescription": {
"singleValue": "",
"keyValue": "",
"table": "",
"statGrid": "",
"progressBars": "",
"statusIndicator": "",
"countGrid": "",
"raw": "",
"actionButton": "",
"customJsx": ""
},
"method": {
"GET": "",
"POST": "",
"PUT": "",
"DELETE": "",
"PATCH": ""
},
"authType": {
"none": "",
"bearer": "",
"basic": "",
"apiKeyHeader": "",
"apiKeyQuery": ""
},
"displayType": {
"singleValue": "",
"keyValue": "",
"table": "",
"statGrid": "",
"progressBars": "",
"statusIndicator": "",
"countGrid": "",
"raw": "",
"actionButton": "",
"customJsx": ""
},
"secret": {
"apiKey": "",
"username": "",
"password": "",
"savedPlaceholder": ""
},
"preview": {
"title": "",
"test": "",
"hint": "",
"rawResponse": ""
},
"notification": {
"created": "",
"updated": "",
"deleted": "",
"imported": "",
"aiPromptCopied": "",
"aiPromptDescription": "",
"aiPromptCopy": "",
"aiPromptNoResponse": "",
"aiPromptCopyError": "",
"createError": "",
"updateError": "",
"importError": "",
"exportError": "",
"duplicated": "",
"duplicateError": "",
"toggleError": "",
"deleteError": "",
"previewError": "",
"executed": "",
"executeError": ""
},
"table": {
"name": "",
"url": "",
"display": ""
},
"widget": {
"disabled": ""
}
},
"integration": {
"page": {
"list": {
@@ -2828,193 +2623,6 @@
"internalServerError": ""
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": {
"name": "",
"description": "",
@@ -3387,35 +2995,6 @@
}
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": {
"name": "Feeds RSS",
"description": "Monitora e exibe um ou mais feeds RSS, ATOM ou JSON genéricos",
@@ -3744,40 +3323,6 @@
"internalServerError": ""
}
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": {
"name": "",
"description": "",
@@ -3901,26 +3446,6 @@
"unhealthy": ""
}
},
"customApi": {
"name": "",
"description": "",
"option": {
"definitionId": {
"label": ""
},
"refreshInterval": {
"label": "",
"description": ""
}
},
"noDefinition": "",
"definitionNotFound": "",
"noDisplayOutput": "",
"executeConfirm": "",
"executing": "",
"executeSuccess": "",
"executeFailed": ""
},
"beszelSystemTable": {
"name": "Sistemas Beszel (Tabela)",
"description": "Visualização em tabela de todos os sistemas monitorados pelo Beszel com colunas classificáveis e indicadores de status",
@@ -4171,6 +3696,256 @@
"subtitle": "Tráfego de rede dos contêineres Docker"
}
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
}
},
"widgetPreview": {
@@ -4551,11 +4326,11 @@
},
"navbar": {
"items": {
"workshop": "Workshop",
"home": "Início",
"boards": "Painéis",
"apps": "Aplicativos",
"integrations": "Integrações",
"customWidgets": "",
"searchEngies": "Mecanismos de busca",
"medias": "Mídias",
"users": {
@@ -5694,6 +5469,9 @@
},
"navigationStructure": {
"manage": {
"workshop": {
"label": "Workshop"
},
"label": "Gerenciar",
"boards": {
"label": "Painéis"
@@ -5728,18 +5506,6 @@
"label": "Editar"
}
},
"custom-widgets": {
"label": "",
"new": {
"label": ""
},
"edit": {
"label": "",
"flow": {
"label": ""
}
}
},
"users": {
"label": "Usuários",
"create": {
+254 -488
View File
@@ -688,211 +688,6 @@
"add": "Pridajte aplikáciu"
}
},
"customWidget": {
"page": {
"list": {
"title": "Vlastné widgety",
"noResults": "Zatiaľ žiadne vlastné widgety. Vytvorte svoj prvý!",
"loading": "Nahrávam..."
},
"create": {
"title": "Vytvoriť vlastný widget",
"subtitle": "Definujte URL API, autentifikáciu a spôsob zobrazenia údajov odpovede."
},
"edit": {
"title": "Upraviť vlastný widget"
}
},
"action": {
"create": "Vytvoriť",
"import": "Importovať",
"save": "Uložiť",
"delete": "Odstrániť vlastný widget",
"deleteConfirm": "Naozaj chcete odstrániť \"{name}\"? Táto akcia sa nedá vrátiť späť.",
"export": "Exportovať",
"addMapping": "Pridať mapovanie",
"addColumn": "Pridať stĺpec",
"edit": "Upraviť",
"removeMapping": "Odstrániť mapovanie",
"removeColumn": "Odstrániť stĺpec",
"addItem": "Pridať položku",
"removeItem": "Odstrániť položku",
"addBar": "Pridať pruh",
"duplicate": "Duplikovať",
"copyAiPrompt": "Kopírovať AI prompt",
"enable": "Povoliť",
"disable": "Zakázať",
"menu": "Akcie"
},
"field": {
"name": "Názov",
"description": "Popis",
"iconUrl": "URL ikony",
"url": "URL",
"authType": "Typ autentifikácie",
"headerName": "Názov hlavičky/parametra dotazu",
"method": "Metóda",
"requestBody": "Telo požiadavky",
"displayType": "Typ zobrazenia",
"jsonPath": "JSON cesta",
"jsonPathHint": "Použite syntax JSONPath na extrakciu hodnôt, napr. $.data.teplota alebo $.polozky[0].nazov",
"label": "Označenie",
"unit": "Jednotka",
"mappings": "Mapovania",
"tablePath": "JSON cesta poľa",
"tablePathHint": "Cesta k poľu v odpovedi, napr. $.data.polozky",
"columns": "Stĺpce",
"header": "Hlavička",
"items": "Položky",
"gridColumns": "Stĺpce mriežky",
"cardStyle": "Štýl karty",
"bars": "Pruhy",
"valuePath": "JSON cesta hodnoty",
"maxPath": "JSON cesta maximálnej hodnoty",
"showPercentage": "Zobraziť percentá",
"barSize": "Veľkosť pruhu",
"goodValues": "Dobré hodnoty (oddelené čiarkou)",
"dotSize": "Veľkosť bodky",
"valueSize": "Veľkosť hodnoty",
"labelPosition": "Pozícia označenia",
"kvLayout": "Rozloženie",
"striped": "Pruhované riadky",
"compact": "Kompaktný režim",
"maxHeight": "Max. výška (px)",
"color": "Farba",
"buttonLabel": "Označenie tlačidla",
"buttonColor": "Farba tlačidla",
"confirmText": "Text potvrdenia",
"confirmTextHint": "Ak je nastavený, pred vykonaním požiadavky sa zobrazí dialóg potvrdenia",
"successMessage": "Správa o úspechu",
"successMessageHint": "Správa zobrazená po úspešnom vykonaní",
"enabled": "Povolené",
"template": {
"label": "JSX šablóna",
"description": "Mantine JSX šablóna. Prístup k poliam odpovede API cez dátové väzby (napr. data.nazov). Používajte iba whitelistované komponenty. Zakázané: constructor, __proto__, eval, Function, window, document."
}
},
"placeholder": {
"exampleLabel": "Teplota CPU",
"exampleLabelShort": "Teplota CPU",
"exampleHeader": "Názov",
"exampleUnit": "°C",
"iconUrl": "https://...",
"url": "https://api.priklad.com/api/v1/status",
"headerName": "X-API-Key",
"jsonPath": "$.data.hodnota",
"tablePath": "$.data.polozky",
"columnJsonPath": "$.nazov",
"valuePath": "$.data.pouzite",
"maxPath": "$.data.celkom",
"goodValues": "online, true, up",
"color": "modrá"
},
"cardStyleOption": {
"filled": "Vyplnené",
"outline": "Obrys",
"subtle": "Jemný"
},
"layoutOption": {
"list": "Zoznam",
"grid": "Mriežka"
},
"sizeOption": {
"sm": "Malé",
"md": "Stredné",
"lg": "Veľké",
"xl": "Extra veľké"
},
"labelPositionOption": {
"above": "Nad",
"below": "Pod"
},
"fieldset": {
"general": "Všeobecné",
"connection": "Pripojenie API",
"display": "Konfigurácia zobrazenia"
},
"displayTypeDescription": {
"singleValue": "Zobraziť jednu extrahovanú hodnotu s označením a jednotkou",
"keyValue": "Zobraziť viacero označených hodnôt vedľa seba",
"table": "Zobraziť riadky údajov vo formáte tabuľky",
"statGrid": "Farebné karty štatistík v mriežke – ako widgety Pi-Hole alebo Speedtest",
"progressBars": "Pruhy postupu zobrazujúce využitie alebo dokončenie – pre disk, pamäť, kvóty",
"statusIndicator": "Farebné bodky stavu zobrazujúce online/offline alebo stavy zdravia",
"countGrid": "Kompaktné počítadlá číslo + označenie v tesnej mriežke",
"raw": "Prehľadne formátovaný JSON výstup pre ladenie",
"actionButton": "Tlačidlo, ktoré po kliknutí spustí požiadavku",
"customJsx": "Vlastné rozloženie JSX pomocou whitelistovaných komponentov Mantine s plnou väzbou API dát"
},
"method": {
"GET": "GET",
"POST": "POST",
"PUT": "PUT",
"DELETE": "DELETE",
"PATCH": "PATCH"
},
"authType": {
"none": "Žiadna",
"bearer": "Bearer token",
"basic": "Basic Auth",
"apiKeyHeader": "API kľúč (hlavička)",
"apiKeyQuery": "API kľúč (dotaz)"
},
"displayType": {
"singleValue": "Jedna hodnota",
"keyValue": "Kľúč-hodnota",
"table": "Tabuľka",
"statGrid": "Mriežka štatistík",
"progressBars": "Pruhy postupu",
"statusIndicator": "Indikátor stavu",
"countGrid": "Mriežka počtu",
"raw": "Surové JSON",
"actionButton": "Akčné tlačidlo",
"customJsx": "Vlastné JSX"
},
"secret": {
"apiKey": "API kľúč / token",
"username": "Používateľské meno",
"password": "Heslo",
"savedPlaceholder": "••••••• (uložené, ponechajte prázdne pre zachovanie)"
},
"preview": {
"title": "Náhľad",
"test": "Test",
"hint": "Kliknite na Test pre náhľad odpovede API s vašou aktuálnou konfiguráciou.",
"rawResponse": "Surová JSON odpoveď"
},
"notification": {
"created": "Widget \"{name}\" bol úspešne vytvorený.",
"updated": "Widget \"{name}\" bol úspešne aktualizovaný.",
"deleted": "Widget \"{name}\" bol odstránený.",
"imported": "",
"aiPromptCopied": "AI prompt skopírovaný do schránky",
"aiPromptDescription": "Skopírujte pripravený prompt a vložte ho do akéhokoľvek AI chatbota (ChatGPT, Claude, Gemini...). Obsahuje úplnú schému widgetu a vašu odpoveď API, aby AI mohla vygenerovať pripravenú JSON konfiguráciu na import.",
"aiPromptCopy": "Skopírovať do schránky",
"aiPromptNoResponse": "Tip: Najprv spustite test, aby ste zahrnuli odpoveď API do výzvy pre lepšie výsledky.",
"aiPromptCopyError": "Nepodarilo sa skopírovať výzvu do schránky. Váš prehliadač možno nepodporuje túto funkciu.",
"createError": "Nepodarilo sa vytvoriť widget. Skontrolujte, či je váš API endpoint dostupný.",
"updateError": "Nepodarilo sa aktualizovať widget. Vaše zmeny neboli uložené.",
"importError": "Nepodarilo sa importovať widget. Uistite sa, že súbor je platný JSON export vlastného widgetu.",
"exportError": "",
"duplicated": "",
"duplicateError": "",
"toggleError": "",
"deleteError": "",
"previewError": "",
"executed": "",
"executeError": ""
},
"table": {
"name": "",
"url": "",
"display": ""
},
"widget": {
"disabled": ""
}
},
"integration": {
"page": {
"list": {
@@ -2828,193 +2623,6 @@
"internalServerError": "Nepodarilo sa načítať údaje Paperless-ngx"
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": {
"name": "",
"description": "",
@@ -3387,35 +2995,6 @@
}
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": {
"name": "RSS kanály",
"description": "Monitorujte a zobrazujte jeden alebo viac všeobecných informačných kanálov RSS, ATOM alebo JSON",
@@ -3744,40 +3323,6 @@
"internalServerError": "Nepodarilo sa načítať údaje o dostupnosti"
}
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": {
"name": "Audio štatistiky",
"description": "Štatistiky knižnice a prehrávania z Navidrome alebo Audiobookshelf",
@@ -3901,26 +3446,6 @@
"unhealthy": ""
}
},
"customApi": {
"name": "",
"description": "",
"option": {
"definitionId": {
"label": ""
},
"refreshInterval": {
"label": "",
"description": ""
}
},
"noDefinition": "",
"definitionNotFound": "",
"noDisplayOutput": "",
"executeConfirm": "",
"executing": "",
"executeSuccess": "",
"executeFailed": ""
},
"beszelSystemTable": {
"name": "Beszel systémy (tabuľka)",
"description": "Tabuľkový pohľad všetkých systémov monitorovaných Beszel s triediteľnými stĺpcami a indikátormi stavu",
@@ -4171,6 +3696,256 @@
"subtitle": "Sieťová prevádzka Docker kontajnerov"
}
}
},
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
}
},
"widgetPreview": {
@@ -4551,11 +4326,11 @@
},
"navbar": {
"items": {
"workshop": "Workshop",
"home": "Domovská stránka",
"boards": "Dosky",
"apps": "Aplikácie",
"integrations": "Integrácie",
"customWidgets": "",
"searchEngies": "Vyhľadávače",
"medias": "Médiá",
"users": {
@@ -5694,6 +5469,9 @@
},
"navigationStructure": {
"manage": {
"workshop": {
"label": "Workshop"
},
"label": "Spravovať",
"boards": {
"label": "Dosky"
@@ -5728,18 +5506,6 @@
"label": "Upraviť"
}
},
"custom-widgets": {
"label": "",
"new": {
"label": ""
},
"edit": {
"label": "",
"flow": {
"label": ""
}
}
},
"users": {
"label": "Používatelia",
"create": {
+254 -488
View File
@@ -688,211 +688,6 @@
"add": "Bir uygulama ekle"
}
},
"customWidget": {
"page": {
"list": {
"title": "Özel Widget'lar",
"noResults": "Henüz özel widget yok. İlk widget'ınızı oluşturun!",
"loading": "Yükleniyor..."
},
"create": {
"title": "Özel Widget Oluştur",
"subtitle": "API URL'sini, kimlik doğrulamasını ve yanıt verilerinin nasıl görüntüleneceğini tanımlayın."
},
"edit": {
"title": "Özel Widget'ı Düzenle"
}
},
"action": {
"create": "Oluştur",
"import": "İçe aktar",
"save": "Kaydet",
"delete": "Özel Widget'ı Sil",
"deleteConfirm": "“{name}” adlı widget'ı silmek istediğinizden emin misiniz? Bu işlem geri alınamaz.",
"export": "Dışa aktar",
"addMapping": "Eşleme Ekle",
"addColumn": "Sütun Ekle",
"edit": "Düzenle",
"removeMapping": "Eşlemeyi kaldır",
"removeColumn": "Sütunu kaldır",
"addItem": "Öğe Ekle",
"removeItem": "Öğeyi kaldır",
"addBar": "Çubuk Ekle",
"duplicate": "Çoğalt",
"copyAiPrompt": "Yapay zekâ istemini kopyala",
"enable": "Etkinleştir",
"disable": "Devre dışı bırak",
"menu": "Eylemler"
},
"field": {
"name": "Ad",
"description": "Açıklama",
"iconUrl": "Simge URL'si",
"url": "URL",
"authType": "Kimlik Doğrulama Türü",
"headerName": "Üst Bilgi/Sorgu Parametresi Adı",
"method": "Yöntem",
"requestBody": "İstek Gövdesi",
"displayType": "Görüntüleme Türü",
"jsonPath": "JSON Yolu",
"jsonPathHint": "Değerleri ayıklamak için JSONPath söz dizimini kullanın; ör. $.data.temperature veya $.items[0].name",
"label": "Etiket",
"unit": "Birim",
"mappings": "Eşlemeler",
"tablePath": "Dizi JSON Yolu",
"tablePathHint": "Yanıttaki dizinin yolu; ör. $.data.items",
"columns": "Sütunlar",
"header": "Başlık",
"items": "Öğeler",
"gridColumns": "Izgara Sütunları",
"cardStyle": "Kart Stili",
"bars": "Çubuklar",
"valuePath": "Değer JSON Yolu",
"maxPath": "En Yüksek Değer JSON Yolu",
"showPercentage": "Yüzdeyi Göster",
"barSize": "Çubuk Boyutu",
"goodValues": "İyi Değerler (virgülle ayrılmış)",
"dotSize": "Nokta Boyutu",
"valueSize": "Değer Boyutu",
"labelPosition": "Etiket Konumu",
"kvLayout": "Düzen",
"striped": "Şeritli Satırlar",
"compact": "Kompakt Mod",
"maxHeight": "En Fazla Yükseklik (px)",
"color": "Renk",
"buttonLabel": "Düğme Etiketi",
"buttonColor": "Düğme Rengi",
"confirmText": "Onay Metni",
"confirmTextHint": "Ayarlanırsa istek yürütülmeden önce bir onay iletişim kutusu gösterilir",
"successMessage": "Başarı Mesajı",
"successMessageHint": "Başarılı yürütmeden sonra gösterilecek mesaj",
"enabled": "Etkin",
"template": {
"label": "JSX Şablonu",
"description": "Mantine JSX şablonu. API yanıt alanlarına veri bağlamalarıyla (ör. data.name) erişin. Yalnızca izin verilen bileşenleri kullanın. Yasak: constructor, __proto__, eval, Function, window, document."
}
},
"placeholder": {
"exampleLabel": "CPU Sıcaklığı",
"exampleLabelShort": "CPU Sıcaklığı",
"exampleHeader": "Ad",
"exampleUnit": "°C",
"iconUrl": "https://...",
"url": "https://api.example.com/api/v1/status",
"headerName": "X-API-Key",
"jsonPath": "$.data.value",
"tablePath": "$.data.items",
"columnJsonPath": "$.name",
"valuePath": "$.data.used",
"maxPath": "$.data.total",
"goodValues": "online, true, up",
"color": "mavi"
},
"cardStyleOption": {
"filled": "Dolu",
"outline": "Çerçeveli",
"subtle": "Hafif"
},
"layoutOption": {
"list": "Liste",
"grid": "Izgara"
},
"sizeOption": {
"sm": "Küçük",
"md": "Orta",
"lg": "Büyük",
"xl": "Çok Büyük"
},
"labelPositionOption": {
"above": "Üstte",
"below": "Altta"
},
"fieldset": {
"general": "Genel",
"connection": "API Bağlantısı",
"display": "Görüntüleme Yapılandırması"
},
"displayTypeDescription": {
"singleValue": "Ayıklanan tek bir değeri etiket ve birimle gösterir",
"keyValue": "Birden fazla etiketli değeri yan yana gösterir",
"table": "Veri satırlarını tablo biçiminde gösterir",
"statGrid": "Pi-hole veya Speedtest widget'ları gibi, ızgara içinde renkli istatistik kartları gösterir",
"progressBars": "Disk, bellek veya kotalar için kullanımı ya da tamamlanmayı gösteren ilerleme çubukları",
"statusIndicator": "Çevrimiçi/çevrimdışı ya da sağlık durumlarını gösteren renkli durum noktaları",
"countGrid": "Sıkı bir ızgarada kompakt sayı ve etiket sayaçları",
"raw": "Hata ayıklama için okunaklı biçimlendirilmiş JSON çıktısı",
"actionButton": "Tıklandığında istek başlatan bir düğme",
"customJsx": "Tam API veri bağlamasıyla izin verilen Mantine bileşenlerini kullanan özel JSX düzeni"
},
"method": {
"GET": "GET",
"POST": "POST",
"PUT": "PUT",
"DELETE": "DELETE",
"PATCH": "PATCH"
},
"authType": {
"none": "Yok",
"bearer": "Bearer Token",
"basic": "Temel Kimlik Doğrulama",
"apiKeyHeader": "API Anahtarı (Üst Bilgi)",
"apiKeyQuery": "API Anahtarı (Sorgu)"
},
"displayType": {
"singleValue": "Tek Değer",
"keyValue": "Anahtar-Değer",
"table": "Tablo",
"statGrid": "İstatistik Izgarası",
"progressBars": "İlerleme Çubukları",
"statusIndicator": "Durum Göstergesi",
"countGrid": "Sayaç Izgarası",
"raw": "Ham JSON",
"actionButton": "Eylem Düğmesi",
"customJsx": "Özel JSX"
},
"secret": {
"apiKey": "API Anahtarı / Token",
"username": "Kullanıcı adı",
"password": "Parola",
"savedPlaceholder": "••••••• (kaydedildi, korumak için boş bırakın)"
},
"preview": {
"title": "Önizleme",
"test": "Test Et",
"hint": "Geçerli yapılandırmanızla API yanıtını önizlemek için Test Et'e tıklayın.",
"rawResponse": "Ham JSON yanıtı"
},
"notification": {
"created": "“{name}” widget'ı başarıyla oluşturuldu.",
"updated": "“{name}” widget'ı başarıyla güncellendi.",
"deleted": "“{name}” widget'ı silindi.",
"imported": "Widget başarıyla içe aktarıldı.",
"aiPromptCopied": "Yapay zekâ istemi panoya kopyalandı",
"aiPromptDescription": "Herhangi bir yapay zekâ sohbet botuna (ChatGPT, Claude, Gemini...) yapıştırmak üzere önceden hazırlanmış bir istemi kopyalayın. İstem, yapay zekânın içe aktarmaya hazır bir JSON yapılandırması oluşturabilmesi için widget şemasının tamamını ve API yanıtınızı içerir.",
"aiPromptCopy": "Panoya kopyala",
"aiPromptNoResponse": "İpucu: Daha iyi sonuçlar için önce bir test çalıştırarak API yanıtınızı isteme ekleyin.",
"aiPromptCopyError": "İstem panoya kopyalanamadı. Tarayıcınız bu özelliği desteklemiyor olabilir.",
"createError": "Widget oluşturulamadı. API uç noktanızın erişilebilir olduğunu kontrol edin.",
"updateError": "Widget güncellenemedi. Değişiklikleriniz kaydedilmedi.",
"importError": "Widget içe aktarılamadı. Dosyanın geçerli bir özel widget JSON dışa aktarımı olduğundan emin olun.",
"exportError": "Widget dışa aktarılamadı.",
"duplicated": "“{name}” widget'ı çoğaltıldı.",
"duplicateError": "Widget çoğaltılamadı.",
"toggleError": "Widget durumu değiştirilemedi.",
"deleteError": "Widget silinemedi.",
"previewError": "Önizleme alınamadı. URL'yi kontrol edip yeniden deneyin.",
"executed": "Eylem başarıyla yürütüldü.",
"executeError": "Eylem başarısız oldu: {error}"
},
"table": {
"name": "Ad",
"url": "URL",
"display": "Görüntüleme"
},
"widget": {
"disabled": "Bu widget devre dışı"
}
},
"integration": {
"page": {
"list": {
@@ -2828,193 +2623,6 @@
"internalServerError": "Paperless-ngx verileri alınamadı"
}
},
"patchmon": {
"name": "PatchMon",
"description": "PatchMon'daki ana makine yama durumunun genel görünümü",
"title": "PatchMon İstatistikleri",
"totalHosts": "Toplam Ana Makine",
"hostsNeedingUpdates": "Güncelleme Gerekiyor",
"securityUpdates": "Güvenlik Güncellemeleri",
"upToDateHosts": "Güncel Ana Makineler",
"hostsWithSecurityUpdates": "Güvenlik Güncellemesi Olan Ana Makineler",
"recentUpdates24h": "Güncellemeler (24 sa.)",
"totalOutdatedPackages": "Güncel Olmayan Paketler",
"totalRepos": "Depolar",
"osDistribution": "İşletim Sistemi Dağılımı",
"compliance": "Yama Uyumluluğu",
"complianceRatio": "{upToDate} / {total}",
"lastUpdated": "Güncellendi: {time}",
"option": {
"showTotalHosts": {
"label": "Toplam ana makine sayısını göster",
"description": "İzlenen toplam ana makine sayısını gösterir"
},
"showHostsNeedingUpdates": {
"label": "Güncelleme gereken ana makineleri göster",
"description": "En az bir güncel olmayan paketi bulunan ana makineleri gösterir"
},
"showSecurityUpdates": {
"label": "Güvenlik güncellemelerini göster",
"description": "Kullanılabilir toplam güvenlik güncellemesi sayısını gösterir"
},
"showUpToDateHosts": {
"label": "Güncel ana makineleri göster",
"description": "Güncel olmayan paketi bulunmayan ana makineleri gösterir"
},
"showHostsWithSecurityUpdates": {
"label": "Güvenlik güncellemesi olan ana makineleri göster",
"description": "Güvenlik yaması gereken ana makineleri gösterir"
},
"showRecentUpdates24h": {
"label": "Son güncellemeleri göster (24 sa.)",
"description": "Son 24 saatte uygulanan güncelleme sayısını gösterir"
},
"showTotalOutdatedPackages": {
"label": "Güncel olmayan paketleri göster",
"description": "Tüm ana makinelerdeki güncel olmayan paketlerin toplam sayısını gösterir"
},
"showTotalRepos": {
"label": "Depoları göster",
"description": "İzlenen etkin depo sayısını gösterir"
},
"enableThresholdColors": {
"label": "Eşik renklerini etkinleştir",
"description": "İstatistik değerlerini önem düzeyi ön ayarlarına göre yeşil, sarı veya kırmızı renklendirir"
},
"useCustomThresholds": {
"label": "Gelişmiş eşikler",
"description": "Her istatistik için uyarı ve kritik eşikleri mutlak sayılarla veya toplam ana makine yüzdesiyle özelleştirin"
},
"thresholdMode": {
"option": {
"absolute": "Mutlak sayı",
"percent": "Toplam ana makinelerin yüzdesi"
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "Güncelleme gereksinimi eşik modu",
"description": "Güncelleme gerekenlerin sayısını mutlak değer veya toplam ana makinelerin yüzdesi olarak karşılaştırır"
},
"hostsNeedingUpdatesWarningAt": {
"label": "Güncelleme gereksinimi uyarı eşiği",
"description": "Değer bu eşiğe ulaştığında sarı renge geçer"
},
"hostsNeedingUpdatesCriticalAt": {
"label": "Güncelleme gereksinimi kritik eşiği",
"description": "Değer bu eşiğe ulaştığında kırmızı renge geçer"
},
"securityUpdatesThresholdMode": {
"label": "Güvenlik güncellemeleri eşik modu",
"description": "Güvenlik güncellemesi sayısını mutlak değer veya toplam ana makinelerin yüzdesi olarak karşılaştırır"
},
"securityUpdatesWarningAt": {
"label": "Güvenlik güncellemeleri uyarı eşiği",
"description": "Değer bu eşiğe ulaştığında sarı renge geçer"
},
"securityUpdatesCriticalAt": {
"label": "Güvenlik güncellemeleri kritik eşiği",
"description": "Değer bu eşiğe ulaştığında kırmızı renge geçer"
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "Güvenlik güncellemesi olan ana makineler için eşik modu",
"description": "Ana makine sayısını mutlak değer veya toplam ana makinelerin yüzdesi olarak karşılaştırır"
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "Güvenlik güncellemesi olan ana makineler için uyarı eşiği",
"description": "Değer bu eşiğe ulaştığında sarı renge geçer"
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "Güvenlik güncellemesi olan ana makineler için kritik eşik",
"description": "Değer bu eşiğe ulaştığında kırmızı renge geçer"
},
"upToDateHostsThresholdMode": {
"label": "Güncel ana makineler için eşik modu",
"description": "Güncel ana makine sayısını mutlak değer veya toplam ana makinelerin yüzdesi olarak karşılaştırır"
},
"upToDateHostsWarningAt": {
"label": "Güncel ana makineler için uyarı eşiği",
"description": "Değer bu eşikte veya üzerinde, ancak tam kapsamanın altındaysa sarı renge geçer"
},
"upToDateHostsCriticalAt": {
"label": "Güncel ana makineler için kritik eşik",
"description": "Değer bu eşiğin altına düştüğünde kırmızı renge geçer"
},
"totalOutdatedPackagesThresholdMode": {
"label": "Güncel olmayan paketler için eşik modu",
"description": "Güncel olmayan paketlerin sayısını mutlak değer veya toplam ana makinelerin yüzdesi olarak karşılaştırır"
},
"totalOutdatedPackagesWarningAt": {
"label": "Güncel olmayan paketler için uyarı eşiği",
"description": "Değer bu eşiğe ulaştığında sarı renge geçer"
},
"totalOutdatedPackagesCriticalAt": {
"label": "Güncel olmayan paketler için kritik eşik",
"description": "Değer bu eşiğe ulaştığında kırmızı renge geçer"
},
"showOsDistribution": {
"label": "İşletim sistemi dağılımını göster",
"description": "İzlenen ana makinelerin işletim sistemine göre dağılımını gösterir"
},
"osDistributionLimit": {
"label": "İşletim sistemi dağılımı sınırı",
"description": "Gösterilecek en fazla işletim sistemi sayısı",
"option": {
"3": "İlk 3",
"5": "İlk 5",
"10": "İlk 10",
"all": "Tümü"
}
},
"showOsVersion": {
"label": "İşletim sistemi sürümünü göster",
"description": "Mevcut olduğunda işletim sistemi sürümünü her dağılım etiketine ekler"
},
"showComplianceHero": {
"label": "Uyumluluk özetini göster",
"description": "Güncel ana makinelerin yüzdesini gösteren bir uyumluluk halkası görüntüler"
},
"osDisplayMode": {
"label": "İşletim sistemi görüntüleme modu",
"description": "İşletim sistemi dağılımının nasıl gösterileceğini seçin",
"option": {
"bars": "Yatay çubuklar",
"donut": "Halka grafik"
}
}
},
"error": {
"internalServerError": "PatchMon verileri alınamadı"
}
},
"bazarr": {
"name": "Bazarr",
"description": "Bazarr örneğinizdeki eksik altyazıların ve sağlık durumunun genel görünümü",
"episodes": "Eksik Bölümler",
"movies": "Eksik Filmler",
"providers": "Sağlayıcı Sorunları",
"status": "Sağlık Sorunları",
"option": {
"showMissingEpisodes": {
"label": "Eksik bölümleri göster",
"description": "Altyazısı eksik bölüm sayısını gösterir"
},
"showMissingMovies": {
"label": "Eksik filmleri göster",
"description": "Altyazısı eksik film sayısını gösterir"
},
"showProviderIssues": {
"label": "Sağlayıcı sorunlarını göster",
"description": "Sorun yaşayan altyazı sağlayıcılarının sayısını gösterir"
},
"showHealthIssues": {
"label": "Sağlık sorunlarını göster",
"description": "Bazarr sağlık sorunlarının sayısını gösterir"
}
},
"error": {
"internalServerError": "Bazarr verileri alınamadı"
}
},
"immich-serverStats": {
"name": "Immich Sunucu İstatistikleri",
"description": "Immich örneğiniz hakkında bilgiler",
@@ -3387,35 +2995,6 @@
}
}
},
"mediaMissing": {
"name": "Eksik ve Kuyruktaki Medya",
"description": "Radarr ve Sonarr'daki eksik ve kuyruğa alınmış film ve bölümleri gösterir",
"option": {
"showMissing": {
"label": "Eksik öğeleri göster"
},
"showQueued": {
"label": "Kuyruktaki öğeleri göster"
},
"pageSize": {
"label": "Sayfa başına öğe"
}
},
"tab": {
"missing": "Eksik",
"queued": "Kuyrukta"
},
"type": {
"movie": "Film",
"episode": "Bölüm"
},
"empty": {
"missing": "Eksik öğe yok",
"queued": "Kuyrukta öğe yok",
"noTabsEnabled": "Widget ayarlarında en az bir sekmeyi etkinleştirin"
},
"timeLeft": "Kalan süre"
},
"rssFeed": {
"name": "RSS Beslemeleri",
"description": "Bir veya daha fazla RSS, ATOM veya JSON beslemesini takip edin ve görüntüleyin",
@@ -3744,40 +3323,6 @@
"internalServerError": "Çalışma süresi verileri alınamadı"
}
},
"traefik": {
"name": "Traefik",
"description": "Traefik yönlendiricilerinin, hizmetlerinin, ara yazılımlarının ve giriş noktalarının genel görünümü",
"option": {
"showTcp": {
"label": "TCP'yi göster"
},
"showUdp": {
"label": "UDP'yi göster"
},
"showEntryPoints": {
"label": "Giriş noktalarını göster"
}
},
"instances": "Traefik örnekleri",
"versionUnknown": "Sürüm bilinmiyor",
"summary": {
"routers": "Yönlendiriciler",
"entryPoints": "Giriş noktaları"
},
"resource": {
"routers": "Yönlendiriciler",
"services": "Hizmetler",
"middlewares": "Ara Yazılımlar"
},
"status": {
"healthy": "Sağlıklı",
"errors": "{count} hata",
"warnings": "{count} uyarı"
},
"error": {
"internalServerError": "Traefik verileri alınamadı"
}
},
"audioStats": {
"name": "Ses İstatistikleri",
"description": "Navidrome veya Audiobookshelf'ten kütüphane ve oynatma istatistikleri",
@@ -3901,26 +3446,6 @@
"unhealthy": "Sağlıksız"
}
},
"customApi": {
"name": "Özel API",
"description": "Özel yapılandırmayla herhangi bir harici API'den veri gösterir.",
"option": {
"definitionId": {
"label": "Tanım Kimliği"
},
"refreshInterval": {
"label": "Yenileme aralığı",
"description": "Verilerin API'den hangi sıklıkta yeniden alınacağı (saniye)"
}
},
"noDefinition": "Tanım seçilmedi",
"definitionNotFound": "Widget tanımı bulunamadı. Silinmiş olabilir.",
"noDisplayOutput": "Görüntülenecek çıktı yok",
"executeConfirm": "Bu eylemi yürütmek istediğinizden emin misiniz?",
"executing": "Yürütülüyor...",
"executeSuccess": "Eylem başarıyla yürütüldü",
"executeFailed": "Eylem başarısız oldu. Widget yapılandırmasını kontrol edin."
},
"beszelSystemTable": {
"name": "Beszel Sistemleri (Tablo)",
"description": "Sıralanabilir sütunlar ve durum göstergeleri ile tüm Beszel tarafından izlenen sistemlerin tablo görünümü",
@@ -4171,6 +3696,256 @@
"subtitle": "Docker konteynerlerinin ağ trafiği"
}
}
},
"patchmon": {
"name": "PatchMon",
"description": "PatchMon'daki ana makine yama durumunun genel görünümü",
"title": "PatchMon İstatistikleri",
"totalHosts": "Toplam Ana Makine",
"hostsNeedingUpdates": "Güncelleme Gerekiyor",
"securityUpdates": "Güvenlik Güncellemeleri",
"upToDateHosts": "Güncel Ana Makineler",
"hostsWithSecurityUpdates": "Güvenlik Güncellemesi Olan Ana Makineler",
"recentUpdates24h": "Güncellemeler (24 sa.)",
"totalOutdatedPackages": "Güncel Olmayan Paketler",
"totalRepos": "Depolar",
"osDistribution": "İşletim Sistemi Dağılımı",
"compliance": "Yama Uyumluluğu",
"complianceRatio": "{upToDate} / {total}",
"lastUpdated": "Güncellendi: {time}",
"option": {
"showTotalHosts": {
"label": "Toplam ana makine sayısını göster",
"description": "İzlenen toplam ana makine sayısını gösterir"
},
"showHostsNeedingUpdates": {
"label": "Güncelleme gereken ana makineleri göster",
"description": "En az bir güncel olmayan paketi bulunan ana makineleri gösterir"
},
"showSecurityUpdates": {
"label": "Güvenlik güncellemelerini göster",
"description": "Kullanılabilir toplam güvenlik güncellemesi sayısını gösterir"
},
"showUpToDateHosts": {
"label": "Güncel ana makineleri göster",
"description": "Güncel olmayan paketi bulunmayan ana makineleri gösterir"
},
"showHostsWithSecurityUpdates": {
"label": "Güvenlik güncellemesi olan ana makineleri göster",
"description": "Güvenlik yaması gereken ana makineleri gösterir"
},
"showRecentUpdates24h": {
"label": "Son güncellemeleri göster (24 sa.)",
"description": "Son 24 saatte uygulanan güncelleme sayısını gösterir"
},
"showTotalOutdatedPackages": {
"label": "Güncel olmayan paketleri göster",
"description": "Tüm ana makinelerdeki güncel olmayan paketlerin toplam sayısını gösterir"
},
"showTotalRepos": {
"label": "Depoları göster",
"description": "İzlenen etkin depo sayısını gösterir"
},
"enableThresholdColors": {
"label": "Eşik renklerini etkinleştir",
"description": "İstatistik değerlerini önem düzeyi ön ayarlarına göre yeşil, sarı veya kırmızı renklendirir"
},
"useCustomThresholds": {
"label": "Gelişmiş eşikler",
"description": "Her istatistik için uyarı ve kritik eşikleri mutlak sayılarla veya toplam ana makine yüzdesiyle özelleştirin"
},
"thresholdMode": {
"option": {
"absolute": "Mutlak sayı",
"percent": "Toplam ana makinelerin yüzdesi"
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "Güncelleme gereksinimi eşik modu",
"description": "Güncelleme gerekenlerin sayısını mutlak değer veya toplam ana makinelerin yüzdesi olarak karşılaştırır"
},
"hostsNeedingUpdatesWarningAt": {
"label": "Güncelleme gereksinimi uyarı eşiği",
"description": "Değer bu eşiğe ulaştığında sarı renge geçer"
},
"hostsNeedingUpdatesCriticalAt": {
"label": "Güncelleme gereksinimi kritik eşiği",
"description": "Değer bu eşiğe ulaştığında kırmızı renge geçer"
},
"securityUpdatesThresholdMode": {
"label": "Güvenlik güncellemeleri eşik modu",
"description": "Güvenlik güncellemesi sayısını mutlak değer veya toplam ana makinelerin yüzdesi olarak karşılaştırır"
},
"securityUpdatesWarningAt": {
"label": "Güvenlik güncellemeleri uyarı eşiği",
"description": "Değer bu eşiğe ulaştığında sarı renge geçer"
},
"securityUpdatesCriticalAt": {
"label": "Güvenlik güncellemeleri kritik eşiği",
"description": "Değer bu eşiğe ulaştığında kırmızı renge geçer"
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "Güvenlik güncellemesi olan ana makineler için eşik modu",
"description": "Ana makine sayısını mutlak değer veya toplam ana makinelerin yüzdesi olarak karşılaştırır"
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "Güvenlik güncellemesi olan ana makineler için uyarı eşiği",
"description": "Değer bu eşiğe ulaştığında sarı renge geçer"
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "Güvenlik güncellemesi olan ana makineler için kritik eşik",
"description": "Değer bu eşiğe ulaştığında kırmızı renge geçer"
},
"upToDateHostsThresholdMode": {
"label": "Güncel ana makineler için eşik modu",
"description": "Güncel ana makine sayısını mutlak değer veya toplam ana makinelerin yüzdesi olarak karşılaştırır"
},
"upToDateHostsWarningAt": {
"label": "Güncel ana makineler için uyarı eşiği",
"description": "Değer bu eşikte veya üzerinde, ancak tam kapsamanın altındaysa sarı renge geçer"
},
"upToDateHostsCriticalAt": {
"label": "Güncel ana makineler için kritik eşik",
"description": "Değer bu eşiğin altına düştüğünde kırmızı renge geçer"
},
"totalOutdatedPackagesThresholdMode": {
"label": "Güncel olmayan paketler için eşik modu",
"description": "Güncel olmayan paketlerin sayısını mutlak değer veya toplam ana makinelerin yüzdesi olarak karşılaştırır"
},
"totalOutdatedPackagesWarningAt": {
"label": "Güncel olmayan paketler için uyarı eşiği",
"description": "Değer bu eşiğe ulaştığında sarı renge geçer"
},
"totalOutdatedPackagesCriticalAt": {
"label": "Güncel olmayan paketler için kritik eşik",
"description": "Değer bu eşiğe ulaştığında kırmızı renge geçer"
},
"showOsDistribution": {
"label": "İşletim sistemi dağılımını göster",
"description": "İzlenen ana makinelerin işletim sistemine göre dağılımını gösterir"
},
"osDistributionLimit": {
"label": "İşletim sistemi dağılımı sınırı",
"description": "Gösterilecek en fazla işletim sistemi sayısı",
"option": {
"3": "İlk 3",
"5": "İlk 5",
"10": "İlk 10",
"all": "Tümü"
}
},
"showOsVersion": {
"label": "İşletim sistemi sürümünü göster",
"description": "Mevcut olduğunda işletim sistemi sürümünü her dağılım etiketine ekler"
},
"showComplianceHero": {
"label": "Uyumluluk özetini göster",
"description": "Güncel ana makinelerin yüzdesini gösteren bir uyumluluk halkası görüntüler"
},
"osDisplayMode": {
"label": "İşletim sistemi görüntüleme modu",
"description": "İşletim sistemi dağılımının nasıl gösterileceğini seçin",
"option": {
"bars": "Yatay çubuklar",
"donut": "Halka grafik"
}
}
},
"error": {
"internalServerError": "PatchMon verileri alınamadı"
}
},
"bazarr": {
"name": "Bazarr",
"description": "Bazarr örneğinizdeki eksik altyazıların ve sağlık durumunun genel görünümü",
"episodes": "Eksik Bölümler",
"movies": "Eksik Filmler",
"providers": "Sağlayıcı Sorunları",
"status": "Sağlık Sorunları",
"option": {
"showMissingEpisodes": {
"label": "Eksik bölümleri göster",
"description": "Altyazısı eksik bölüm sayısını gösterir"
},
"showMissingMovies": {
"label": "Eksik filmleri göster",
"description": "Altyazısı eksik film sayısını gösterir"
},
"showProviderIssues": {
"label": "Sağlayıcı sorunlarını göster",
"description": "Sorun yaşayan altyazı sağlayıcılarının sayısını gösterir"
},
"showHealthIssues": {
"label": "Sağlık sorunlarını göster",
"description": "Bazarr sağlık sorunlarının sayısını gösterir"
}
},
"error": {
"internalServerError": "Bazarr verileri alınamadı"
}
},
"mediaMissing": {
"name": "Eksik ve Kuyruktaki Medya",
"description": "Radarr ve Sonarr'daki eksik ve kuyruğa alınmış film ve bölümleri gösterir",
"option": {
"showMissing": {
"label": "Eksik öğeleri göster"
},
"showQueued": {
"label": "Kuyruktaki öğeleri göster"
},
"pageSize": {
"label": "Sayfa başına öğe"
}
},
"tab": {
"missing": "Eksik",
"queued": "Kuyrukta"
},
"type": {
"movie": "Film",
"episode": "Bölüm"
},
"empty": {
"missing": "Eksik öğe yok",
"queued": "Kuyrukta öğe yok",
"noTabsEnabled": "Widget ayarlarında en az bir sekmeyi etkinleştirin"
},
"timeLeft": "Kalan süre"
},
"traefik": {
"name": "Traefik",
"description": "Traefik yönlendiricilerinin, hizmetlerinin, ara yazılımlarının ve giriş noktalarının genel görünümü",
"option": {
"showTcp": {
"label": "TCP'yi göster"
},
"showUdp": {
"label": "UDP'yi göster"
},
"showEntryPoints": {
"label": "Giriş noktalarını göster"
}
},
"instances": "Traefik örnekleri",
"versionUnknown": "Sürüm bilinmiyor",
"summary": {
"routers": "Yönlendiriciler",
"entryPoints": "Giriş noktaları"
},
"resource": {
"routers": "Yönlendiriciler",
"services": "Hizmetler",
"middlewares": "Ara Yazılımlar"
},
"status": {
"healthy": "Sağlıklı",
"errors": "{count} hata",
"warnings": "{count} uyarı"
},
"error": {
"internalServerError": "Traefik verileri alınamadı"
}
}
},
"widgetPreview": {
@@ -4551,11 +4326,11 @@
},
"navbar": {
"items": {
"workshop": "Workshop",
"home": "Ana Sayfa",
"boards": "Paneller",
"apps": "Uygulamalar",
"integrations": "Entegrasyonlar",
"customWidgets": "Özel Widget'lar",
"searchEngies": "Arama Motorları",
"medias": "Medyalar",
"users": {
@@ -5694,6 +5469,9 @@
},
"navigationStructure": {
"manage": {
"workshop": {
"label": "Workshop"
},
"label": "Yönet",
"boards": {
"label": "Paneller"
@@ -5728,18 +5506,6 @@
"label": "Düzenle"
}
},
"custom-widgets": {
"label": "Özel widget'lar",
"new": {
"label": "Yeni"
},
"edit": {
"label": "Düzenle",
"flow": {
"label": "Akış"
}
}
},
"users": {
"label": "Kullanıcılar",
"create": {
+256 -480
View File
@@ -691,206 +691,11 @@
"customWidget": {
"page": {
"list": {
"title": "Власні віджети",
"noResults": "Поки що немає власних віджетів. Створіть свій перший!",
"loading": "Завантаження..."
},
"create": {
"title": "Створити власний віджет",
"subtitle": "Визначте URL-адресу API, автентифікацію та спосіб показу даних відповіді."
},
"edit": {
"title": "Редагувати власний віджет"
"title": "Власні віджети"
}
},
"action": {
"create": "Створити",
"import": "Імпорт",
"save": "Зберегти",
"delete": "Видалити власний віджет",
"deleteConfirm": "Ви впевнені, що хочете видалити \"{name}\"? Цю дію неможливо скасувати.",
"export": "Експорт",
"addMapping": "Додати зіставлення",
"addColumn": "Додати стовпець",
"edit": "Редагувати",
"removeMapping": "Видалити зіставлення",
"removeColumn": "Видалити стовпець",
"addItem": "Додати елемент",
"removeItem": "Видалити елемент",
"addBar": "Додати бар",
"duplicate": "Дублікат",
"copyAiPrompt": "Копіювати запит AI",
"enable": "Увімкнути",
"disable": "Вимкнути",
"menu": "Дії"
},
"field": {
"name": "Назва",
"description": "Опис",
"iconUrl": "URL іконки",
"url": "URL-адреса",
"authType": "Тип авторизації",
"headerName": "Назва параметра заголовок/запиту",
"method": "Метод",
"requestBody": "Текст запиту",
"displayType": "Тип для показу",
"jsonPath": "Шлях до JSON",
"jsonPathHint": "Використовуйте синтаксис JSONPath для вилучення значень, наприклад, $.data.temperature або $.items[0].name",
"label": "Мітка",
"unit": "Одиниця",
"mappings": "Зіставлення",
"tablePath": "Шлях масиву JSON",
"tablePathHint": "Шлях до масиву у відповідь, наприклад, $.data.items",
"columns": "Стовпці",
"header": "Заголовок",
"items": "Елементи",
"gridColumns": "Стовпці сітки",
"cardStyle": "Стиль картки",
"bars": "Бари",
"valuePath": "Значення JSON шлях",
"maxPath": "Макс. значення JSON шляху",
"showPercentage": "Показувати відсоток",
"barSize": "Розмір панелі",
"goodValues": "Хороші значення (розділені комами)",
"dotSize": "Розмір точки",
"valueSize": "Розмір значення",
"labelPosition": "Позиція мітки",
"kvLayout": "Макет",
"striped": "Смугасті рядки",
"compact": "Компактний режим",
"maxHeight": "Макс висота (пікс.)",
"color": "Колір",
"buttonLabel": "Підпис кнопки",
"buttonColor": "Колір кнопки",
"confirmText": "Текст підтвердження",
"confirmTextHint": "Якщо встановлено, перед виконанням запиту з’явиться діалогове вікно підтвердження",
"successMessage": "Повідомлення про успіх",
"successMessageHint": "Повідомлення яке відображається після успішного виконання",
"enabled": "Увімкнено",
"template": {
"label": "Шаблон JSX",
"description": "Шаблон Mantine JSX. Доступ до полів відповіді API через прив'язки даних (наприклад, data.name). Використовуйте лише компоненти з білого списку. Заборонено: constructor, __proto__, eval, Function, window, document."
}
},
"placeholder": {
"exampleLabel": "Температура ЦП",
"exampleLabelShort": "Темп процесора",
"exampleHeader": "Назва",
"exampleUnit": "°C",
"iconUrl": "https://...",
"url": "https://api.example.com/api/v1/status",
"headerName": "X-API-Key",
"jsonPath": "$.data.value",
"tablePath": "$.data.items",
"columnJsonPath": "$.name",
"valuePath": "$.data.used",
"maxPath": "$.data.total",
"goodValues": "онлайн, правда, вгору",
"color": "синій"
},
"cardStyleOption": {
"filled": "Заповнений",
"outline": "Контур",
"subtle": "Тонкий"
},
"layoutOption": {
"list": "Список",
"grid": "Сітка"
},
"sizeOption": {
"sm": "Малий",
"md": "Середній",
"lg": "Великий",
"xl": "Дуже великий"
},
"labelPositionOption": {
"above": "Вище",
"below": "Нижче"
},
"fieldset": {
"general": "Загальне",
"connection": "API підключення",
"display": "Конфігурації дисплея"
},
"displayTypeDescription": {
"singleValue": "Показати одне витягнуте значення з міткою та одиницею вимірювання",
"keyValue": "Показати кілька позначених значень поруч",
"table": "Показати рядки даних у форматі таблиці",
"statGrid": "Кольорові картки статистики в сітці — як-от віджети Pi-Hole або Speedtest",
"progressBars": "Індикатори виконання, що показують використання або завершення — для диска, пам'яті, квот",
"statusIndicator": "Кольорові крапки стану показують онлайн/оффлайн або охорони здоров'я",
"countGrid": "Компактне число + лічильники міток у вигляді сітки",
"raw": "Гарно надрукований JSON-вивід для налагодження",
"actionButton": "Кнопка яка виконує запит при натисканні",
"customJsx": "Користувацький макет JSX з пов'язування повним API даних з білого списку"
},
"method": {
"GET": "ОТРИМАТИ",
"POST": "СТВОРИТИ",
"PUT": "Розміщення",
"DELETE": "ВИДАЛИТИ",
"PATCH": "ПАТЧ"
},
"authType": {
"none": "Немає",
"bearer": "Пред'явити токен",
"basic": "Базова авторизація",
"apiKeyHeader": "Ключ API (Заголовок)",
"apiKeyQuery": "Ключ API (запит)"
},
"displayType": {
"singleValue": "Одиночні Значення",
"keyValue": "Значення ключа",
"table": "Таблиця",
"statGrid": "Статистична сітка",
"progressBars": "Індикатори прогресу",
"statusIndicator": "Індикатор стану",
"countGrid": "Кількість сіток",
"raw": "Необроблений JSON",
"actionButton": "Кнопка дії",
"customJsx": "Користувацький JSX"
},
"secret": {
"apiKey": "Ключ API / Токен",
"username": "Ім'я користувача",
"password": "Пароль",
"savedPlaceholder": "• • • • • • (збережено, залиште порожнім, щоб зберегти)"
},
"preview": {
"title": "Попередній перегляд",
"test": "Перевірка",
"hint": "Натисніть Тест, щоб переглянути відповідь API з поточною конфігурацією.",
"rawResponse": "Необроблена відповідь JSON"
},
"notification": {
"created": "Віджет \"{name}\" успішно створено.",
"updated": "Віджет \"{name}\" успішно оновлено.",
"deleted": "Віджет \"{name}\" видалено.",
"imported": "Віджет успішно імпортовано.",
"aiPromptCopied": "Запит ШІ скопійовано до буферу обміну",
"aiPromptDescription": "Скопіюйте запит на вставку в будь-який AI чатбот (ChatGPT, Claude, Gemini ...). Вона включає в себе повну схему віджетів і вашу API відповідь, щоб ШІ могла генерувати конфігурацію AI для вашого коректного імпортування.",
"aiPromptCopy": "Скопіювати в буфер обміну",
"aiPromptNoResponse": "Порада: Спочатку запустіть тест, щоб включити відповідь API в командний рядок для отримання кращих результатів.",
"aiPromptCopyError": "Не вдалося скопіювати запит до буфера обміну. Можливо, ваш браузер не підтримує цю функцію.",
"createError": "Не вдалося створити віджет. Перевірте кінцеву точку API.",
"updateError": "Неможливо оновити віджет. Зміни не збережено.",
"importError": "Неможливо імпортувати віджет. Переконайтеся, що файл є допустимим експортом користувацьких віджетів JSON.",
"exportError": "Не вдалося експортувати віджет.",
"duplicated": "Віджет \"{name}\" продубльовано.",
"duplicateError": "Не вдалося продублювати віджет.",
"toggleError": "Не вдалося змінити стан віджету.",
"deleteError": "Не вдалося видалити віджет.",
"previewError": "Не вдалося отримати попередній перегляд. Перевірте URL-адресу та повторіть спробу.",
"executed": "Дію успішно виконано.",
"executeError": "Дію не виконано: {error}"
},
"table": {
"name": "Назва",
"url": "URL",
"display": "Показати"
},
"widget": {
"disabled": "Цей віджет вимкнено"
"toggleError": "Не вдалося змінити стан віджету."
}
},
"integration": {
@@ -2828,193 +2633,6 @@
"internalServerError": "Не вдалося отримати дані Paperless-ngx"
}
},
"patchmon": {
"name": "ПатчМон",
"description": "Огляд стану патчів хоста від PatchMon",
"title": "Статистика PatchMon",
"totalHosts": "Всього хостів",
"hostsNeedingUpdates": "Потребує оновлення",
"securityUpdates": "Оновлення безпеки",
"upToDateHosts": "Оновлені хости",
"hostsWithSecurityUpdates": "Хости з оновленнями безпеки",
"recentUpdates24h": "Оновлення (24г)",
"totalOutdatedPackages": "Застарілі пакети",
"totalRepos": "Репозитарії",
"osDistribution": "Розподіл ОС",
"compliance": "Відповідність патчам",
"complianceRatio": "{upToDate} / {total}",
"lastUpdated": "Оновлено {time}",
"option": {
"showTotalHosts": {
"label": "Показати хости загалом",
"description": "Відображати загальну кількість контрольованих хостів"
},
"showHostsNeedingUpdates": {
"label": "Показувати потрібні оновлення хостів",
"description": "Відображати хости з принаймні одним застарілим пакетом"
},
"showSecurityUpdates": {
"label": "Показати оновлення безпеки",
"description": "Відображати загальну кількість доступних оновлень безпеки"
},
"showUpToDateHosts": {
"label": "Показувати актуальні хости",
"description": "Відображати хостингові системи без застарілих пакетів"
},
"showHostsWithSecurityUpdates": {
"label": "Показувати хости з оновленнями безпеки",
"description": "Показувати хости, які потребують патчів безпеки"
},
"showRecentUpdates24h": {
"label": "Показати останні оновлення (24h)",
"description": "Відображати кількість оновлень, застосованих за останні 24 години"
},
"showTotalOutdatedPackages": {
"label": "Показати застарілі пакети",
"description": "Відображати загальну кількість застарілих пакетів у всіх хостах"
},
"showTotalRepos": {
"label": "Показати репозиторії",
"description": "Відображати кількість активних репозиторіїв, що відслідковуються"
},
"enableThresholdColors": {
"label": "Увімкнути кольори порогових значень",
"description": "Значення колірних характеристик: зелений, жовтий або червоний, залежно від пресетів серйозності"
},
"useCustomThresholds": {
"label": "Розширені пороги",
"description": "Налаштуйте пороги попереджень та критичних значень для кожної статистики, використовуючи абсолютні показники або відсотки від загальної кількості хостів"
},
"thresholdMode": {
"option": {
"absolute": "Абсолютна кількість",
"percent": "Відсоток від загальної кількості хостів"
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "Потрібен поріг оновлення",
"description": "Порівняйте оновлення як абсолютне значення або відсоток від загальної кількості хостів"
},
"hostsNeedingUpdatesWarningAt": {
"label": "Поріг попередження про нові оновлення",
"description": "Вмикається жовтий колір, коли значення досягає цього порогового значення"
},
"hostsNeedingUpdatesCriticalAt": {
"label": "Потребує оновлення критичного порогу",
"description": "Вмикається червоний коли значення досягає цього порогу"
},
"securityUpdatesThresholdMode": {
"label": "Режим оновлення системи безпеки",
"description": "Порівняйте оновлення безпеки як абсолютне значення або відсоток від загальної кількості хостів"
},
"securityUpdatesWarningAt": {
"label": "Поріг попередження про оновлення безпеки",
"description": "Вмикається жовтий колір, коли значення досягає цього порогового значення"
},
"securityUpdatesCriticalAt": {
"label": "Критичний поріг оновлення системи безпеки",
"description": "Вмикається червоний коли значення досягає цього порогу"
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "Хости з режимом порогу оновлень безпеки",
"description": "Порівняйте кількість хостів як абсолютне значення або відсоток від загальної кількості хостів"
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "Хости з попередженням про оновлення безпеки",
"description": "Вмикається жовтий колір коли значення досягає цього порогу"
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "Хости з критичним порогом оновлення безпеки",
"description": "Вмикається червоний коли значення досягає цього порогу"
},
"upToDateHostsThresholdMode": {
"label": "Оновлений режим порогового хостів",
"description": "Порівняйте актуальний хост як абсолютне значення або відсоток від загальної кількості хостів"
},
"upToDateHostsWarningAt": {
"label": "Поріг попередження для актуальних хостів",
"description": "Вмикається жовтий колір, коли значення дорівнює або перевищує цей поріг, але нижче повного покриття."
},
"upToDateHostsCriticalAt": {
"label": "Критичний поріг для оновлених хостів",
"description": "Вмикається червоний, коли значення падає нижче цього порогу"
},
"totalOutdatedPackagesThresholdMode": {
"label": "Режим порогу застарілих пакетів",
"description": "Порівняйте застарілі пакети як абсолютне значення або відсоток від загальної кількості хостів"
},
"totalOutdatedPackagesWarningAt": {
"label": "Поріг попередження про застарілі пакети",
"description": "Вмикається жовтий, коли значення досягає цього порогу"
},
"totalOutdatedPackagesCriticalAt": {
"label": "Критичний поріг застарілих пакетів",
"description": "Вмикається червоний коли значення досягає цього порогу"
},
"showOsDistribution": {
"label": "Показати розподіл ОС",
"description": "Показати розподіл контрольованих хостів операційною системою"
},
"osDistributionLimit": {
"label": "Обмеження розподілу ОС",
"description": "Максимальна кількість операційних систем для відображення",
"option": {
"3": "Топ 3",
"5": "Тор 5",
"10": "Топ 10",
"all": "Усі"
}
},
"showOsVersion": {
"label": "Показати версію ОС",
"description": "Додавати версію ОС до кожної мітки дистрибуції, коли вона стане доступною"
},
"showComplianceHero": {
"label": "Показати героя відповідності",
"description": "Відображати кільце відповідності, яке показує відсоток оновлених хостів"
},
"osDisplayMode": {
"label": "Режим відображення ОС",
"description": "Виберіть спосіб відображення дистрибутива операційної системи",
"option": {
"bars": "Горизонтальні смуги",
"donut": "Кільцева діаграма"
}
}
},
"error": {
"internalServerError": "Не вдалося отримати дані PatchMon"
}
},
"bazarr": {
"name": "Bazarr",
"description": "Огляд відсутніх субтитрів та стану справності вашого екземпляра Bazarr",
"episodes": "Відсутні епізоди",
"movies": "Відсутні фільми",
"providers": "Проблеми p постачальником",
"status": "Проблеми зі здоров'ям",
"option": {
"showMissingEpisodes": {
"label": "Показати відсутні епізоди",
"description": "Відображати кількість епізодів без субтититрів"
},
"showMissingMovies": {
"label": "Показати відсутні фільми",
"description": "Відобразити кількість фільмів без субтитрів"
},
"showProviderIssues": {
"label": "Показати проблеми постачальника",
"description": "Відображати кількість постачальника субтитрів з проблемами"
},
"showHealthIssues": {
"label": "Показувати проблеми зі здоров’ям",
"description": "Відображати кількість проблем зі здоров’ям Bazarr"
}
},
"error": {
"internalServerError": "Не вдалося отримати дані Bazarr"
}
},
"immich-serverStats": {
"name": "Статистика Immich на сервері",
"description": "Інформація про Ваш екземпляр Immich",
@@ -3387,35 +3005,6 @@
}
}
},
"mediaMissing": {
"name": "Відсутня медіа в черзі",
"description": "Показує відсутні і в черзі фільми і епізоди з Radarr і Sonarr",
"option": {
"showMissing": {
"label": "Показати відсутні елементи"
},
"showQueued": {
"label": "Показати елементи в черзі"
},
"pageSize": {
"label": "Елементів на сторінці"
}
},
"tab": {
"missing": "Відсутні",
"queued": "У черзі"
},
"type": {
"movie": "Фільм",
"episode": "Епізод"
},
"empty": {
"missing": "Немає відсутніх елементів",
"queued": "Немає елементів у черзі",
"noTabsEnabled": "Увімкнути принаймні одну вкладку в налаштуваннях віджету"
},
"timeLeft": "Залишилося часу"
},
"rssFeed": {
"name": "RSS-канали",
"description": "Моніторинг та відображення однієї або кількох загальних RSS-, ATOM- або JSON-стрічок",
@@ -3744,40 +3333,6 @@
"internalServerError": "Не вдалося отримати дані про час роботи"
}
},
"traefik": {
"name": "Трафік",
"description": "Огляд маршрутизаторів, сервісів, проміжного програмного забезпечення та точок входу Traefik",
"option": {
"showTcp": {
"label": "Показати TCP"
},
"showUdp": {
"label": "Show UDP"
},
"showEntryPoints": {
"label": "Показувати точки входу"
}
},
"instances": "Traefik екземпляри",
"versionUnknown": "Версія невідома",
"summary": {
"routers": "Маршрутизатори",
"entryPoints": "Точки входу"
},
"resource": {
"routers": "Маршрутизатори",
"services": "Служби",
"middlewares": "Проміжне програмне забезпечення"
},
"status": {
"healthy": "Здоровий",
"errors": "{count} помилок",
"warnings": "{count} застережень"
},
"error": {
"internalServerError": "Неможливо отримати дані Traefik"
}
},
"audioStats": {
"name": "Статистика аудіо",
"description": "Бібліотека і відтворення статистики з Navidrome або Audiobookf",
@@ -3901,26 +3456,6 @@
"unhealthy": "Нездоровий"
}
},
"customApi": {
"name": "Користувацький API",
"description": "Відображення даних з будь-якої зовнішньої API з користувальницької конфігурації.",
"option": {
"definitionId": {
"label": "Ідентифікатор визначення"
},
"refreshInterval": {
"label": "Інтервал оновлення",
"description": "Як часто слід оновлювати дані з API (в секундах)"
}
},
"noDefinition": "Не обрано визначення",
"definitionNotFound": "Визначення віджета не знайдено. Можливо, його видалено.",
"noDisplayOutput": "Без виводу на екран",
"executeConfirm": "Ви впевнені, що хочете виконати цю дію?",
"executing": "Виконання...",
"executeSuccess": "Дія успішно виконана",
"executeFailed": "Не вдалося виконати дію. Перевірте налаштування віджету."
},
"beszelSystemTable": {
"name": "Beszel системи (Таблиця)",
"description": "Вид таблиць всіх систем, що контролюються в Beszel, з сортованими стовпцями і індикатори стану",
@@ -4171,6 +3706,256 @@
"subtitle": "Мережевий трафік Docker контейнерів"
}
}
},
"patchmon": {
"name": "ПатчМон",
"description": "Огляд стану патчів хоста від PatchMon",
"title": "Статистика PatchMon",
"totalHosts": "Всього хостів",
"hostsNeedingUpdates": "Потребує оновлення",
"securityUpdates": "Оновлення безпеки",
"upToDateHosts": "Оновлені хости",
"hostsWithSecurityUpdates": "Хости з оновленнями безпеки",
"recentUpdates24h": "Оновлення (24г)",
"totalOutdatedPackages": "Застарілі пакети",
"totalRepos": "Репозитарії",
"osDistribution": "Розподіл ОС",
"compliance": "Відповідність патчам",
"complianceRatio": "{upToDate} / {total}",
"lastUpdated": "Оновлено {time}",
"option": {
"showTotalHosts": {
"label": "Показати хости загалом",
"description": "Відображати загальну кількість контрольованих хостів"
},
"showHostsNeedingUpdates": {
"label": "Показувати потрібні оновлення хостів",
"description": "Відображати хости з принаймні одним застарілим пакетом"
},
"showSecurityUpdates": {
"label": "Показати оновлення безпеки",
"description": "Відображати загальну кількість доступних оновлень безпеки"
},
"showUpToDateHosts": {
"label": "Показувати актуальні хости",
"description": "Відображати хостингові системи без застарілих пакетів"
},
"showHostsWithSecurityUpdates": {
"label": "Показувати хости з оновленнями безпеки",
"description": "Показувати хости, які потребують патчів безпеки"
},
"showRecentUpdates24h": {
"label": "Показати останні оновлення (24h)",
"description": "Відображати кількість оновлень, застосованих за останні 24 години"
},
"showTotalOutdatedPackages": {
"label": "Показати застарілі пакети",
"description": "Відображати загальну кількість застарілих пакетів у всіх хостах"
},
"showTotalRepos": {
"label": "Показати репозиторії",
"description": "Відображати кількість активних репозиторіїв, що відслідковуються"
},
"enableThresholdColors": {
"label": "Увімкнути кольори порогових значень",
"description": "Значення колірних характеристик: зелений, жовтий або червоний, залежно від пресетів серйозності"
},
"useCustomThresholds": {
"label": "Розширені пороги",
"description": "Налаштуйте пороги попереджень та критичних значень для кожної статистики, використовуючи абсолютні показники або відсотки від загальної кількості хостів"
},
"thresholdMode": {
"option": {
"absolute": "Абсолютна кількість",
"percent": "Відсоток від загальної кількості хостів"
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "Потрібен поріг оновлення",
"description": "Порівняйте оновлення як абсолютне значення або відсоток від загальної кількості хостів"
},
"hostsNeedingUpdatesWarningAt": {
"label": "Поріг попередження про нові оновлення",
"description": "Вмикається жовтий колір, коли значення досягає цього порогового значення"
},
"hostsNeedingUpdatesCriticalAt": {
"label": "Потребує оновлення критичного порогу",
"description": "Вмикається червоний коли значення досягає цього порогу"
},
"securityUpdatesThresholdMode": {
"label": "Режим оновлення системи безпеки",
"description": "Порівняйте оновлення безпеки як абсолютне значення або відсоток від загальної кількості хостів"
},
"securityUpdatesWarningAt": {
"label": "Поріг попередження про оновлення безпеки",
"description": "Вмикається жовтий колір, коли значення досягає цього порогового значення"
},
"securityUpdatesCriticalAt": {
"label": "Критичний поріг оновлення системи безпеки",
"description": "Вмикається червоний коли значення досягає цього порогу"
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "Хости з режимом порогу оновлень безпеки",
"description": "Порівняйте кількість хостів як абсолютне значення або відсоток від загальної кількості хостів"
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "Хости з попередженням про оновлення безпеки",
"description": "Вмикається жовтий колір коли значення досягає цього порогу"
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "Хости з критичним порогом оновлення безпеки",
"description": "Вмикається червоний коли значення досягає цього порогу"
},
"upToDateHostsThresholdMode": {
"label": "Оновлений режим порогового хостів",
"description": "Порівняйте актуальний хост як абсолютне значення або відсоток від загальної кількості хостів"
},
"upToDateHostsWarningAt": {
"label": "Поріг попередження для актуальних хостів",
"description": "Вмикається жовтий колір, коли значення дорівнює або перевищує цей поріг, але нижче повного покриття."
},
"upToDateHostsCriticalAt": {
"label": "Критичний поріг для оновлених хостів",
"description": "Вмикається червоний, коли значення падає нижче цього порогу"
},
"totalOutdatedPackagesThresholdMode": {
"label": "Режим порогу застарілих пакетів",
"description": "Порівняйте застарілі пакети як абсолютне значення або відсоток від загальної кількості хостів"
},
"totalOutdatedPackagesWarningAt": {
"label": "Поріг попередження про застарілі пакети",
"description": "Вмикається жовтий, коли значення досягає цього порогу"
},
"totalOutdatedPackagesCriticalAt": {
"label": "Критичний поріг застарілих пакетів",
"description": "Вмикається червоний коли значення досягає цього порогу"
},
"showOsDistribution": {
"label": "Показати розподіл ОС",
"description": "Показати розподіл контрольованих хостів операційною системою"
},
"osDistributionLimit": {
"label": "Обмеження розподілу ОС",
"description": "Максимальна кількість операційних систем для відображення",
"option": {
"3": "Топ 3",
"5": "Тор 5",
"10": "Топ 10",
"all": "Усі"
}
},
"showOsVersion": {
"label": "Показати версію ОС",
"description": "Додавати версію ОС до кожної мітки дистрибуції, коли вона стане доступною"
},
"showComplianceHero": {
"label": "Показати героя відповідності",
"description": "Відображати кільце відповідності, яке показує відсоток оновлених хостів"
},
"osDisplayMode": {
"label": "Режим відображення ОС",
"description": "Виберіть спосіб відображення дистрибутива операційної системи",
"option": {
"bars": "Горизонтальні смуги",
"donut": "Кільцева діаграма"
}
}
},
"error": {
"internalServerError": "Не вдалося отримати дані PatchMon"
}
},
"bazarr": {
"name": "Bazarr",
"description": "Огляд відсутніх субтитрів та стану справності вашого екземпляра Bazarr",
"episodes": "Відсутні епізоди",
"movies": "Відсутні фільми",
"providers": "Проблеми p постачальником",
"status": "Проблеми зі здоров'ям",
"option": {
"showMissingEpisodes": {
"label": "Показати відсутні епізоди",
"description": "Відображати кількість епізодів без субтититрів"
},
"showMissingMovies": {
"label": "Показати відсутні фільми",
"description": "Відобразити кількість фільмів без субтитрів"
},
"showProviderIssues": {
"label": "Показати проблеми постачальника",
"description": "Відображати кількість постачальника субтитрів з проблемами"
},
"showHealthIssues": {
"label": "Показувати проблеми зі здоров’ям",
"description": "Відображати кількість проблем зі здоров’ям Bazarr"
}
},
"error": {
"internalServerError": "Не вдалося отримати дані Bazarr"
}
},
"mediaMissing": {
"name": "Відсутня медіа в черзі",
"description": "Показує відсутні і в черзі фільми і епізоди з Radarr і Sonarr",
"option": {
"showMissing": {
"label": "Показати відсутні елементи"
},
"showQueued": {
"label": "Показати елементи в черзі"
},
"pageSize": {
"label": "Елементів на сторінці"
}
},
"tab": {
"missing": "Відсутні",
"queued": "У черзі"
},
"type": {
"movie": "Фільм",
"episode": "Епізод"
},
"empty": {
"missing": "Немає відсутніх елементів",
"queued": "Немає елементів у черзі",
"noTabsEnabled": "Увімкнути принаймні одну вкладку в налаштуваннях віджету"
},
"timeLeft": "Залишилося часу"
},
"traefik": {
"name": "Трафік",
"description": "Огляд маршрутизаторів, сервісів, проміжного програмного забезпечення та точок входу Traefik",
"option": {
"showTcp": {
"label": "Показати TCP"
},
"showUdp": {
"label": "Show UDP"
},
"showEntryPoints": {
"label": "Показувати точки входу"
}
},
"instances": "Traefik екземпляри",
"versionUnknown": "Версія невідома",
"summary": {
"routers": "Маршрутизатори",
"entryPoints": "Точки входу"
},
"resource": {
"routers": "Маршрутизатори",
"services": "Служби",
"middlewares": "Проміжне програмне забезпечення"
},
"status": {
"healthy": "Здоровий",
"errors": "{count} помилок",
"warnings": "{count} застережень"
},
"error": {
"internalServerError": "Неможливо отримати дані Traefik"
}
}
},
"widgetPreview": {
@@ -4551,11 +4336,11 @@
},
"navbar": {
"items": {
"workshop": "Workshop",
"home": "Головна",
"boards": "Дошки",
"apps": "Додатки",
"integrations": "Інтеграції",
"customWidgets": "Власні віджети",
"searchEngies": "Пошукові системи",
"medias": "Медіа",
"users": {
@@ -5694,6 +5479,9 @@
},
"navigationStructure": {
"manage": {
"workshop": {
"label": "Workshop"
},
"label": "Керувати",
"boards": {
"label": "Дошки"
@@ -5728,18 +5516,6 @@
"label": "Редагувати"
}
},
"custom-widgets": {
"label": "Користувальницькі віджети",
"new": {
"label": "Новий"
},
"edit": {
"label": "Редагувати",
"flow": {
"label": "Потік"
}
}
},
"users": {
"label": "Користувачі",
"create": {
+254 -488
View File
@@ -688,211 +688,6 @@
"add": "新增應用程式"
}
},
"customWidget": {
"page": {
"list": {
"title": "自訂小工具",
"noResults": "尚無自訂小工具。建立您的第一個!",
"loading": "正在讀取……"
},
"create": {
"title": "建立自訂小工具",
"subtitle": "定義 API URL、驗證方式以及如何顯示回應資料。"
},
"edit": {
"title": "編輯自訂小工具"
}
},
"action": {
"create": "建立",
"import": "匯入",
"save": "儲存",
"delete": "刪除自訂小工具",
"deleteConfirm": "確定要刪除 \"{name}\" 嗎?此動作無法復原。",
"export": "匯出",
"addMapping": "新增對應",
"addColumn": "新增欄",
"edit": "編輯",
"removeMapping": "移除對應",
"removeColumn": "移除欄",
"addItem": "新增項目",
"removeItem": "移除項目",
"addBar": "新增長條",
"duplicate": "複製",
"copyAiPrompt": "複製 AI 提示",
"enable": "啟用",
"disable": "停用",
"menu": "動作"
},
"field": {
"name": "名稱",
"description": "描述",
"iconUrl": "圖示網址",
"url": "網址",
"authType": "驗證類型",
"headerName": "標頭/查詢參數名稱",
"method": "方法",
"requestBody": "請求主體",
"displayType": "顯示類型",
"jsonPath": "JSON 路徑",
"jsonPathHint": "使用 JSONPath 語法來擷取值,例如 $.data.temperature 或 $.items[0].name",
"label": "標籤",
"unit": "單位",
"mappings": "對應",
"tablePath": "陣列 JSON 路徑",
"tablePathHint": "回應中陣列的路徑,例如 $.data.items",
"columns": "欄",
"header": "標頭",
"items": "項目",
"gridColumns": "網格欄",
"cardStyle": "卡片樣式",
"bars": "長條",
"valuePath": "值 JSON 路徑",
"maxPath": "最大值 JSON 路徑",
"showPercentage": "顯示百分比",
"barSize": "長條大小",
"goodValues": "良好值 (逗號分隔)",
"dotSize": "點大小",
"valueSize": "值大小",
"labelPosition": "標籤位置",
"kvLayout": "佈局",
"striped": "條紋列",
"compact": "精簡模式",
"maxHeight": "最大高度 (像素)",
"color": "顏色",
"buttonLabel": "按鈕標籤",
"buttonColor": "按鈕顏色",
"confirmText": "確認文字",
"confirmTextHint": "若設定,執行請求前會顯示確認對話框",
"successMessage": "成功訊息",
"successMessageHint": "執行成功後顯示的訊息",
"enabled": "已啟用",
"template": {
"label": "JSX 樣板",
"description": "Mantine JSX 樣板。透過資料綁定存取 API 回應欄位 (例如 data.name)。僅使用白名單中的組件。禁止: constructor, __proto__, eval, Function, window, document。"
}
},
"placeholder": {
"exampleLabel": "CPU 溫度",
"exampleLabelShort": "CPU 溫度",
"exampleHeader": "名稱",
"exampleUnit": "°C",
"iconUrl": "https://……",
"url": "https://api.example.com/api/v1/status",
"headerName": "X-API-Key",
"jsonPath": "$.data.value",
"tablePath": "$.data.items",
"columnJsonPath": "$.name",
"valuePath": "$.data.used",
"maxPath": "$.data.total",
"goodValues": "online, true, up",
"color": "blue"
},
"cardStyleOption": {
"filled": "填滿",
"outline": "外框",
"subtle": "細微"
},
"layoutOption": {
"list": "清單",
"grid": "網格"
},
"sizeOption": {
"sm": "小",
"md": "中",
"lg": "大",
"xl": "特大"
},
"labelPositionOption": {
"above": "上方",
"below": "下方"
},
"fieldset": {
"general": "一般",
"connection": "API 連線",
"display": "顯示設定"
},
"displayTypeDescription": {
"singleValue": "顯示一個帶有標籤和單位的擷取值",
"keyValue": "並排顯示多個帶有標籤的值",
"table": "以表格格式顯示資料列",
"statGrid": "以網格形式顯示彩色統計卡 — 類似 Pi-Hole 或 Speedtest 小工具",
"progressBars": "顯示使用量或完成度的進度條 — 適用於磁碟、記憶體、配額",
"statusIndicator": "彩色狀態點顯示線上/離線或健康狀態",
"countGrid": "在緊湊的網格中顯示精簡的數字 + 標籤計數器",
"raw": "用於偵錯的美化 JSON 輸出",
"actionButton": "點擊時觸發請求的按鈕",
"customJsx": "使用白名單 Mantine 組件的自訂 JSX 佈局,具有完整的 API 資料綁定"
},
"method": {
"GET": "GET",
"POST": "POST",
"PUT": "PUT",
"DELETE": "DELETE",
"PATCH": "PATCH"
},
"authType": {
"none": "無",
"bearer": "Bearer 令牌",
"basic": "基本驗證",
"apiKeyHeader": "API 金鑰 (標頭)",
"apiKeyQuery": "API 金鑰 (查詢)"
},
"displayType": {
"singleValue": "單一值",
"keyValue": "鍵值",
"table": "表格",
"statGrid": "統計網格",
"progressBars": "進度條",
"statusIndicator": "狀態指示器",
"countGrid": "計數網格",
"raw": "原始 JSON",
"actionButton": "動作按鈕",
"customJsx": "自訂 JSX"
},
"secret": {
"apiKey": "API 金鑰 / 令牌",
"username": "使用者名稱",
"password": "密碼",
"savedPlaceholder": "••••••• (已儲存,留空則保持不變)"
},
"preview": {
"title": "預覽",
"test": "測試",
"hint": "點擊「測試」以用目前設定預覽 API 回應。",
"rawResponse": "原始 JSON 回應"
},
"notification": {
"created": "小工具 \"{name}\" 建立成功。",
"updated": "小工具 \"{name}\" 更新成功。",
"deleted": "小工具 \"{name}\" 已刪除。",
"imported": "小工具匯入成功。",
"aiPromptCopied": "AI 提示已複製到剪貼簿",
"aiPromptDescription": "複製預先構建的提示,貼到任何 AI 聊天機器人 (ChatGPT、Claude、Gemini...)。其中包含完整的小工具綱要和您的 API 回應,讓 AI 能為您產生可直接匯入的 JSON 設定。",
"aiPromptCopy": "複製到剪貼簿",
"aiPromptNoResponse": "提示: 先執行測試將您的 API 回應包含在提示中,以獲得更好的結果。",
"aiPromptCopyError": "無法將提示複製到剪貼簿。您的瀏覽器可能不支援此功能。",
"createError": "建立小工具失敗。請檢查 API 端點是否可達。",
"updateError": "更新小工具失敗。您的變更未被儲存。",
"importError": "匯入小工具失敗。請確保檔案是有效的自訂小工具 JSON 匯出。",
"exportError": "匯出小工具失敗。",
"duplicated": "小工具 \"{name}\" 已複製。",
"duplicateError": "複製小工具失敗。",
"toggleError": "切換小工具狀態失敗。",
"deleteError": "刪除小工具失敗。",
"previewError": "無法取得預覽。請檢查網址並重試。",
"executed": "動作執行成功。",
"executeError": "動作失敗: {error}"
},
"table": {
"name": "名稱",
"url": "網址",
"display": "顯示"
},
"widget": {
"disabled": "此小工具已停用"
}
},
"integration": {
"page": {
"list": {
@@ -2828,193 +2623,6 @@
"internalServerError": "無法取得 Paperless-ngx 資料"
}
},
"patchmon": {
"name": "PatchMon",
"description": "來自 PatchMon 的主機修補狀態概覽",
"title": "PatchMon 統計",
"totalHosts": "主機總數",
"hostsNeedingUpdates": "需要更新",
"securityUpdates": "安全性更新",
"upToDateHosts": "已更新至最新",
"hostsWithSecurityUpdates": "有安全性更新的主機",
"recentUpdates24h": "更新 (24h)",
"totalOutdatedPackages": "過時套件",
"totalRepos": "儲存庫",
"osDistribution": "作業系統分佈",
"compliance": "修補合規性",
"complianceRatio": "{upToDate} / {total}",
"lastUpdated": "更新於 {time}",
"option": {
"showTotalHosts": {
"label": "顯示主機總數",
"description": "顯示受監控的主機總數"
},
"showHostsNeedingUpdates": {
"label": "顯示需要更新的主機",
"description": "顯示至少有一個過時套件的主機"
},
"showSecurityUpdates": {
"label": "顯示安全性更新總數",
"description": "顯示可用的安全性更新總數"
},
"showUpToDateHosts": {
"label": "顯示已更新至最新主機",
"description": "顯示沒有任何過時套件的主機"
},
"showHostsWithSecurityUpdates": {
"label": "顯示有安全性更新的主機",
"description": "顯示需要安全性修補的主機"
},
"showRecentUpdates24h": {
"label": "顯示近期更新 (24h)",
"description": "顯示過去 24 小時內已套用的更新數量"
},
"showTotalOutdatedPackages": {
"label": "顯示過時套件總數",
"description": "顯示所有主機上過時套件的總數"
},
"showTotalRepos": {
"label": "顯示儲存庫數量",
"description": "顯示正在監控的活躍儲存庫數量"
},
"enableThresholdColors": {
"label": "啟用閾值顏色",
"description": "根據嚴重性預設將統計值著色為綠色、黃色或紅色"
},
"useCustomThresholds": {
"label": "進階閾值",
"description": "使用絕對計數或主機總數百分比,對每個統計值自訂警告和嚴重閾值"
},
"thresholdMode": {
"option": {
"absolute": "絕對計數",
"percent": "主機總數百分比"
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "需要更新閾值模式",
"description": "以絕對值或主機總數百分比比較需要更新的計數"
},
"hostsNeedingUpdatesWarningAt": {
"label": "需要更新警告閾值",
"description": "數值達到此閾值時轉為黃色"
},
"hostsNeedingUpdatesCriticalAt": {
"label": "需要更新嚴重閾值",
"description": "數值達到此閾值時轉為紅色"
},
"securityUpdatesThresholdMode": {
"label": "安全性更新閾值模式",
"description": "以絕對值或主機總數百分比比較安全性更新的計數"
},
"securityUpdatesWarningAt": {
"label": "安全性更新警告閾值",
"description": "數值達到此閾值時轉為黃色"
},
"securityUpdatesCriticalAt": {
"label": "安全性更新嚴重閾值",
"description": "數值達到此閾值時轉為紅色"
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "有安全性更新主機閾值模式",
"description": "以絕對值或主機總數百分比比較主機計數"
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "有安全性更新主機警告閾值",
"description": "數值達到此閾值時轉為黃色"
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "有安全性更新主機嚴重閾值",
"description": "數值達到此閾值時轉為紅色"
},
"upToDateHostsThresholdMode": {
"label": "已更新至最新主機閾值模式",
"description": "以絕對值或主機總數百分比比較已更新至最新主機計數"
},
"upToDateHostsWarningAt": {
"label": "已更新至最新主機警告閾值",
"description": "數值達到或高於此閾值但低於全覆蓋時轉為黃色"
},
"upToDateHostsCriticalAt": {
"label": "已更新至最新主機嚴重閾值",
"description": "數值低於此閾值時轉為紅色"
},
"totalOutdatedPackagesThresholdMode": {
"label": "過時套件閾值模式",
"description": "以絕對值或主機總數百分比比較過時套件計數"
},
"totalOutdatedPackagesWarningAt": {
"label": "過時套件警告閾值",
"description": "數值達到此閾值時轉為黃色"
},
"totalOutdatedPackagesCriticalAt": {
"label": "過時套件嚴重閾值",
"description": "數值達到此閾值時轉為紅色"
},
"showOsDistribution": {
"label": "顯示作業系統分佈",
"description": "顯示按作業系統細分的受監控主機"
},
"osDistributionLimit": {
"label": "作業系統分佈限制",
"description": "最多顯示的作業系統數量",
"option": {
"3": "前 3 名",
"5": "前 5 名",
"10": "前 10 名",
"all": "全部"
}
},
"showOsVersion": {
"label": "顯示作業系統版本",
"description": "當可用時,在每個分佈標籤後附加作業系統版本"
},
"showComplianceHero": {
"label": "顯示合規性英雄",
"description": "顯示一個合規性環,展示已更新至最新主機的百分比"
},
"osDisplayMode": {
"label": "作業系統顯示模式",
"description": "選擇如何顯示作業系統分佈",
"option": {
"bars": "水平長條",
"donut": "甜甜圈圖"
}
}
},
"error": {
"internalServerError": "無法擷取 PatchMon 資料"
}
},
"bazarr": {
"name": "Bazarr",
"description": "來自 Bazarr 實例的缺少字幕和健康狀態概覽",
"episodes": "缺少的集數",
"movies": "缺少的電影",
"providers": "提供者問題",
"status": "健康問題",
"option": {
"showMissingEpisodes": {
"label": "顯示缺少的集數",
"description": "顯示缺少字幕的集數數量"
},
"showMissingMovies": {
"label": "顯示缺少的電影",
"description": "顯示缺少字幕的電影數量"
},
"showProviderIssues": {
"label": "顯示提供者問題",
"description": "顯示有問題的字幕提供者數量"
},
"showHealthIssues": {
"label": "顯示健康問題",
"description": "顯示 Bazarr 健康問題的數量"
}
},
"error": {
"internalServerError": "無法擷取 Bazarr 資料"
}
},
"immich-serverStats": {
"name": "",
"description": "",
@@ -3387,35 +2995,6 @@
}
}
},
"mediaMissing": {
"name": "缺少和佇列中的媒體",
"description": "顯示來自 Radarr 和 Sonarr 的缺少和佇列中的電影及影集",
"option": {
"showMissing": {
"label": "顯示缺少的項目"
},
"showQueued": {
"label": "顯示佇列中的項目"
},
"pageSize": {
"label": "每頁項目數"
}
},
"tab": {
"missing": "缺少",
"queued": "佇列中"
},
"type": {
"movie": "電影",
"episode": "集數"
},
"empty": {
"missing": "沒有缺少的項目",
"queued": "沒有佇列中的項目",
"noTabsEnabled": "在小工具設定中至少啟用一個分頁"
},
"timeLeft": "剩餘時間"
},
"rssFeed": {
"name": "RSS 訂閱",
"description": "顯示一個或多個 RSS、ATOM、JSON 源",
@@ -3744,40 +3323,6 @@
"internalServerError": "無法取得運作時間資料"
}
},
"traefik": {
"name": "Traefik",
"description": "Traefik 路由器、服務、中間件和入口點概覽",
"option": {
"showTcp": {
"label": "顯示 TCP"
},
"showUdp": {
"label": "顯示 UDP"
},
"showEntryPoints": {
"label": "顯示入口點"
}
},
"instances": "Traefik 實例",
"versionUnknown": "版本未知",
"summary": {
"routers": "路由器",
"entryPoints": "入口點"
},
"resource": {
"routers": "路由器",
"services": "服務",
"middlewares": "中間件"
},
"status": {
"healthy": "健康",
"errors": "{count} 個錯誤",
"warnings": "{count} 個警告"
},
"error": {
"internalServerError": "無法擷取 Traefik 資料"
}
},
"audioStats": {
"name": "音訊統計",
"description": "來自 Navidrome 或 Audiobookshelf 的資料庫和播放統計資料",
@@ -3901,26 +3446,6 @@
"unhealthy": ""
}
},
"customApi": {
"name": "自訂 API",
"description": "使用自訂設定顯示來自任何外部 API 的資料。",
"option": {
"definitionId": {
"label": "定義 ID"
},
"refreshInterval": {
"label": "重新整理間隔",
"description": "從 API 重新擷取資料的頻率 (秒)"
}
},
"noDefinition": "未選擇定義",
"definitionNotFound": "找不到小工具定義。可能已被刪除。",
"noDisplayOutput": "無顯示輸出",
"executeConfirm": "確定要執行此動作嗎?",
"executing": "正在執行……",
"executeSuccess": "動作執行成功",
"executeFailed": "動作失敗。請檢查小工具設定。"
},
"beszelSystemTable": {
"name": "Beszel 系統(表格)",
"description": "所有 Beszel 監控系統的表格檢視,帶有可排序的欄位和狀態指示器",
@@ -4171,6 +3696,256 @@
"subtitle": "Docker 容器的網路流量"
}
}
},
"patchmon": {
"name": "PatchMon",
"description": "來自 PatchMon 的主機修補狀態概覽",
"title": "PatchMon 統計",
"totalHosts": "主機總數",
"hostsNeedingUpdates": "需要更新",
"securityUpdates": "安全性更新",
"upToDateHosts": "已更新至最新",
"hostsWithSecurityUpdates": "有安全性更新的主機",
"recentUpdates24h": "更新 (24h)",
"totalOutdatedPackages": "過時套件",
"totalRepos": "儲存庫",
"osDistribution": "作業系統分佈",
"compliance": "修補合規性",
"complianceRatio": "{upToDate} / {total}",
"lastUpdated": "更新於 {time}",
"option": {
"showTotalHosts": {
"label": "顯示主機總數",
"description": "顯示受監控的主機總數"
},
"showHostsNeedingUpdates": {
"label": "顯示需要更新的主機",
"description": "顯示至少有一個過時套件的主機"
},
"showSecurityUpdates": {
"label": "顯示安全性更新總數",
"description": "顯示可用的安全性更新總數"
},
"showUpToDateHosts": {
"label": "顯示已更新至最新主機",
"description": "顯示沒有任何過時套件的主機"
},
"showHostsWithSecurityUpdates": {
"label": "顯示有安全性更新的主機",
"description": "顯示需要安全性修補的主機"
},
"showRecentUpdates24h": {
"label": "顯示近期更新 (24h)",
"description": "顯示過去 24 小時內已套用的更新數量"
},
"showTotalOutdatedPackages": {
"label": "顯示過時套件總數",
"description": "顯示所有主機上過時套件的總數"
},
"showTotalRepos": {
"label": "顯示儲存庫數量",
"description": "顯示正在監控的活躍儲存庫數量"
},
"enableThresholdColors": {
"label": "啟用閾值顏色",
"description": "根據嚴重性預設將統計值著色為綠色、黃色或紅色"
},
"useCustomThresholds": {
"label": "進階閾值",
"description": "使用絕對計數或主機總數百分比,對每個統計值自訂警告和嚴重閾值"
},
"thresholdMode": {
"option": {
"absolute": "絕對計數",
"percent": "主機總數百分比"
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "需要更新閾值模式",
"description": "以絕對值或主機總數百分比比較需要更新的計數"
},
"hostsNeedingUpdatesWarningAt": {
"label": "需要更新警告閾值",
"description": "數值達到此閾值時轉為黃色"
},
"hostsNeedingUpdatesCriticalAt": {
"label": "需要更新嚴重閾值",
"description": "數值達到此閾值時轉為紅色"
},
"securityUpdatesThresholdMode": {
"label": "安全性更新閾值模式",
"description": "以絕對值或主機總數百分比比較安全性更新的計數"
},
"securityUpdatesWarningAt": {
"label": "安全性更新警告閾值",
"description": "數值達到此閾值時轉為黃色"
},
"securityUpdatesCriticalAt": {
"label": "安全性更新嚴重閾值",
"description": "數值達到此閾值時轉為紅色"
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "有安全性更新主機閾值模式",
"description": "以絕對值或主機總數百分比比較主機計數"
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "有安全性更新主機警告閾值",
"description": "數值達到此閾值時轉為黃色"
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "有安全性更新主機嚴重閾值",
"description": "數值達到此閾值時轉為紅色"
},
"upToDateHostsThresholdMode": {
"label": "已更新至最新主機閾值模式",
"description": "以絕對值或主機總數百分比比較已更新至最新主機計數"
},
"upToDateHostsWarningAt": {
"label": "已更新至最新主機警告閾值",
"description": "數值達到或高於此閾值但低於全覆蓋時轉為黃色"
},
"upToDateHostsCriticalAt": {
"label": "已更新至最新主機嚴重閾值",
"description": "數值低於此閾值時轉為紅色"
},
"totalOutdatedPackagesThresholdMode": {
"label": "過時套件閾值模式",
"description": "以絕對值或主機總數百分比比較過時套件計數"
},
"totalOutdatedPackagesWarningAt": {
"label": "過時套件警告閾值",
"description": "數值達到此閾值時轉為黃色"
},
"totalOutdatedPackagesCriticalAt": {
"label": "過時套件嚴重閾值",
"description": "數值達到此閾值時轉為紅色"
},
"showOsDistribution": {
"label": "顯示作業系統分佈",
"description": "顯示按作業系統細分的受監控主機"
},
"osDistributionLimit": {
"label": "作業系統分佈限制",
"description": "最多顯示的作業系統數量",
"option": {
"3": "前 3 名",
"5": "前 5 名",
"10": "前 10 名",
"all": "全部"
}
},
"showOsVersion": {
"label": "顯示作業系統版本",
"description": "當可用時,在每個分佈標籤後附加作業系統版本"
},
"showComplianceHero": {
"label": "顯示合規性英雄",
"description": "顯示一個合規性環,展示已更新至最新主機的百分比"
},
"osDisplayMode": {
"label": "作業系統顯示模式",
"description": "選擇如何顯示作業系統分佈",
"option": {
"bars": "水平長條",
"donut": "甜甜圈圖"
}
}
},
"error": {
"internalServerError": "無法擷取 PatchMon 資料"
}
},
"bazarr": {
"name": "Bazarr",
"description": "來自 Bazarr 實例的缺少字幕和健康狀態概覽",
"episodes": "缺少的集數",
"movies": "缺少的電影",
"providers": "提供者問題",
"status": "健康問題",
"option": {
"showMissingEpisodes": {
"label": "顯示缺少的集數",
"description": "顯示缺少字幕的集數數量"
},
"showMissingMovies": {
"label": "顯示缺少的電影",
"description": "顯示缺少字幕的電影數量"
},
"showProviderIssues": {
"label": "顯示提供者問題",
"description": "顯示有問題的字幕提供者數量"
},
"showHealthIssues": {
"label": "顯示健康問題",
"description": "顯示 Bazarr 健康問題的數量"
}
},
"error": {
"internalServerError": "無法擷取 Bazarr 資料"
}
},
"mediaMissing": {
"name": "缺少和佇列中的媒體",
"description": "顯示來自 Radarr 和 Sonarr 的缺少和佇列中的電影及影集",
"option": {
"showMissing": {
"label": "顯示缺少的項目"
},
"showQueued": {
"label": "顯示佇列中的項目"
},
"pageSize": {
"label": "每頁項目數"
}
},
"tab": {
"missing": "缺少",
"queued": "佇列中"
},
"type": {
"movie": "電影",
"episode": "集數"
},
"empty": {
"missing": "沒有缺少的項目",
"queued": "沒有佇列中的項目",
"noTabsEnabled": "在小工具設定中至少啟用一個分頁"
},
"timeLeft": "剩餘時間"
},
"traefik": {
"name": "Traefik",
"description": "Traefik 路由器、服務、中間件和入口點概覽",
"option": {
"showTcp": {
"label": "顯示 TCP"
},
"showUdp": {
"label": "顯示 UDP"
},
"showEntryPoints": {
"label": "顯示入口點"
}
},
"instances": "Traefik 實例",
"versionUnknown": "版本未知",
"summary": {
"routers": "路由器",
"entryPoints": "入口點"
},
"resource": {
"routers": "路由器",
"services": "服務",
"middlewares": "中間件"
},
"status": {
"healthy": "健康",
"errors": "{count} 個錯誤",
"warnings": "{count} 個警告"
},
"error": {
"internalServerError": "無法擷取 Traefik 資料"
}
}
},
"widgetPreview": {
@@ -4551,11 +4326,11 @@
},
"navbar": {
"items": {
"workshop": "Workshop",
"home": "首頁",
"boards": "面板",
"apps": "應用程式",
"integrations": "集成",
"customWidgets": "自訂小工具",
"searchEngies": "搜尋引擎",
"medias": "多媒體",
"users": {
@@ -5694,6 +5469,9 @@
},
"navigationStructure": {
"manage": {
"workshop": {
"label": "Workshop"
},
"label": "管理",
"boards": {
"label": "面板"
@@ -5728,18 +5506,6 @@
"label": "編輯"
}
},
"custom-widgets": {
"label": "自訂小工具",
"new": {
"label": "新增"
},
"edit": {
"label": "編輯",
"flow": {
"label": "流程"
}
}
},
"users": {
"label": "使用者",
"create": {
+4 -1
View File
@@ -116,7 +116,10 @@ export default function AppWidget({ options, isEditMode, height, width }: Widget
/>
</Flex>
</AppDescriptionTooltip>
{options.pingEnabled && !settings.forceDisableStatus && !board.disableStatus && app.href ? (
{options.pingEnabled &&
!settings.forceDisableStatus &&
!board.disableStatus &&
Boolean(app.pingUrl ?? app.href) ? (
<Suspense fallback={<PingDot icon={IconMinus} color="gray" tooltip={`${t("common.action.loading")}…`} />}>
<PingIndicator appId={app.id} />
</Suspense>
@@ -16,6 +16,7 @@ import {
VisuallyHidden,
} from "@mantine/core";
import { IconBellOff, IconCircleCheck, IconFlame, IconHistory } from "@tabler/icons-react";
import { getQueryKey } from "@trpc/react-query";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import type { LucideIcon } from "lucide-react";
@@ -27,6 +28,10 @@ import { useScopedI18n } from "@homarr/translation/client";
import type { WidgetComponentProps } from "../definition";
import { IntegrationErrorIndicator } from "../common/integration-error-indicator";
import { getUsableWidgetQueryData } from "../common/query-state";
import { WidgetQueryErrorIndicator } from "../common/query-state-indicator";
import { useWidgetRuntimeQueries } from "../runtime-hooks";
import { getBeszelAlertsQueryInput } from "./display";
import { buildBeszelSystemNameMap, getBeszelSystemName } from "./system-name-map";
const alertIconMap: Record<string, LucideIcon> = {
CPU: Cpu,
@@ -50,43 +55,64 @@ export default function BeszelAlertsWidget({
integrationIds,
isEditMode,
height,
displayMode,
widgetRuntimeRef,
}: WidgetComponentProps<"beszelAlerts">) {
const t = useScopedI18n("widget.beszelAlerts");
const isAdvanced = displayMode === "advanced";
const alertsInput = useMemo(
() => ({ integrationIds, includeHistory: options.showHistory, maxHistoryItems: options.maxHistoryItems }),
[integrationIds, options.showHistory, options.maxHistoryItems],
() =>
getBeszelAlertsQueryInput(
integrationIds,
{ showHistory: options.showHistory, maxHistoryItems: options.maxHistoryItems },
isAdvanced,
),
[integrationIds, options.showHistory, options.maxHistoryItems, isAdvanced],
);
const alertsQuery = clientApi.widget.beszel.getAlerts.useQuery(alertsInput);
const results = getUsableWidgetQueryData(alertsQuery) ?? [];
const runtimeQueries = useMemo(
() => [getQueryKey(clientApi.widget.beszel.getAlerts, alertsInput, "query")],
[alertsInput],
);
useWidgetRuntimeQueries(widgetRuntimeRef, runtimeQueries);
const resultData = getUsableWidgetQueryData(alertsQuery);
const results = useMemo(() => resultData ?? [], [resultData]);
const { isPending } = alertsQuery;
const systemNameMap = useMemo(() => {
const map: Record<string, string> = {};
for (const r of results) {
if (r.systemNameMap) {
Object.assign(map, r.systemNameMap);
}
}
return map;
}, [results]);
const systemNameMap = useMemo(() => buildBeszelSystemNameMap(results), [results]);
const showIntegrationName = isAdvanced || results.length > 1;
const alerts = useMemo(
() => results.flatMap((r) => r.alerts.map((a) => ({ ...a, _key: `${r.integrationId}:${a.id}` }))),
() =>
results.flatMap((r) =>
r.alerts.map((a) => ({
...a,
integrationId: r.integrationId,
integrationName: r.integrationName,
key: `${r.integrationId}:${a.id}`,
})),
),
[results],
);
const history = useMemo(() => {
const all = results.flatMap((r) => r.history.map((h) => ({ ...h, _key: `${r.integrationId}:${h.id}` })));
return all
.toSorted((a, b) => new Date(b.created).getTime() - new Date(a.created).getTime())
.slice(0, options.maxHistoryItems);
}, [results, options.maxHistoryItems]);
const all = results.flatMap((r) =>
r.history.map((h) => ({
...h,
integrationId: r.integrationId,
integrationName: r.integrationName,
key: `${r.integrationId}:${h.id}`,
})),
);
const sorted = all.toSorted((a, b) => new Date(b.created).getTime() - new Date(a.created).getTime());
return isAdvanced ? sorted : sorted.slice(0, options.maxHistoryItems);
}, [results, options.maxHistoryItems, isAdvanced]);
const triggeredAlerts = alerts.filter((a) => a.triggered);
const okAlerts = alerts.filter((a) => !a.triggered);
const showOkAlerts = triggeredAlerts.length === 0 || height >= 260;
const showHistory = options.showHistory && height >= 360;
const showAlertDescriptions = height >= 190;
const showOkAlerts = isAdvanced || triggeredAlerts.length === 0 || height >= 260;
const showHistory = isAdvanced || (options.showHistory && height >= 360);
const showAlertDescriptions = isAdvanced || height >= 190;
if (isPending) {
return (
@@ -99,7 +125,10 @@ export default function BeszelAlertsWidget({
return (
<Box h="100%" pos="relative">
<Box pos="absolute" top={4} right={8} style={{ zIndex: 1 }}>
<IntegrationErrorIndicator results={results} />
<Group gap={0}>
<WidgetQueryErrorIndicator error={alertsQuery.error} label={t("name")} />
<IntegrationErrorIndicator results={results} />
</Group>
</Box>
<ScrollArea h="100%" style={{ pointerEvents: isEditMode ? "none" : undefined }}>
<Stack gap="sm" p="sm">
@@ -124,11 +153,12 @@ export default function BeszelAlertsWidget({
</Group>
{triggeredAlerts.map((alert) => (
<AlertRow
key={alert._key}
key={alert.key}
name={alert.name}
value={alert.value}
min={alert.min}
systemName={systemNameMap[alert.system] ?? alert.system}
systemName={getBeszelSystemName(systemNameMap, alert.integrationId, alert.system)}
integrationName={showIntegrationName ? alert.integrationName : undefined}
triggered
showDescription={showAlertDescriptions}
/>
@@ -148,11 +178,12 @@ export default function BeszelAlertsWidget({
</Group>
{okAlerts.map((alert) => (
<AlertRow
key={alert._key}
key={alert.key}
name={alert.name}
value={alert.value}
min={alert.min}
systemName={systemNameMap[alert.system] ?? alert.system}
systemName={getBeszelSystemName(systemNameMap, alert.integrationId, alert.system)}
integrationName={showIntegrationName ? alert.integrationName : undefined}
triggered={false}
showDescription={showAlertDescriptions}
/>
@@ -171,11 +202,12 @@ export default function BeszelAlertsWidget({
</Text>
</Group>
{history.map((entry) => {
const systemName = systemNameMap[entry.system] ?? entry.system;
const systemName = getBeszelSystemName(systemNameMap, entry.integrationId, entry.system);
const systemLabel = showIntegrationName ? `${systemName} · ${entry.integrationName}` : systemName;
const isResolved = !!entry.resolved;
const HistoryIcon = alertIconMap[entry.name] ?? Server;
return (
<Group key={entry._key} justify="space-between" wrap="nowrap" gap="xs" pl={4}>
<Group key={entry.key} justify="space-between" wrap="nowrap" gap="xs" pl={4}>
<Group gap="xs" wrap="nowrap" style={{ minWidth: 0 }}>
<Box
w={3}
@@ -189,7 +221,7 @@ export default function BeszelAlertsWidget({
{entry.name}
</Text>
<Text size="xs" c="dimmed" truncate>
{systemName}
{systemLabel}
</Text>
</Stack>
</Group>
@@ -218,6 +250,7 @@ interface AlertRowProps {
value: number;
min: number;
systemName: string;
integrationName?: string;
triggered: boolean;
showDescription: boolean;
}
@@ -243,7 +276,7 @@ function formatAlertDescription(name: string, value: number, min: number): strin
return `exceeds ${value}${suffix} over ${min} min`;
}
function AlertRow({ name, value, min, systemName, triggered, showDescription }: AlertRowProps) {
function AlertRow({ name, value, min, systemName, integrationName, triggered, showDescription }: AlertRowProps) {
const Icon = alertIconMap[name] ?? Server;
const description = formatAlertDescription(name, value, min);
return (
@@ -263,7 +296,7 @@ function AlertRow({ name, value, min, systemName, triggered, showDescription }:
<Stack gap={0} style={{ flex: 1, minWidth: 0 }}>
<Group gap={6} wrap="nowrap">
<Text size="xs" fw={600} truncate>
{systemName}
{integrationName ? `${systemName} · ${integrationName}` : systemName}
</Text>
<Text size="xs" c="dimmed">
·
+8 -5
View File
@@ -1,19 +1,22 @@
import { IconBell, IconServerOff } from "@tabler/icons-react";
import { z } from "zod/v4";
import { createWidgetDefinition, widgetQueryInputMatches } from "../definition";
import { createWidgetDefinition, matchesWidgetRuntimeQuery, widgetQueryInputMatches } from "../definition";
import { optionsBuilder } from "../options";
export const { definition, componentLoader } = createWidgetDefinition("beszelAlerts", {
icon: IconBell,
supportsAdvancedFocus: false,
queryKey: [["widget", "beszel", "getAlerts"]],
queryMatcher: ({ input }, scope) =>
widgetQueryInputMatches(input, {
queryMatcher(query, scope) {
const hasRuntimeAlertsQuery = scope.runtimeQueries.some(({ path }) => path.at(-1) === "getAlerts");
if (hasRuntimeAlertsQuery) return matchesWidgetRuntimeQuery(query, scope);
return widgetQueryInputMatches(query.input, {
integrationIds: scope.integrationIds,
includeHistory: scope.options.showHistory,
maxHistoryItems: scope.options.maxHistoryItems,
}),
});
},
supportedIntegrations: ["beszel", "mock"],
integrationsRequired: true,
createOptions() {
@@ -1,7 +1,7 @@
"use client";
import type { MantineSize } from "@mantine/core";
import { Badge, Box, Card, Center, Group, Loader, Progress, Text, Stack } from "@mantine/core";
import { Badge, Box, Card, Center, Group, Loader, Progress, SimpleGrid, Stack, Text } from "@mantine/core";
import {
Activity,
Battery,
@@ -19,6 +19,7 @@ import { IconServerOff } from "@tabler/icons-react";
import { clientApi } from "@homarr/api/client";
import { useRequiredBoard } from "@homarr/boards/context";
import { formatBytes } from "@homarr/common";
import { useModalAction } from "@homarr/modals";
import { useScopedI18n } from "@homarr/translation/client";
@@ -38,8 +39,10 @@ import {
import { useBeszelFilteredSystems } from "../beszel/_shared/hooks";
import { IntegrationErrorIndicator } from "../common/integration-error-indicator";
import { getUsableWidgetQueryData } from "../common/query-state";
import { WidgetQueryErrorIndicator } from "../common/query-state-indicator";
import { BeszelSystemStatsModal } from "../beszel/_shared/system-stats-modal";
import { DiskUsage } from "../beszel/_shared/disk-usage";
import { isBeszelGridMetricVisible } from "./display";
interface SizeConfig {
iconSize: number;
@@ -117,10 +120,12 @@ const getMaxVisibleMetrics = (cellHeight: number, size: SizeConfig): number => {
const MIN_CELL_WIDTH = 140;
const MIN_CELL_HEIGHT = 80;
const ADVANCED_MIN_CELL_WIDTH = 320;
const ADVANCED_MIN_CELL_HEIGHT = 420;
const getColCount = (width: number, _height: number, itemCount: number): number => {
const getColCount = (width: number, _height: number, itemCount: number, minCellWidth = MIN_CELL_WIDTH): number => {
if (itemCount <= 1) return 1;
const maxCols = Math.min(itemCount, Math.max(1, Math.floor(width / MIN_CELL_WIDTH)));
const maxCols = Math.min(itemCount, Math.max(1, Math.floor(width / minCellWidth)));
let best = 1;
for (let c = 1; c <= maxCols; c++) {
@@ -168,12 +173,14 @@ const MetricRow = ({ icon, label, value, progress, size }: MetricRowProps) => (
);
interface SystemCardProps {
system: BeszelSystemRow & { _key: string };
system: BeszelSystemRow & { rowKey: string };
options: WidgetComponentProps<"beszelSystemGrid">["options"];
t: ReturnType<typeof useScopedI18n<"widget.beszelSystemGrid">>;
size: SizeConfig;
maxMetrics: number;
itemRadius: MantineSize;
integrationName: string;
isAdvanced: boolean;
onClick?: () => void;
}
@@ -190,7 +197,8 @@ const metricRenderers = [
size={sz}
/>
),
visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showCpu,
visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) =>
isBeszelGridMetricVisible(o.showCpu, advanced),
},
{
key: "showMemory",
@@ -204,7 +212,8 @@ const metricRenderers = [
size={sz}
/>
),
visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showMemory,
visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) =>
isBeszelGridMetricVisible(o.showMemory, advanced),
},
{
key: "showDisk",
@@ -217,7 +226,8 @@ const metricRenderers = [
<DiskUsage system={s} fontSize={sz.fontSize} progressSize={sz.progressSize} valueMiw={sz.valueMiw} />
</Group>
),
visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showDisk,
visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) =>
isBeszelGridMetricVisible(o.showDisk, advanced),
},
{
key: "showGpu",
@@ -231,7 +241,8 @@ const metricRenderers = [
size={sz}
/>
),
visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showGpu && s.gpu > 0,
visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) =>
isBeszelGridMetricVisible(o.showGpu, advanced, s.gpu > 0),
},
{
key: "showLoadAvg",
@@ -244,7 +255,8 @@ const metricRenderers = [
size={sz}
/>
),
visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showLoadAvg && s.loadAvg !== null,
visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) =>
isBeszelGridMetricVisible(o.showLoadAvg, advanced, s.loadAvg !== null),
},
{
key: "showNet",
@@ -257,7 +269,8 @@ const metricRenderers = [
size={sz}
/>
),
visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showNet,
visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) =>
isBeszelGridMetricVisible(o.showNet, advanced),
},
{
key: "showTemp",
@@ -270,7 +283,8 @@ const metricRenderers = [
size={sz}
/>
),
visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showTemp && s.temp !== null,
visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) =>
isBeszelGridMetricVisible(o.showTemp, advanced, s.temp !== null),
},
{
key: "showBattery",
@@ -287,7 +301,8 @@ const metricRenderers = [
/>
);
},
visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showBattery && s.battery !== null,
visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) =>
isBeszelGridMetricVisible(o.showBattery, advanced, s.battery !== null),
},
{
key: "showServices",
@@ -300,7 +315,8 @@ const metricRenderers = [
size={sz}
/>
),
visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showServices,
visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) =>
isBeszelGridMetricVisible(o.showServices, advanced),
},
{
key: "showUptime",
@@ -313,7 +329,8 @@ const metricRenderers = [
size={sz}
/>
),
visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showUptime,
visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) =>
isBeszelGridMetricVisible(o.showUptime, advanced),
},
{
key: "showAgent",
@@ -326,12 +343,23 @@ const metricRenderers = [
size={sz}
/>
),
visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showAgent,
visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) =>
isBeszelGridMetricVisible(o.showAgent, advanced),
},
] as const;
const SystemCard = ({ system, options, t, size, maxMetrics, itemRadius, onClick }: SystemCardProps) => {
const enabledMetrics = metricRenderers.filter((metric) => metric.visible(system, options));
const SystemCard = ({
system,
options,
t,
size,
maxMetrics,
itemRadius,
integrationName,
isAdvanced,
onClick,
}: SystemCardProps) => {
const enabledMetrics = metricRenderers.filter((metric) => metric.visible(system, options, isAdvanced));
const visibleMetrics = enabledMetrics.slice(0, maxMetrics);
const hiddenMetricCount = enabledMetrics.length - visibleMetrics.length;
@@ -368,6 +396,20 @@ const SystemCard = ({ system, options, t, size, maxMetrics, itemRadius, onClick
</Badge>
</Group>
{isAdvanced && (
<SimpleGrid cols={2} spacing={4} verticalSpacing={2} mb={4}>
<SystemMetadata label={t("metadata.hostname")} value={system.hostname || "—"} />
<SystemMetadata label={t("metadata.os")} value={system.osName || "—"} />
<SystemMetadata label={t("metadata.cpuModel")} value={system.cpuModel || "—"} />
<SystemMetadata label={t("metadata.cores")} value={String(system.cores)} />
<SystemMetadata
label={t("metadata.memoryTotal")}
value={system.memoryTotal > 0 ? formatBytes(system.memoryTotal) : "—"}
/>
<SystemMetadata label={t("metadata.source")} value={integrationName} />
</SimpleGrid>
)}
<Stack gap={0} style={{ flex: 1 }} justify="space-evenly">
{visibleMetrics.map((m) => m.render(system, t, size))}
</Stack>
@@ -380,12 +422,24 @@ const SystemCard = ({ system, options, t, size, maxMetrics, itemRadius, onClick
);
};
const SystemMetadata = ({ label, value }: { label: string; value: string }) => (
<Box style={{ minWidth: 0 }}>
<Text size="10px" c="dimmed">
{label}
</Text>
<Text size="xs" fw={500} truncate title={value}>
{value}
</Text>
</Box>
);
export default function BeszelSystemGridWidget({
options,
integrationIds,
isEditMode,
width,
height,
displayMode,
}: WidgetComponentProps<"beszelSystemGrid">) {
const t = useScopedI18n("widget.beszelSystemGrid");
const board = useRequiredBoard();
@@ -394,6 +448,8 @@ export default function BeszelSystemGridWidget({
const systemsQuery = clientApi.widget.beszel.getSystems.useQuery({ integrationIds });
const results = getUsableWidgetQueryData(systemsQuery) ?? [];
const { isPending } = systemsQuery;
const isAdvanced = displayMode === "advanced";
const integrationNames = new Map(results.map((result) => [result.integrationId, result.integrationName]));
const filteredSystems = useBeszelFilteredSystems(results, options.statusFilter);
@@ -408,7 +464,10 @@ export default function BeszelSystemGridWidget({
if (filteredSystems.length === 0) {
return (
<Box h="100%" pos="relative" style={{ pointerEvents: isEditMode ? "none" : undefined }}>
<IntegrationErrorIndicator results={results} />
<Group pos="absolute" top={4} right={8} gap={0} style={{ zIndex: 1 }}>
<WidgetQueryErrorIndicator error={systemsQuery.error} label={t("name")} />
<IntegrationErrorIndicator results={results} />
</Group>
<Center h="100%">
<Stack align="center" gap="xs">
<IconServerOff size={28} opacity={0.5} />
@@ -421,19 +480,23 @@ export default function BeszelSystemGridWidget({
);
}
const cols = getColCount(width, height, filteredSystems.length);
const minimumCellWidth = isAdvanced ? ADVANCED_MIN_CELL_WIDTH : MIN_CELL_WIDTH;
const cols = getColCount(width, height, filteredSystems.length, minimumCellWidth);
const rows = Math.ceil(filteredSystems.length / cols) || 1;
const rawCellHeight = height / rows;
const minimumCellHeight = MIN_CELL_HEIGHT;
const minimumCellHeight = isAdvanced ? ADVANCED_MIN_CELL_HEIGHT : MIN_CELL_HEIGHT;
const scrollEnabled = rawCellHeight < minimumCellHeight;
const effectiveCellHeight = scrollEnabled ? minimumCellHeight : rawCellHeight;
const cellWidth = width / cols;
const size = getSizeConfig(cellWidth, effectiveCellHeight);
const maxMetrics = getMaxVisibleMetrics(effectiveCellHeight, size);
const maxMetrics = isAdvanced ? Number.POSITIVE_INFINITY : getMaxVisibleMetrics(effectiveCellHeight, size);
return (
<Box h="100%" pos="relative" style={{ pointerEvents: isEditMode ? "none" : undefined }}>
<IntegrationErrorIndicator results={results} />
<Group pos="absolute" top={4} right={8} gap={0} style={{ zIndex: 1 }}>
<WidgetQueryErrorIndicator error={systemsQuery.error} label={t("name")} />
<IntegrationErrorIndicator results={results} />
</Group>
<Box
h="100%"
style={{
@@ -445,19 +508,22 @@ export default function BeszelSystemGridWidget({
}}
>
{filteredSystems.map((system) => {
const integrationId = system._key.split(":")[0] ?? "";
const integrationId = system.rowKey.split(":")[0] ?? "";
const integrationName = integrationNames.get(integrationId) ?? "—";
const handleClick = isEditMode
? undefined
: () => openModal({ integrationId, systemId: system.id }, { title: system.name });
return (
<SystemCard
key={system._key}
key={system.rowKey}
system={system}
options={options}
t={t}
size={size}
maxMetrics={maxMetrics}
itemRadius={board.itemRadius}
integrationName={integrationName}
isAdvanced={isAdvanced}
onClick={handleClick}
/>
);
@@ -6,7 +6,6 @@ import { optionsBuilder } from "../options";
export const { definition, componentLoader } = createWidgetDefinition("beszelSystemGrid", {
icon: IconLayoutGrid,
supportsAdvancedFocus: false,
queryKey: [["widget", "beszel", "getSystems"]],
supportedIntegrations: ["beszel", "mock"],
integrationsRequired: true,
@@ -19,6 +19,7 @@ import { useWidgetRuntimeQueries } from "../runtime-hooks";
import type { BeszelTimePeriod } from "../beszel/_shared/chart";
import { IntegrationErrorIndicator } from "../common/integration-error-indicator";
import { getUsableWidgetQueryData } from "../common/query-state";
import { WidgetQueryErrorIndicator } from "../common/query-state-indicator";
import { BeszelStatsView } from "../beszel/_shared/stats-view";
import { createBeszelSystemChoices, resolveBeszelSystemChoice } from "./selection";
@@ -46,7 +47,8 @@ export default function BeszelSystemStatsWidget({
}),
});
const systemsQuery = clientApi.widget.beszel.getSystems.useQuery({ integrationIds });
const systemsResult = getUsableWidgetQueryData(systemsQuery) ?? [];
const systemsData = getUsableWidgetQueryData(systemsQuery);
const systemsResult = useMemo(() => systemsData ?? [], [systemsData]);
const { isPending: systemsPending } = systemsQuery;
const systems = useMemo(() => createBeszelSystemChoices(systemsResult), [systemsResult]);
@@ -140,7 +142,10 @@ export default function BeszelSystemStatsWidget({
if (systems.length === 0) {
return (
<Box h="100%" pos="relative">
<IntegrationErrorIndicator results={systemsResult} />
<Group pos="absolute" top={4} right={8} gap={0} style={{ zIndex: 1 }}>
<WidgetQueryErrorIndicator error={systemsQuery.error} label={t("name")} />
<IntegrationErrorIndicator results={systemsResult} />
</Group>
<Center h="100%">
<Stack align="center" gap="xs">
<IconServerOff size={28} opacity={0.5} />
@@ -177,7 +182,10 @@ export default function BeszelSystemStatsWidget({
return (
<Box h="100%" pos="relative">
<Box pos="absolute" top={4} right={8} style={{ zIndex: 1 }}>
<IntegrationErrorIndicator results={systemsResult} />
<Group gap={0}>
<WidgetQueryErrorIndicator error={systemsQuery.error} label={t("name")} />
<IntegrationErrorIndicator results={systemsResult} />
</Group>
</Box>
<ScrollArea
h="100%"
@@ -16,7 +16,6 @@ const timePeriodOptions = [
];
export const { definition, componentLoader } = createWidgetDefinition("beszelSystemStats", {
supportsAdvancedFocus: false,
icon: IconChartAreaLine,
queryKeys: [[["widget", "beszel", "getSystems"]], [["widget", "beszel", "getSystemStats"]]],
queryMatcher(query, scope) {
@@ -20,6 +20,7 @@ import { clientApi } from "@homarr/api/client";
import { useSession } from "@homarr/auth/client";
import { constructBoardPermissions } from "@homarr/auth/shared";
import { useOptionalBoard } from "@homarr/boards/context";
import { formatBytes } from "@homarr/common";
import { useModalAction } from "@homarr/modals";
import { showErrorNotification } from "@homarr/notifications";
import { useScopedI18n } from "@homarr/translation/client";
@@ -40,15 +41,23 @@ import {
} from "../beszel/_shared/format";
import { useBeszelFilteredSystems } from "../beszel/_shared/hooks";
import { IntegrationErrorIndicator } from "../common/integration-error-indicator";
import { WidgetQueryErrorIndicator } from "../common/query-state-indicator";
import { BeszelSystemStatsModal } from "../beszel/_shared/system-stats-modal";
import { DiskUsage } from "../beszel/_shared/disk-usage";
import { getBeszelTableVisibleMetricKeys } from "./display";
const directionMultiplier: Record<string, number> = { asc: 1, desc: -1 };
type SystemRowWithKey = BeszelSystemRow & { _key: string };
type SystemRowWithKey = BeszelSystemRow & { rowKey: string; integrationName: string };
const columnAccessors = [
"name",
"integrationName",
"hostname",
"osName",
"cpuModel",
"cores",
"memoryTotal",
"cpu",
"memory",
"disk",
@@ -60,7 +69,7 @@ const columnAccessors = [
"services",
"uptime",
"agentVersion",
] as const satisfies readonly (keyof BeszelSystemRow)[];
] as const satisfies readonly (keyof SystemRowWithKey)[];
interface SizeConfig {
iconSize: number;
@@ -113,6 +122,7 @@ export default function BeszelSystemTableWidget({
boardId,
itemId,
setOptions,
displayMode,
}: WidgetComponentProps<"beszelSystemTable">) {
const t = useScopedI18n("widget.beszelSystemTable");
const { openModal } = useModalAction(BeszelSystemStatsModal);
@@ -120,26 +130,15 @@ export default function BeszelSystemTableWidget({
const { data: session } = useSession();
const hasChangeAccess = board ? constructBoardPermissions(board, session).hasChangeAccess : false;
const systemsQuery = clientApi.widget.beszel.getSystems.useQuery({ integrationIds });
const results = getUsableWidgetQueryData(systemsQuery) ?? [];
const systemsData = getUsableWidgetQueryData(systemsQuery);
const results = useMemo(() => systemsData ?? [], [systemsData]);
const { isPending } = systemsQuery;
const isAdvanced = displayMode === "advanced";
const size = useMemo(() => getSizeConfig(width), [width]);
const visibleMetricKeys = useMemo(() => {
const enabled = [
"showCpu",
"showMemory",
"showDisk",
"showGpu",
"showLoadAvg",
"showNet",
"showTemp",
"showBattery",
"showServices",
"showUptime",
"showAgent",
].filter((key) => options[key as keyof typeof options]) as string[];
const budget = width < 360 ? 1 : width < 560 ? 2 : width < 760 ? 4 : enabled.length;
return new Set(enabled.slice(0, budget));
}, [options, width]);
const visibleMetricKeys = useMemo(
() => getBeszelTableVisibleMetricKeys(options, width, isAdvanced),
[options, width, isAdvanced],
);
const { mutate: saveItemOptions } = clientApi.widget.options.saveItemOptions.useMutation({
onError: () =>
@@ -157,6 +156,18 @@ export default function BeszelSystemTableWidget({
});
const filteredSystems = useBeszelFilteredSystems(results, options.statusFilter);
const integrationNames = useMemo(
() => new Map(results.map((result) => [result.integrationId, result.integrationName])),
[results],
);
const systemsWithSource = useMemo(
() =>
filteredSystems.map((system) => ({
...system,
integrationName: integrationNames.get(system.rowKey.split(":")[0] ?? "") ?? "—",
})),
[filteredSystems, integrationNames],
);
const [sortStatus, setSortStatus] = useState<DataTableSortStatus<SystemRowWithKey>>({
columnAccessor: options.sortBy,
@@ -170,16 +181,16 @@ export default function BeszelSystemTableWidget({
}, [options.sortBy, options.sortDirection]);
const sortedSystems = useMemo(() => {
const accessor = sortStatus.columnAccessor as keyof BeszelSystemRow;
const accessor = sortStatus.columnAccessor as keyof SystemRowWithKey;
const dir = directionMultiplier[sortStatus.direction] ?? 1;
return [...filteredSystems].toSorted((a, b) => {
return [...systemsWithSource].toSorted((a, b) => {
const aVal = a[accessor] ?? 0;
const bVal = b[accessor] ?? 0;
if (typeof aVal === "string" && typeof bVal === "string") return aVal.localeCompare(bVal) * dir;
if (typeof aVal === "number" && typeof bVal === "number") return (aVal - bVal) * dir;
return 0;
});
}, [filteredSystems, sortStatus]);
}, [systemsWithSource, sortStatus]);
const columns = useMemo((): DataTableColumn<SystemRowWithKey>[] => {
const cols: (DataTableColumn<SystemRowWithKey> | false)[] = [
@@ -203,6 +214,54 @@ export default function BeszelSystemTableWidget({
</Group>
),
},
isAdvanced && {
accessor: "integrationName",
width: 140,
ellipsis: true,
title: t("column.source"),
sortable: true,
render: (record) => <Text size={size.fontSize}>{record.integrationName}</Text>,
},
isAdvanced && {
accessor: "hostname",
width: 150,
ellipsis: true,
title: t("column.hostname"),
sortable: true,
render: (record) => <Text size={size.fontSize}>{record.hostname || "—"}</Text>,
},
isAdvanced && {
accessor: "osName",
width: 160,
ellipsis: true,
title: t("column.os"),
sortable: true,
render: (record) => <Text size={size.fontSize}>{record.osName || "—"}</Text>,
},
isAdvanced && {
accessor: "cpuModel",
width: 220,
ellipsis: true,
title: t("column.cpuModel"),
sortable: true,
render: (record) => <Text size={size.fontSize}>{record.cpuModel || "—"}</Text>,
},
isAdvanced && {
accessor: "cores",
width: 80,
title: t("column.cores"),
sortable: true,
render: (record) => <Text size={size.fontSize}>{record.cores}</Text>,
},
isAdvanced && {
accessor: "memoryTotal",
width: 120,
title: t("column.memoryTotal"),
sortable: true,
render: (record) => (
<Text size={size.fontSize}>{record.memoryTotal > 0 ? formatBytes(record.memoryTotal) : "—"}</Text>
),
},
visibleMetricKeys.has("showCpu") && {
accessor: "cpu",
width: 140,
@@ -359,7 +418,7 @@ export default function BeszelSystemTableWidget({
];
return cols.filter(Boolean) as DataTableColumn<SystemRowWithKey>[];
}, [t, size, visibleMetricKeys]);
}, [t, size, visibleMetricKeys, isAdvanced]);
const { effectiveColumns, storeKey } = usePersistedTableLayout({
columns,
@@ -373,7 +432,7 @@ export default function BeszelSystemTableWidget({
const handleRowClick = useCallback(
({ record }: { record: SystemRowWithKey }) => {
const integrationId = record._key.split(":")[0] ?? "";
const integrationId = record.rowKey.split(":")[0] ?? "";
openModal({ integrationId, systemId: record.id }, { title: record.name });
},
[openModal],
@@ -390,7 +449,10 @@ export default function BeszelSystemTableWidget({
const table = (
<div style={{ position: "relative", height: "100%" }}>
<div style={{ position: "absolute", top: 4, right: 8, zIndex: 1 }}>
<IntegrationErrorIndicator results={results} />
<Group gap={0}>
<WidgetQueryErrorIndicator error={systemsQuery.error} label={t("name")} />
<IntegrationErrorIndicator results={results} />
</Group>
</div>
<HomarrDataTable
isEditMode={isEditMode}
@@ -401,7 +463,7 @@ export default function BeszelSystemTableWidget({
sortStatus={sortStatus}
onSortStatusChange={setSortStatus}
noRecordsText={t("noRecords")}
idAccessor="_key"
idAccessor="rowKey"
storeColumnsKey={storeKey}
onRowClick={isEditMode ? undefined : handleRowClick}
/>
@@ -25,7 +25,6 @@ const sortDirectionOptions = [
export const { definition, componentLoader } = createWidgetDefinition("beszelSystemTable", {
icon: IconTable,
supportsAdvancedFocus: false,
queryKeys: [[["widget", "beszel", "getSystems"]], [["widget", "beszel", "getSystemStats"]]],
queryMatcher: (query, scope) =>
query.path.at(-1) === "getSystems"
@@ -50,7 +50,6 @@ export const BeszelSystemStatsModal = createModal<BeszelSystemStatsModalProps>((
timePeriod={timePeriod}
visibility={allCharts}
columns={2}
tooltipLayer="modal"
onSwitchToHistorical={() => setTimePeriod("1h")}
/>
</Stack>
+3 -3
View File
@@ -111,7 +111,7 @@ export default function BookmarksWidget({
return (
<Stack h="100%" mih={0} gap="sm" p={height < 120 ? "xs" : "sm"}>
{options.title.length > 0 && (
<Title order={4} px="0.25rem" lineClamp={1}>
<Title order={4} px="0.25rem" lineClamp={displayMode === "advanced" ? undefined : 1}>
{options.title}
</Title>
)}
@@ -283,14 +283,14 @@ const AdvancedBookmarksLayout = ({
style={{ width: 40, height: 40, flex: "0 0 auto" }}
/>
<Stack gap={3} miw={0}>
<Text fw={700} size="sm" truncate="end">
<Text fw={700} size="sm">
{app.name}
</Text>
<Anchor component="span" size="xs" truncate="end">
{getBookmarkHostname(app.href)}
</Anchor>
{app.description && (
<Text size="xs" c="dimmed" lineClamp={3}>
<Text size="xs" c="dimmed">
{app.description}
</Text>
)}
+37 -8
View File
@@ -10,13 +10,13 @@ import dayjs from "dayjs";
import { clientApi } from "@homarr/api/client";
import { useRequiredBoard } from "@homarr/boards/context";
import type { CalendarEvent } from "@homarr/integrations/types";
import { useSettings } from "@homarr/settings";
import { useCurrentIntlLocale, useScopedI18n } from "@homarr/translation/client";
import { useCurrentIntlLocale, useI18n, useScopedI18n } from "@homarr/translation/client";
import actionTargetClasses from "../common/action-target.module.css";
import type { WidgetComponentProps } from "../definition";
import { getUsableWidgetQueryData } from "../common/query-state";
import { WidgetQueryErrorIndicator } from "../common/query-state-indicator";
import { useWidgetRuntimeQueries } from "../runtime-hooks";
import { IntegrationErrorIndicator } from "../common/integration-error-indicator";
import { CalendarDay } from "./calender-day";
@@ -27,6 +27,7 @@ import {
splitEvents,
toCalendarDateKey,
} from "./calendar-events";
import type { CalendarEventWithSource } from "./calendar-event-list";
import { CalendarEventList } from "./calendar-event-list";
import classes from "./component.module.css";
@@ -53,6 +54,7 @@ export default function CalendarWidget(props: WidgetComponentProps<"calendar">)
events={[]}
failedIntegrations={[]}
isPending={false}
queryError={undefined}
month={month}
setMonth={setMonth}
/>
@@ -79,7 +81,20 @@ const FetchCalendar = ({ month, setMonth, isEditMode, integrationIds, options, d
const data = getUsableWidgetQueryData(calendarQuery);
const { isPending } = calendarQuery;
const events = useMemo(() => data?.flatMap((item) => item.events) ?? [], [data]);
const events = useMemo(
() =>
data?.flatMap(({ events: integrationEvents, integration, error }) =>
error
? []
: integrationEvents.map(
(event): CalendarEventWithSource => ({
...event,
source: { integrationId: integration.id, integrationName: integration.name },
}),
),
) ?? [],
[data],
);
const failedIntegrations =
data?.flatMap(({ integration, error }) =>
error ? [{ integrationId: integration.id, integrationName: integration.name, error }] : [],
@@ -91,6 +106,7 @@ const FetchCalendar = ({ month, setMonth, isEditMode, integrationIds, options, d
events={events}
failedIntegrations={failedIntegrations}
isPending={isPending}
queryError={calendarQuery.error}
month={month}
setMonth={setMonth}
options={options}
@@ -101,9 +117,10 @@ const FetchCalendar = ({ month, setMonth, isEditMode, integrationIds, options, d
interface CalendarBaseProps {
isEditMode: boolean;
events: CalendarEvent[];
events: CalendarEventWithSource[];
failedIntegrations: { integrationId: string; integrationName: string; error: string }[];
isPending: boolean;
queryError: unknown;
month: Date;
setMonth: (date: Date) => void;
options: WidgetComponentProps<"calendar">["options"];
@@ -115,11 +132,13 @@ const CalendarBase = ({
events,
failedIntegrations,
isPending,
queryError,
month,
setMonth,
options,
displayMode,
}: CalendarBaseProps) => {
const t = useI18n();
const locale = useCurrentIntlLocale();
const { firstDayOfWeek } = useSettings();
const board = useRequiredBoard();
@@ -151,6 +170,8 @@ const CalendarBase = ({
events={agendaEvents}
failedIntegrations={failedIntegrations}
isPending={isPending}
queryError={queryError}
queryErrorLabel={t("widget.calendar.name")}
isEditMode={isEditMode}
locale={locale}
month={month}
@@ -161,9 +182,10 @@ const CalendarBase = ({
return (
<Stack ref={ref} h="100%" w="100%" gap="xs" style={{ overflow: "hidden" }}>
{failedIntegrations.length > 0 && (
{(failedIntegrations.length > 0 || Boolean(queryError)) && (
<Group px="xs" justify="flex-end">
<IntegrationErrorIndicator results={failedIntegrations} />
<WidgetQueryErrorIndicator error={queryError} label={t("widget.calendar.name")} />
</Group>
)}
<Calendar
@@ -243,9 +265,11 @@ const CalendarBase = ({
};
interface CalendarAgendaProps {
events: CalendarEvent[];
events: CalendarEventWithSource[];
failedIntegrations: CalendarBaseProps["failedIntegrations"];
isPending: boolean;
queryError: unknown;
queryErrorLabel: string;
isEditMode: boolean;
locale: string;
month: Date;
@@ -256,6 +280,8 @@ const CalendarAgenda = ({
events,
failedIntegrations,
isPending,
queryError,
queryErrorLabel,
isEditMode,
locale,
month,
@@ -301,7 +327,10 @@ const CalendarAgenda = ({
</ActionIcon>
</Tooltip>
</Group>
{failedIntegrations.length > 0 && <IntegrationErrorIndicator results={failedIntegrations} />}
<Group gap={0}>
<IntegrationErrorIndicator results={failedIntegrations} />
<WidgetQueryErrorIndicator error={queryError} label={queryErrorLabel} />
</Group>
</Group>
<Box style={{ flex: 1, minHeight: 0 }}>
@@ -310,7 +339,7 @@ const CalendarAgenda = ({
<Loader size="sm" />
</Center>
) : events.length > 0 ? (
<CalendarEventList events={events} groupByDate locale={locale} fillHeight />
<CalendarEventList events={events} advanced groupByDate locale={locale} fillHeight />
) : (
<Stack h="100%" align="center" justify="center" p="md">
<Text c="dimmed" size="sm" ta="center">
+2
View File
@@ -34,6 +34,7 @@ import {
IconPhoto,
IconReportSearch,
IconRocket,
IconRobot,
IconRoute,
IconRss,
IconServer2,
@@ -56,6 +57,7 @@ export const widgetCatalogIcons: Record<WidgetKind, TablerIcon> = {
clock: IconClock,
weather: IconCloud,
app: IconApps,
assistant: IconRobot,
iframe: IconBrowser,
video: IconDeviceCctv,
notebook: IconNotes,
-1
View File
@@ -6,7 +6,6 @@ import { optionsBuilder } from "../options";
export const { definition, componentLoader } = createWidgetDefinition("clock", {
icon: IconClock,
supportsAdvancedFocus: true,
queryKey: [["widget", "weather", "atLocation"]],
queryMatcher: ({ input }, scope) => {
const location = scope.options.weatherLocation;
+99 -30
View File
@@ -1,17 +1,26 @@
"use client";
import { ScrollArea, SimpleGrid, Stack, Text } from "@mantine/core";
import { Badge, Box, Group, ScrollArea, SimpleGrid, Stack, Text } from "@mantine/core";
import { clientApi } from "@homarr/api/client";
import { useScopedI18n } from "@homarr/translation/client";
import type { WidgetComponentProps } from "../definition";
import { getUsableWidgetQueryData } from "../common/query-state";
import { createWidgetKey } from "./coolify-utils";
import { WidgetQueryErrorIndicator } from "../common/query-state-indicator";
import { WidgetEmptyState } from "../common/empty-state";
import type { WidgetComponentProps } from "../definition";
import { createWidgetKey, getCoolifySectionVisibility } from "./coolify-utils";
import { InstanceCard } from "./instance-card";
import { SingleInstanceLayout } from "./single-instance-layout";
import type { InstanceData } from "./types";
export default function CoolifyWidget({ options, integrationIds, width, height }: WidgetComponentProps<"coolify">) {
export default function CoolifyWidget({
options,
integrationIds,
width,
height,
displayMode,
}: WidgetComponentProps<"coolify">) {
const t = useScopedI18n("widget.coolify");
if (integrationIds.length === 0) {
@@ -22,7 +31,18 @@ export default function CoolifyWidget({ options, integrationIds, width, height }
);
}
return <CoolifyContent integrationIds={integrationIds} options={options} width={width} height={height} />;
const isAdvanced = displayMode === "advanced";
const sectionVisibility = getCoolifySectionVisibility(options, displayMode);
return (
<CoolifyContent
integrationIds={integrationIds}
options={{ ...options, ...sectionVisibility }}
width={width}
height={height}
isAdvanced={isAdvanced}
/>
);
}
interface CoolifyContentProps {
@@ -30,19 +50,24 @@ interface CoolifyContentProps {
options: WidgetComponentProps<"coolify">["options"];
width: number;
height: number;
isAdvanced: boolean;
}
function CoolifyContent({ integrationIds, options, width, height }: CoolifyContentProps) {
function CoolifyContent({ integrationIds, options, width, height, isAdvanced }: CoolifyContentProps) {
const t = useScopedI18n("common");
const instancesQuery = clientApi.widget.coolify.getInstancesInfo.useQuery({
integrationIds,
});
const instancesData = getUsableWidgetQueryData(instancesQuery) ?? [];
const { isPending } = instancesQuery;
const successfulInstances = instancesData.filter(
(instance): instance is InstanceData => instance.instanceInfo !== null,
);
const failedInstances = instancesData.filter((instance) => instance.instanceInfo === null);
const isTiny = width < 256 || height < 144;
const hideFooter = height < 112;
const [firstInstance] = instancesData;
const [firstInstance] = successfulInstances;
const widgetKey = createWidgetKey(integrationIds);
if (isPending) {
@@ -54,33 +79,77 @@ function CoolifyContent({ integrationIds, options, width, height }: CoolifyConte
</Stack>
);
}
if (instancesData.length === 1 && firstInstance) {
if (successfulInstances.length === 0) {
return (
<SingleInstanceLayout
instance={firstInstance}
options={options}
isTiny={isTiny}
widgetKey={widgetKey}
hideFooter={hideFooter}
/>
<Stack h="100%" gap={0}>
<FailedSourceBadges sources={failedInstances} queryError={instancesQuery.error} />
<Box style={{ minHeight: 0, flex: 1 }}>
<WidgetEmptyState />
</Box>
</Stack>
);
}
if (successfulInstances.length === 1 && firstInstance) {
return (
<Stack h="100%" gap={0}>
<FailedSourceBadges sources={failedInstances} queryError={instancesQuery.error} />
<div style={{ minHeight: 0, flex: 1 }}>
<SingleInstanceLayout
instance={firstInstance}
options={options}
isTiny={!isAdvanced && isTiny}
isAdvanced={isAdvanced}
widgetKey={widgetKey}
hideFooter={!isAdvanced && hideFooter}
/>
</div>
</Stack>
);
}
return (
<ScrollArea h="100%">
<SimpleGrid cols={width >= 760 ? 2 : 1} spacing="sm" p="xs">
{instancesData.map((instance) => (
<InstanceCard
key={instance.integrationId}
instance={instance}
options={options}
isTiny={isTiny}
widgetKey={widgetKey}
hideFooter={hideFooter}
/>
))}
</SimpleGrid>
</ScrollArea>
<Stack h="100%" gap={0}>
<FailedSourceBadges sources={failedInstances} queryError={instancesQuery.error} />
<ScrollArea style={{ minHeight: 0, flex: 1 }}>
<SimpleGrid cols={width >= 760 ? 2 : 1} spacing="sm" p="xs">
{successfulInstances.map((instance) => (
<InstanceCard
key={instance.integrationId}
instance={instance}
options={options}
isTiny={!isAdvanced && isTiny}
isAdvanced={isAdvanced}
widgetKey={widgetKey}
hideFooter={!isAdvanced && hideFooter}
/>
))}
</SimpleGrid>
</ScrollArea>
</Stack>
);
}
const FailedSourceBadges = ({
sources,
queryError,
}: {
sources: { integrationId: string; integrationName: string }[];
queryError: unknown;
}) => {
const t = useScopedI18n("widget.coolify");
if (sources.length === 0 && !queryError) return null;
return (
<Group gap={4} p="xs" pb={0} wrap="wrap">
{sources.map((source) => (
<Badge key={source.integrationId} color="red" variant="light" size="xs">
{t("source.unavailable", { source: source.integrationName })}
</Badge>
))}
<Box ml="auto">
<WidgetQueryErrorIndicator error={queryError} label={t("name")} />
</Box>
</Group>
);
};
+38 -20
View File
@@ -1,6 +1,7 @@
"use client";
import { Accordion, Anchor, Badge, Card, Group, Image, Text, Tooltip } from "@mantine/core";
import { useState } from "react";
import { Accordion, Anchor, Badge, Card, Group, Image, Stack, Text, Tooltip } from "@mantine/core";
import { useLocalStorage } from "@mantine/hooks";
import { useTimeAgo } from "@homarr/common";
@@ -8,7 +9,7 @@ import { useScopedI18n } from "@homarr/translation/client";
import { ApplicationsSection } from "./applications-section";
import { getSafeApplicationUrl, SAFE_NEW_TAB_REL } from "../common/application-url";
import { buildServerResourceCounts, getBadgeColor, parseStatus } from "./coolify-utils";
import { buildServerResourceCounts, getBadgeColor, isCoolifyServerOnline, parseStatus } from "./coolify-utils";
import { ServersSection } from "./servers-section";
import { ServicesSection } from "./services-section";
import type { CoolifyOptions, InstanceData } from "./types";
@@ -18,11 +19,13 @@ interface InstanceCardProps {
instance: InstanceData;
options: CoolifyOptions;
isTiny: boolean;
isAdvanced: boolean;
widgetKey: string;
hideFooter: boolean;
}
export function InstanceCard({ instance, options, isTiny, widgetKey, hideFooter }: InstanceCardProps) {
export function InstanceCard({ instance, options, isTiny, isAdvanced, widgetKey, hideFooter }: InstanceCardProps) {
const t = useScopedI18n("widget.coolify");
const tCommon = useScopedI18n("common");
const cardKey = `${widgetKey}-${instance.integrationId}`;
const [showIp, setShowIp] = useLocalStorage({
@@ -33,6 +36,7 @@ export function InstanceCard({ instance, options, isTiny, widgetKey, hideFooter
key: `coolify-sections-${cardKey}`,
defaultValue: ["applications"],
});
const [advancedOpenSections, setAdvancedOpenSections] = useState(["servers", "applications", "services"]);
const serverResourceCounts = buildServerResourceCounts(
instance.instanceInfo.servers,
instance.instanceInfo.applications,
@@ -40,7 +44,8 @@ export function InstanceCard({ instance, options, isTiny, widgetKey, hideFooter
);
const baseUrl = getSafeApplicationUrl(instance.integrationUrl)?.replace(/\/+$/, "") ?? "";
const onlineServers = instance.instanceInfo.servers.filter((s) => s.is_reachable !== false).length;
const displayUrl = baseUrl ? baseUrl.replace(/^https?:\/\//, "") : "—";
const onlineServers = instance.instanceInfo.servers.filter(isCoolifyServerOnline).length;
const runningApps = instance.instanceInfo.applications.filter(
(a) => parseStatus(a.status ?? "") === "running",
).length;
@@ -73,20 +78,27 @@ export function InstanceCard({ instance, options, isTiny, widgetKey, hideFooter
wrap="nowrap"
style={{ borderBottom: "1px solid var(--mantine-color-dark-4)" }}
>
<Group gap={4} wrap="nowrap">
<Group gap={4} wrap="nowrap" miw={0}>
<Image src={COOLIFY_ICON_URL} alt="Coolify" w={16} h={16} />
<Anchor
component={baseUrl ? "a" : "span"}
href={baseUrl}
target={baseUrl ? "_blank" : undefined}
rel={baseUrl ? SAFE_NEW_TAB_REL : undefined}
fz={isTiny ? "10px" : "xs"}
fw={600}
c="inherit"
lineClamp={1}
>
{instance.integrationName}
</Anchor>
<Stack gap={0} miw={0}>
<Anchor
component={baseUrl ? "a" : "span"}
href={baseUrl}
target={baseUrl ? "_blank" : undefined}
rel={baseUrl ? SAFE_NEW_TAB_REL : undefined}
fz={isTiny ? "10px" : "xs"}
fw={600}
c="inherit"
lineClamp={1}
>
{instance.integrationName}
</Anchor>
{isAdvanced && (
<Text fz="10px" c="dimmed" truncate="end">
{t("source.url", { url: displayUrl })}
</Text>
)}
</Stack>
</Group>
<Group gap={4} wrap="nowrap">
{isTiny && totalResources > 0 ? (
@@ -127,8 +139,8 @@ export function InstanceCard({ instance, options, isTiny, widgetKey, hideFooter
chevronPosition="right"
multiple
keepMounted={false}
value={openSections}
onChange={setOpenSections}
value={isAdvanced ? advancedOpenSections : openSections}
onChange={isAdvanced ? setAdvancedOpenSections : setOpenSections}
>
{options.showServers && (
<ServersSection
@@ -136,6 +148,7 @@ export function InstanceCard({ instance, options, isTiny, widgetKey, hideFooter
serverResourceCounts={serverResourceCounts}
baseUrl={baseUrl}
isTiny={isTiny}
isAdvanced={isAdvanced}
showIp={showIp}
onToggleIp={() => setShowIp((prev) => !prev)}
/>
@@ -144,7 +157,12 @@ export function InstanceCard({ instance, options, isTiny, widgetKey, hideFooter
<ApplicationsSection applications={instance.instanceInfo.applications} baseUrl={baseUrl} isTiny={isTiny} />
)}
{options.showServices && (
<ServicesSection services={instance.instanceInfo.services} baseUrl={baseUrl} isTiny={isTiny} />
<ServicesSection
services={instance.instanceInfo.services}
baseUrl={baseUrl}
isTiny={isTiny}
isAdvanced={isAdvanced}
/>
)}
</Accordion>
@@ -1,20 +1,28 @@
"use client";
import { Accordion, ActionIcon, Anchor, Badge, Group, Stack, Text } from "@mantine/core";
import { IconCircleCheckFilled, IconCircleXFilled, IconEye, IconEyeOff, IconServer } from "@tabler/icons-react";
import {
IconCircleCheckFilled,
IconCircleFilled,
IconCircleXFilled,
IconEye,
IconEyeOff,
IconServer,
} from "@tabler/icons-react";
import type { CoolifyServer } from "@homarr/integrations/types";
import { useScopedI18n } from "@homarr/translation/client";
import actionTargetClasses from "../common/action-target.module.css";
import { getSafeApplicationUrl, SAFE_NEW_TAB_REL } from "../common/application-url";
import { getBadgeColor } from "./coolify-utils";
import { getBadgeColor, getCoolifyServerState, isCoolifyServerOnline } from "./coolify-utils";
interface ServersSectionProps {
servers: CoolifyServer[];
serverResourceCounts: Map<number, { apps: number; services: number }>;
baseUrl: string;
isTiny: boolean;
isAdvanced: boolean;
showIp: boolean;
onToggleIp: () => void;
}
@@ -24,12 +32,13 @@ export function ServersSection({
serverResourceCounts,
baseUrl,
isTiny,
isAdvanced,
showIp,
onToggleIp,
}: ServersSectionProps) {
const t = useScopedI18n("widget.coolify");
const tCommon = useScopedI18n("common");
const onlineServers = servers.filter((server) => server.is_reachable !== false).length;
const onlineServers = servers.filter(isCoolifyServerOnline).length;
return (
<Accordion.Item value="servers">
@@ -67,6 +76,7 @@ export function ServersSection({
}
baseUrl={baseUrl}
isTiny={isTiny}
isAdvanced={isAdvanced}
showIp={showIp}
/>
))}
@@ -86,23 +96,28 @@ interface ServerRowProps {
counts: { apps: number; services: number };
baseUrl: string;
isTiny: boolean;
isAdvanced: boolean;
showIp: boolean;
}
function ServerRow({ server, counts, baseUrl, isTiny, showIp }: ServerRowProps) {
function ServerRow({ server, counts, baseUrl, isTiny, isAdvanced, showIp }: ServerRowProps) {
const t = useScopedI18n("widget.coolify");
const isBuildServer = server.settings?.is_build_server === true;
const isOnline = server.is_reachable !== false;
const reachability = getCoolifyServerState(server, "is_reachable");
const usability = getCoolifyServerState(server, "is_usable");
const serverUrl = getSafeApplicationUrl(`${baseUrl}/server/${server.uuid}`);
const StatusIcon = isOnline ? IconCircleCheckFilled : IconCircleXFilled;
const status = reachability === true ? "online" : reachability === false ? "offline" : "unknown";
const StatusIcon =
reachability === true ? IconCircleCheckFilled : reachability === false ? IconCircleXFilled : IconCircleFilled;
const statusColor = reachability === true ? "green" : reachability === false ? "red" : "gray";
return (
<Stack gap={0}>
<Group wrap="nowrap" gap={isTiny ? 4 : "xs"}>
<StatusIcon
aria-label={t(isOnline ? "status.online" : "status.offline")}
aria-label={t(`status.${status}`)}
size={isTiny ? 12 : 16}
color={`var(--mantine-color-${isOnline ? "green" : "red"}-6)`}
color={`var(--mantine-color-${statusColor}-6)`}
/>
<Anchor
className={actionTargetClasses.root}
@@ -129,9 +144,30 @@ function ServerRow({ server, counts, baseUrl, isTiny, showIp }: ServerRowProps)
</Group>
<Group wrap="nowrap" gap={4} ml={16}>
<Text fz="10px" c="dimmed">
{showIp ? server.ip : "***.***.***.***"}
{showIp ? (server.ip ?? "—") : "***.***.***.***"}
</Text>
</Group>
{isAdvanced && (
<Group gap={4} ml={16} wrap="wrap">
<ServerStateBadge field="reachability" value={reachability} />
<ServerStateBadge field="usability" value={usability} />
</Group>
)}
</Stack>
);
}
const ServerStateBadge = ({ field, value }: { field: "reachability" | "usability"; value: boolean | undefined }) => {
const t = useScopedI18n("widget.coolify");
const status =
value === undefined
? t("status.unknown")
: field === "reachability"
? t(value ? "status.reachable" : "status.unreachable")
: t(value ? "status.usable" : "status.unusable");
return (
<Badge size="xs" variant="light" color={value === true ? "green" : value === false ? "red" : "gray"}>
{t(`server.${field}`)}: {status}
</Badge>
);
};
@@ -1,21 +1,24 @@
"use client";
import { Accordion, Badge, Group, Stack, Text } from "@mantine/core";
import { Accordion, Anchor, Badge, Group, Stack, Text } from "@mantine/core";
import { IconStack2 } from "@tabler/icons-react";
import type { CoolifyServiceWithContext } from "@homarr/integrations/types";
import { useScopedI18n } from "@homarr/translation/client";
import { getBadgeColor, parseStatus } from "./coolify-utils";
import actionTargetClasses from "../common/action-target.module.css";
import { getSafeApplicationUrl, SAFE_NEW_TAB_REL } from "../common/application-url";
import { cleanFqdn, getBadgeColor, getStatusColor, parseStatus } from "./coolify-utils";
import { ResourceRow } from "./resource-row";
interface ServicesSectionProps {
services: CoolifyServiceWithContext[];
baseUrl: string;
isTiny: boolean;
isAdvanced: boolean;
}
export function ServicesSection({ services, baseUrl, isTiny }: ServicesSectionProps) {
export function ServicesSection({ services, baseUrl, isTiny, isAdvanced }: ServicesSectionProps) {
const t = useScopedI18n("widget.coolify");
const tCommon = useScopedI18n("common");
const runningServices = services.filter((svc) => parseStatus(svc.status ?? "") === "running").length;
@@ -34,7 +37,19 @@ export function ServicesSection({ services, baseUrl, isTiny }: ServicesSectionPr
{services.length > 0 ? (
<Stack gap={4}>
{services.map((service) => (
<ResourceRow key={service.uuid} item={service} baseUrl={baseUrl} isTiny={isTiny} resourceType="service" />
<Stack key={service.uuid} gap={2}>
<ResourceRow item={service} baseUrl={baseUrl} isTiny={isTiny} resourceType="service" />
{isAdvanced && service.applications && service.applications.length > 0 && (
<Stack gap={2} ml="lg">
<Text fz="10px" c="dimmed">
{tCommon("applications")}
</Text>
{service.applications.map((application) => (
<ServiceApplicationRow key={application.uuid} application={application} />
))}
</Stack>
)}
</Stack>
))}
</Stack>
) : (
@@ -46,3 +61,45 @@ export function ServicesSection({ services, baseUrl, isTiny }: ServicesSectionPr
</Accordion.Item>
);
}
type ServiceApplication = NonNullable<CoolifyServiceWithContext["applications"]>[number];
const ServiceApplicationRow = ({ application }: { application: ServiceApplication }) => {
const t = useScopedI18n("widget.coolify");
const status = parseStatus(application.status ?? "");
const publicUrl = getSafeApplicationUrl(cleanFqdn(application.fqdn));
const statusLabel =
status === "running" ||
status === "stopped" ||
status === "exited" ||
status === "starting" ||
status === "restarting"
? t(`status.${status}`)
: t("status.unknown");
return (
<Group gap={4} wrap="nowrap">
<Badge size="xs" variant="dot" color={getStatusColor(status)}>
{statusLabel}
</Badge>
{publicUrl ? (
<Anchor
className={actionTargetClasses.root}
href={publicUrl}
target="_blank"
rel={SAFE_NEW_TAB_REL}
fz="xs"
c="inherit"
truncate="end"
style={{ textDecoration: "none" }}
>
{application.name}
</Anchor>
) : (
<Text fz="xs" truncate="end">
{application.name}
</Text>
)}
</Group>
);
};
@@ -1,5 +1,6 @@
"use client";
import { useState } from "react";
import { Accordion, Anchor, Group, Image, ScrollArea, Stack, Text } from "@mantine/core";
import { useLocalStorage } from "@mantine/hooks";
@@ -18,11 +19,20 @@ interface SingleInstanceLayoutProps {
instance: InstanceData;
options: CoolifyOptions;
isTiny: boolean;
isAdvanced: boolean;
widgetKey: string;
hideFooter: boolean;
}
export function SingleInstanceLayout({ instance, options, isTiny, widgetKey, hideFooter }: SingleInstanceLayoutProps) {
export function SingleInstanceLayout({
instance,
options,
isTiny,
isAdvanced,
widgetKey,
hideFooter,
}: SingleInstanceLayoutProps) {
const t = useScopedI18n("widget.coolify");
const [showIp, setShowIp] = useLocalStorage({
key: `coolify-show-ip-${widgetKey}`,
defaultValue: false,
@@ -31,6 +41,7 @@ export function SingleInstanceLayout({ instance, options, isTiny, widgetKey, hid
key: `coolify-sections-${widgetKey}`,
defaultValue: ["applications"],
});
const [advancedOpenSections, setAdvancedOpenSections] = useState(["servers", "applications", "services"]);
const serverResourceCounts = buildServerResourceCounts(
instance.instanceInfo.servers,
instance.instanceInfo.applications,
@@ -49,18 +60,25 @@ export function SingleInstanceLayout({ instance, options, isTiny, widgetKey, hid
oolify
</Text>
</Group>
<Anchor
component={baseUrl ? "a" : "span"}
href={baseUrl}
target={baseUrl ? "_blank" : undefined}
rel={baseUrl ? SAFE_NEW_TAB_REL : undefined}
fz={isTiny ? "xs" : "sm"}
fw={500}
c="dimmed"
lineClamp={1}
>
{displayUrl}
</Anchor>
<Stack gap={0} miw={0}>
{isAdvanced && (
<Text fz="xs" fw={600} truncate="end">
{instance.integrationName}
</Text>
)}
<Anchor
component={baseUrl ? "a" : "span"}
href={baseUrl}
target={baseUrl ? "_blank" : undefined}
rel={baseUrl ? SAFE_NEW_TAB_REL : undefined}
fz={isTiny ? "xs" : "sm"}
fw={500}
c="dimmed"
lineClamp={1}
>
{isAdvanced ? t("source.url", { url: displayUrl }) : displayUrl}
</Anchor>
</Stack>
</Group>
<Accordion
@@ -68,8 +86,8 @@ export function SingleInstanceLayout({ instance, options, isTiny, widgetKey, hid
chevronPosition="right"
multiple
keepMounted={false}
value={openSections}
onChange={setOpenSections}
value={isAdvanced ? advancedOpenSections : openSections}
onChange={isAdvanced ? setAdvancedOpenSections : setOpenSections}
>
{options.showServers && (
<ServersSection
@@ -77,6 +95,7 @@ export function SingleInstanceLayout({ instance, options, isTiny, widgetKey, hid
serverResourceCounts={serverResourceCounts}
baseUrl={baseUrl}
isTiny={isTiny}
isAdvanced={isAdvanced}
showIp={showIp}
onToggleIp={() => setShowIp((prev) => !prev)}
/>
@@ -85,7 +104,12 @@ export function SingleInstanceLayout({ instance, options, isTiny, widgetKey, hid
<ApplicationsSection applications={instance.instanceInfo.applications} baseUrl={baseUrl} isTiny={isTiny} />
)}
{options.showServices && (
<ServicesSection services={instance.instanceInfo.services} baseUrl={baseUrl} isTiny={isTiny} />
<ServicesSection
services={instance.instanceInfo.services}
baseUrl={baseUrl}
isTiny={isTiny}
isAdvanced={isAdvanced}
/>
)}
</Accordion>
@@ -6,6 +6,7 @@ import { useState } from "react";
import {
ActionIcon,
Badge,
Box,
Button,
Card,
Flex,
@@ -33,7 +34,9 @@ import { MaskedOrNormalImage } from "@homarr/ui";
import type { widgetKind } from ".";
import type { WidgetComponentProps } from "../../definition";
import { IntegrationErrorIndicator } from "../../common/integration-error-indicator";
import { getUsableWidgetQueryData } from "../../common/query-state";
import { WidgetQueryErrorIndicator } from "../../common/query-state-indicator";
import actionTargetClasses from "../../common/action-target.module.css";
import classes from "./component.module.css";
import TimerModal from "./TimerModal";
@@ -41,6 +44,15 @@ import TimerModal from "./TimerModal";
const dnsLightStatus = (enabled: boolean | undefined) =>
`var(--mantine-color-${typeof enabled === "undefined" ? "blue" : enabled ? "green" : "red"}-6`;
type DnsSummaryResult = RouterOutputs["widget"]["dnsHole"]["summary"][number];
type AvailableDnsSummaryResult = DnsSummaryResult & {
summary: NonNullable<DnsSummaryResult["summary"]>;
integration: DnsSummaryResult["integration"] & { updatedAt: Date };
};
const isAvailableDnsSummaryResult = (result: DnsSummaryResult): result is AvailableDnsSummaryResult =>
result.summary !== null && result.integration.updatedAt !== undefined;
export default function DnsHoleControlsWidget({
options,
integrationIds,
@@ -55,7 +67,8 @@ export default function DnsHoleControlsWidget({
.filter((id) => integrationIds.includes(id));
const summaryQuery = clientApi.widget.dnsHole.summary.useQuery({ integrationIds });
const summaries = getUsableWidgetQueryData(summaryQuery) ?? [];
const summaryResults = getUsableWidgetQueryData(summaryQuery) ?? [];
const summaries = summaryResults.filter(isAvailableDnsSummaryResult);
const { isPending: isSummaryPending } = summaryQuery;
const utils = clientApi.useUtils();
@@ -84,7 +97,7 @@ export default function DnsHoleControlsWidget({
if (!prevData) return [];
return prevData.map((item) =>
item.integration.id === integrationId
item.integration.id === integrationId && item.summary
? {
...item,
summary: {
@@ -147,7 +160,14 @@ export default function DnsHoleControlsWidget({
p="sm"
gap="sm"
style={{ pointerEvents: isEditMode ? "none" : undefined }}
pos="relative"
>
<Box pos="absolute" top={4} right={4} style={{ zIndex: 2 }}>
<Group gap={0}>
<IntegrationErrorIndicator results={summaryResults} />
<WidgetQueryErrorIndicator error={summaryQuery.error} label={t("widget.dnsHoleControls.name")} />
</Group>
</Box>
{controlAllButtonsVisible && (
<Flex className="dns-hole-controls-buttons" gap="sm">
<Tooltip label={t("widget.dnsHoleControls.controls.enableAll")}>
@@ -260,7 +280,7 @@ export default function DnsHoleControlsWidget({
interface ControlsCardProps {
integrationsWithInteractions: string[];
toggleDns: (integrationId: string) => Promise<void>;
data: RouterOutputs["widget"]["dnsHole"]["summary"][number];
data: AvailableDnsSummaryResult;
setSelectedIntegrationIds: (integrationId: string[]) => void;
open: () => void;
t: TranslationFunction;
+43 -35
View File
@@ -53,11 +53,18 @@ import { showErrorNotification } from "@homarr/notifications";
import { useCurrentIntlLocale, useScopedI18n } from "@homarr/translation/client";
import type { WidgetComponentProps } from "../definition";
import { IntegrationErrorIndicator } from "../common/integration-error-indicator";
import { getUsableWidgetQueryData } from "../common/query-state";
import { WidgetQueryErrorIndicator } from "../common/query-state-indicator";
import { HomarrDataTable } from "../common/homarr-data-table";
import { formatLocalizedDateTime } from "../common/locale";
import { usePersistedTableLayout, useTableLayoutPersistence } from "../common/use-persisted-table-layout";
import { filterDownloadItemsByStatus, getAvailableDownloadStates } from "./helpers";
import {
DOWNLOAD_COLUMN_ACCESSORS,
filterDownloadItemsByStatus,
getAvailableDownloadStates,
getDownloadColumnAccessors,
} from "./helpers";
dayjs.extend(relativeTime);
@@ -84,6 +91,7 @@ interface ColumnContext {
hasTorrents: boolean;
hasMultipleClients: boolean;
hasMultipleTypes: boolean;
isAdvanced: boolean;
size: SizeConfig;
}
@@ -143,8 +151,8 @@ const columnVisibilityChecks: Partial<Record<string, (ctx: ColumnContext) => boo
upSpeed: (ctx) => ctx.hasTorrents && ctx.size.showSpeedColumns,
ratio: (ctx) => ctx.hasTorrents,
sent: (ctx) => ctx.hasTorrents,
integration: (ctx) => ctx.hasMultipleClients,
type: (ctx) => ctx.hasMultipleTypes,
integration: (ctx) => ctx.isAdvanced || ctx.hasMultipleClients,
type: (ctx) => ctx.isAdvanced || ctx.hasMultipleTypes,
downSpeed: (ctx) => ctx.size.showSpeedColumns,
time: (ctx) => ctx.size.showTimeColumn,
state: (ctx) => ctx.size.showStateColumn,
@@ -171,24 +179,6 @@ function progressColor(state: DownloadState, progress: number): string {
return "blue";
}
const columnAccessors = [
"name",
"progress",
"size",
"downSpeed",
"upSpeed",
"time",
"state",
"added",
"ratio",
"received",
"sent",
"category",
"integration",
"index",
"type",
] as const;
function toCategoryArray(category: string | string[]): string[] {
if (Array.isArray(category)) return category;
return [category];
@@ -320,10 +310,17 @@ export default function DownloadClientsWidget({
integrationIds,
limitPerIntegration: options.limitPerIntegration,
});
const currentItems = getUsableWidgetQueryData(downloadsQuery) ?? [];
const currentItems = getUsableWidgetQueryData(downloadsQuery);
const availableItems = useMemo(() => currentItems?.filter((item) => item.data !== null) ?? [], [currentItems]);
const { isFetching } = downloadsQuery;
const t = useScopedI18n("widget.downloads");
const queryIndicators = (
<Group gap={0}>
<IntegrationErrorIndicator results={currentItems ?? []} />
<WidgetQueryErrorIndicator error={downloadsQuery.error} label={t("name")} />
</Group>
);
const [clientFilter, setClientFilter] = useState<string[]>([]);
const [statusFilter, setStatusFilter] = useState<string[]>([]);
@@ -370,7 +367,7 @@ export default function DownloadClientsWidget({
}, [options.defaultSort, defaultSortDirection]);
const eligibleData = useMemo<ExtendedDownloadClientItem[]>(() => {
return currentItems
return availableItems
.filter(({ integration }) => integrationIds.includes(integration.id))
.flatMap((pair) =>
pair.data.items
@@ -399,7 +396,7 @@ export default function DownloadClientsWidget({
}),
);
}, [
currentItems,
availableItems,
integrationIds,
integrationInteractSet,
mutateDeleteItem,
@@ -422,7 +419,7 @@ export default function DownloadClientsWidget({
}, [data, sortStatus]);
const clients = useMemo<ExtendedClientStatus[]>(() => {
return currentItems
return availableItems
.filter(({ integration }) => integrationIds.includes(integration.id))
.map(({ integration, data: clientData }): ExtendedClientStatus => {
const interact = integrationInteractSet.has(integration.id);
@@ -459,7 +456,7 @@ export default function DownloadClientsWidget({
};
});
}, [
currentItems,
availableItems,
integrationIds,
integrationInteractSet,
options.applyFilterToRatio,
@@ -472,10 +469,13 @@ export default function DownloadClientsWidget({
const hasMultipleTypes = new Set(data.map(({ type }) => type)).size > 1;
const size = useMemo(() => getSizeConfig(width, height, isAdvanced), [height, isAdvanced, width]);
const optionsColumnSet = useMemo(() => new Set<string>(options.columns), [options.columns]);
const optionsColumnSet = useMemo(
() => new Set<string>(getDownloadColumnAccessors(options.columns, isAdvanced)),
[isAdvanced, options.columns],
);
const columnContext = useMemo<ColumnContext>(
() => ({ optionsColumnSet, hasTorrents, hasMultipleClients, hasMultipleTypes, size }),
[optionsColumnSet, hasTorrents, hasMultipleClients, hasMultipleTypes, size],
() => ({ optionsColumnSet, hasTorrents, hasMultipleClients, hasMultipleTypes, isAdvanced, size }),
[optionsColumnSet, hasTorrents, hasMultipleClients, hasMultipleTypes, isAdvanced, size],
);
let progressColumnWidth = 120;
@@ -688,7 +688,7 @@ export default function DownloadClientsWidget({
const { effectiveColumns, storeKey } = usePersistedTableLayout({
columns,
columnAccessors,
columnAccessors: DOWNLOAD_COLUMN_ACCESSORS,
columnOrder: options.columnOrder,
columnWidths: options.columnWidths,
itemId,
@@ -733,11 +733,16 @@ export default function DownloadClientsWidget({
return { stateCounts, totalSize, completedSize, totalItems: data.length };
}, [data]);
if (options.columns.length === 0) {
if (!isAdvanced && options.columns.length === 0) {
return (
<Center h="100%">
<Text>{t("errors.noColumns")}</Text>
</Center>
<Box h="100%" pos="relative">
<Box pos="absolute" top={4} right={8} style={{ zIndex: 2 }}>
{queryIndicators}
</Box>
<Center h="100%">
<Text>{t("errors.noColumns")}</Text>
</Center>
</Box>
);
}
@@ -759,10 +764,13 @@ export default function DownloadClientsWidget({
)}
<Box style={{ flex: 1, minHeight: 0, position: "relative" }}>
<Box pos="absolute" top={4} right={8} style={{ zIndex: 2 }}>
{queryIndicators}
</Box>
<HomarrDataTable
isEditMode={isEditMode}
cellPadding={`${size.cellPadding}px 8px`}
fetching={isFetching && currentItems.length === 0}
fetching={isFetching && (currentItems?.length ?? 0) === 0}
fz={size.fontSize}
records={sortedData}
columns={effectiveColumns}
-12
View File
@@ -40,15 +40,3 @@ export function filterDownloadItemsByStatus<T extends { state: DownloadState }>(
export function getAvailableDownloadStates(items: readonly { state: DownloadState }[]): DownloadState[] {
return [...new Set(items.map(({ state }) => state))];
}
export function columnWidthsToRecord(columnsWidth: readonly Record<string, string | number>[]): Record<string, number> {
const result: Record<string, number> = {};
for (const entry of columnsWidth) {
const key = Object.keys(entry)[0];
if (!key) continue;
const width = entry[key];
if (typeof width === "number") result[key] = width;
else if (typeof width === "string" && width.endsWith("px")) result[key] = parseInt(width, 10);
}
return result;
}
+3 -21
View File
@@ -2,28 +2,10 @@ import { IconDownload } from "@tabler/icons-react";
import { z } from "zod/v4";
import { getIntegrationKindsByCategory } from "@homarr/definitions";
import type { ExtendedDownloadClientItem } from "@homarr/integrations";
import { createWidgetDefinition, widgetQueryInputMatches } from "../definition";
import { optionsBuilder } from "../options";
const columnsList = [
"name",
"progress",
"size",
"downSpeed",
"upSpeed",
"time",
"state",
"added",
"ratio",
"received",
"sent",
"category",
"integration",
"index",
"type",
] as const satisfies (keyof ExtendedDownloadClientItem)[];
import { DOWNLOAD_COLUMN_ACCESSORS } from "./helpers";
const sortColumns = [
"name",
@@ -38,7 +20,7 @@ const sortColumns = [
"sent",
"index",
"type",
] as const satisfies readonly (typeof columnsList)[number][];
] as const satisfies readonly (typeof DOWNLOAD_COLUMN_ACCESSORS)[number][];
export const { definition, componentLoader } = createWidgetDefinition("downloads", {
icon: IconDownload,
@@ -55,7 +37,7 @@ export const { definition, componentLoader } = createWidgetDefinition("downloads
(factory) => ({
columns: factory.multiSelect({
defaultValue: ["name", "progress", "downSpeed", "time", "state"],
options: columnsList.map((value) => ({
options: DOWNLOAD_COLUMN_ACCESSORS.map((value) => ({
value,
label: (t) => t(`widget.downloads.items.${value}.columnTitle`),
})),
@@ -46,7 +46,6 @@ describe("WidgetError", () => {
MantineProvider,
null,
createElement(WidgetError, {
kind: "app",
error: new Error(secret),
resetErrorBoundary: vi.fn(),
}),
@@ -35,11 +35,7 @@ const storageDeviceNamesMatch = (leftDeviceName: string, rightDeviceName: string
);
};
const matchesVisibleStorageVolume = (
visibleVolume: string,
integrationId: string,
deviceName: string,
): boolean => {
const matchesVisibleStorageVolume = (visibleVolume: string, integrationId: string, deviceName: string): boolean => {
const separatorIndex = visibleVolume.indexOf(":");
if (separatorIndex === -1) {
return storageDeviceNamesMatch(visibleVolume, deviceName);
+24 -9
View File
@@ -37,7 +37,7 @@ interface FirewallQueryState {
isPending: boolean;
isFetching: boolean;
isError: boolean;
data?: readonly { error?: string }[];
data?: readonly { error?: string; integration?: { id: string } }[];
}
export const hasTotalFirewallFailure = (queries: readonly FirewallQueryState[]) =>
@@ -48,6 +48,13 @@ export const hasTotalFirewallFailure = (queries: readonly FirewallQueryState[])
(query.data !== undefined && query.data.length > 0 && query.data.every(({ error }) => error)),
);
export const hasFirewallPartialFailure = (firewallId: string, queries: readonly FirewallQueryState[]) =>
queries.some(
(query) =>
query.isError ||
query.data?.some(({ error, integration }) => integration?.id === firewallId && Boolean(error)) === true,
);
export default function FirewallWidget({
integrationIds,
width,
@@ -101,6 +108,7 @@ export default function FirewallWidget({
const initialSelectedFirewall = firewallIds[0] ?? "";
const activeFirewall = firewallMetadata.has(selectedFirewall) ? selectedFirewall : initialSelectedFirewall;
const displayedFirewallIds = isAdvanced ? firewallIds : activeFirewall ? [activeFirewall] : [];
const firewallHasError = (firewallId: string) => hasFirewallPartialFailure(firewallId, queries);
const dropdownItems = firewallIds.map((firewallId) => ({
label: firewallMetadata.get(firewallId)?.name ?? firewallId,
value: firewallId,
@@ -128,11 +136,20 @@ export default function FirewallWidget({
dropdownItems={dropdownItems}
isTiny={isTiny}
/>
<FirewallVersion
firewallsVersionData={firewallsVersionData.filter(({ error }) => !error)}
selectedFirewall={activeFirewall}
isTiny={isTiny}
/>
<Group gap={4} wrap="nowrap">
{activeFirewall && firewallHasError(activeFirewall) && (
<Tooltip label={t("widget.firewall.error.internalServerError")}>
<Badge color="red" variant="light" size="xs">
{t("common.error")}
</Badge>
</Tooltip>
)}
<FirewallVersion
firewallsVersionData={firewallsVersionData.filter(({ error }) => !error)}
selectedFirewall={activeFirewall}
isTiny={isTiny}
/>
</Group>
</Group>
)}
@@ -142,9 +159,7 @@ export default function FirewallWidget({
const memory = firewallsMemoryData.find(({ integration }) => integration.id === firewallId);
const version = firewallsVersionData.find(({ integration }) => integration.id === firewallId);
const interfaces = firewallsInterfacesData.find(({ integration }) => integration.id === firewallId);
const hasError = Boolean(
cpu?.error || memory?.error || version?.error || interfacesQuery.isError || interfaces?.error,
);
const hasError = firewallHasError(firewallId);
const metadata = firewallMetadata.get(firewallId);
return (
@@ -24,6 +24,8 @@ import {
IconCpu2,
IconFileReport,
IconInfoCircle,
IconPackages,
IconRefreshAlert,
IconServer,
IconTemperature,
IconVersions,
@@ -41,7 +43,9 @@ import { useI18n } from "@homarr/translation/client";
import { filterStorageVolumes, normalizeStorageDeviceName } from "../filter-storage-volumes";
import { WidgetEmptyState } from "../common/empty-state";
import { getUsableWidgetQueryData } from "../common/query-state";
import { IntegrationErrorIndicator } from "../common/integration-error-indicator";
import { getUsableWidgetQueryData, isInitialWidgetQueryPending } from "../common/query-state";
import { WidgetQueryErrorIndicator, WidgetQueryLoadingState } from "../common/query-state-indicator";
import type { WidgetComponentProps } from "../definition";
import actionTargetClasses from "../common/action-target.module.css";
import { CpuRing } from "./rings/cpu-ring";
@@ -60,21 +64,46 @@ export const SystemHealthMonitoring = ({
withScrollArea = true,
}: WidgetComponentProps<"healthMonitoring"> & { withScrollArea?: boolean }) => {
const t = useI18n();
const healthData =
getUsableWidgetQueryData(clientApi.widget.healthMonitoring.getSystemHealthStatus.useQuery({ integrationIds })) ??
[];
const healthQuery = clientApi.widget.healthMonitoring.getSystemHealthStatus.useQuery({ integrationIds });
const healthResults = getUsableWidgetQueryData(healthQuery) ?? [];
const healthData = healthResults.filter(
(entry): entry is typeof entry & { healthInfo: NonNullable<typeof entry.healthInfo> } => entry.healthInfo !== null,
);
const [openedIntegrationId, setOpenedIntegrationId] = useState<string | null>(null);
const board = useRequiredBoard();
const isAdvanced = displayMode === "advanced";
const isTiny = !isAdvanced && width < 256;
const showCpu = isAdvanced || options.cpu;
const showMemory = isAdvanced || options.memory;
const showGpu = isAdvanced || options.gpu;
const showFileSystem = isAdvanced || options.fileSystem;
const queryIndicators = (
<Group gap={0}>
<IntegrationErrorIndicator results={healthResults} />
<WidgetQueryErrorIndicator error={healthQuery.error} label={t("widget.healthMonitoring.name")} />
</Group>
);
if (healthData.length === 0) return <WidgetEmptyState />;
if (isInitialWidgetQueryPending(healthQuery)) return <WidgetQueryLoadingState />;
if (healthData.length === 0) {
return (
<Box h="100%" pos="relative">
<Box pos="absolute" top={4} right={8} style={{ zIndex: 2 }}>
{queryIndicators}
</Box>
<WidgetEmptyState />
</Box>
);
}
const Container = withScrollArea ? ScrollArea : Box;
return (
<Container h={withScrollArea ? "100%" : undefined}>
<Container h={withScrollArea ? "100%" : undefined} pos="relative">
<Box pos="absolute" top={4} right={8} style={{ zIndex: 2 }}>
{queryIndicators}
</Box>
<Stack mih="100%" gap="sm" className="health-monitoring">
{healthData.map(({ integrationId, integrationName, healthInfo }) => {
const filteredFileSystem = filterStorageVolumes(
@@ -145,18 +174,18 @@ export const SystemHealthMonitoring = ({
</Modal>
</Box>
<Flex className="health-monitoring-information-card-elements" justify="center" align="center" wrap="wrap">
{options.cpu && <CpuRing cpuUtilization={healthInfo.cpuUtilization} isTiny={isTiny} />}
{options.cpu && (
{showCpu && <CpuRing cpuUtilization={healthInfo.cpuUtilization} isTiny={isTiny} />}
{showCpu && (
<CpuTempRing fahrenheit={options.fahrenheit} cpuTemp={healthInfo.cpuTemp} isTiny={isTiny} />
)}
{options.memory && (
{showMemory && (
<MemoryRing
available={healthInfo.memAvailableInBytes}
used={healthInfo.memUsedInBytes}
isTiny={isTiny}
/>
)}
{options.gpu &&
{showGpu &&
healthInfo.gpu.map((gpu) => (
<GpuRing key={gpu.gpuId} gpu={gpu} isTiny={isTiny} fahrenheit={options.fahrenheit} />
))}
@@ -166,7 +195,7 @@ export const SystemHealthMonitoring = ({
<SystemInformationList healthInfo={healthInfo} memoryUsage={memoryUsage} t={t} compact />
</Card>
)}
{options.fileSystem &&
{showFileSystem &&
disksData.map((disk) => {
return (
<Card
@@ -242,7 +271,9 @@ export const SystemHealthMonitoring = ({
);
};
type HealthInfo = RouterOutputs["widget"]["healthMonitoring"]["getSystemHealthStatus"][number]["healthInfo"];
type HealthInfo = NonNullable<
RouterOutputs["widget"]["healthMonitoring"]["getSystemHealthStatus"][number]["healthInfo"]
>;
const SystemInformationList = ({
healthInfo,
@@ -285,6 +316,14 @@ const SystemInformationList = ({
{healthInfo.loadAverage["5min"]}% / {healthInfo.loadAverage["15min"]}%
</List.Item>
)}
<List.Item className="health-monitoring-information-updates" icon={<IconPackages size={compact ? 18 : 30} />}>
{t("widget.healthMonitoring.popover.updatesAvailable", { count: healthInfo.availablePkgUpdates })}
</List.Item>
<List.Item className="health-monitoring-information-reboot" icon={<IconRefreshAlert size={compact ? 18 : 30} />}>
{healthInfo.rebootRequired
? t("widget.healthMonitoring.popover.rebootRequired")
: t("widget.healthMonitoring.popover.rebootNotRequired")}
</List.Item>
</List>
);
@@ -13,12 +13,19 @@ const mocks = vi.hoisted(() => ({
getAlbums: vi.fn(() => ({ data: [], isPending: false, isError: false })),
}));
vi.mock("@trpc/react-query", () => ({
getQueryKey: (procedure: { path: string[] }, input: unknown) => [procedure.path, { input, type: "query" }],
}));
vi.mock("@homarr/api/client", () => ({
clientApi: {
widget: {
immich: {
getAlbums: { useQuery: mocks.getAlbums },
getServerStats: { useQuery: () => ({ data: undefined }) },
getAlbums: { path: ["widget", "immich", "getAlbums"], useQuery: mocks.getAlbums },
getServerStats: {
path: ["widget", "immich", "getServerStats"],
useQuery: () => ({ data: undefined }),
},
},
},
},
@@ -13,7 +13,6 @@ const createOptions = () =>
}));
export const { definition, componentLoader } = createWidgetDefinition("indexerManager", {
supportsAdvancedFocus: false,
icon: IconReportSearch,
contextActions: ({ widgetRuntimeRef, context }) => [
{
+15 -13
View File
@@ -15,6 +15,7 @@ import {
} from "./manifest";
import { widgetQueryRefetchIntervals } from "./refetch-intervals";
import { widgetCatalogIcons } from "./catalog";
import { getWidgetQueryKeys } from "./definition";
describe("widget manifest promise stability", () => {
it("returns the same module promise for every render", () => {
@@ -111,11 +112,11 @@ describe("widget manifest promise stability", () => {
const definitions = await loadAllWidgetDefinitions();
const expectedQueryKeys = new Map([
["anchorNote", [["widget", "anchorNotes"]]],
["beszelAlerts", [["widget", "beszel"]]],
["clock", [["widget", "weather"]]],
["mediaMissing", [["widget", "mediaOrganizer"]]],
["mediaRequests-requestList", [["widget", "mediaRequests"]]],
["mediaRequests-requestStats", [["widget", "mediaRequests"]]],
["beszelAlerts", [["widget", "beszel", "getAlerts"]]],
["clock", [["widget", "weather", "atLocation"]]],
["mediaMissing", [["widget", "mediaOrganizer", "getData"]]],
["mediaRequests-requestList", [["widget", "mediaRequests", "getLatestRequests"]]],
["mediaRequests-requestStats", [["widget", "mediaRequests", "getStats"]]],
["smartHome-entityState", [["widget", "smartHome"]]],
] as const);
@@ -133,14 +134,15 @@ describe("widget manifest promise stability", () => {
const definition = definitions.get(kind);
if (definition?.refetchInterval === undefined) continue;
const entry = {
queryKey: definition.queryKey ?? [["widget", kind]],
intervalSeconds: definition.refetchInterval,
} as const;
const serializedQueryKey = JSON.stringify(entry.queryKey);
const existing = expectedByQueryKey.get(serializedQueryKey);
expect(existing?.intervalSeconds ?? entry.intervalSeconds).toBe(entry.intervalSeconds);
expectedByQueryKey.set(serializedQueryKey, entry);
for (const queryKey of getWidgetQueryKeys(definition, kind)) {
const path = queryKey[0];
if (!Array.isArray(path) || (path[0] !== "widget" && path[0] !== "docker")) continue;
const entry = { queryKey, intervalSeconds: definition.refetchInterval } as const;
const serializedQueryKey = JSON.stringify(entry.queryKey);
const existing = expectedByQueryKey.get(serializedQueryKey);
expect(existing?.intervalSeconds ?? entry.intervalSeconds).toBe(entry.intervalSeconds);
expectedByQueryKey.set(serializedQueryKey, entry);
}
}
const serializePolicy = (entry: PollingPolicy) => JSON.stringify(entry);
+2
View File
@@ -25,6 +25,7 @@ const moduleLoaders: Record<WidgetKind, () => Promise<WidgetModule>> = {
clock: () => import("./clock") as Promise<WidgetModule>,
weather: () => import("./weather") as Promise<WidgetModule>,
app: () => import("./app") as Promise<WidgetModule>,
assistant: () => import("./assistant") as Promise<WidgetModule>,
archiveTeamWarrior: () => import("./archive-team-warrior") as Promise<WidgetModule>,
anchorNote: () => import("./anchor-note") as Promise<WidgetModule>,
notebook: () => import("./notebook") as Promise<WidgetModule>,
@@ -85,6 +86,7 @@ const componentLoaders: Record<WidgetKind, () => Promise<WidgetComponentModule>>
clock: () => import("./clock/component") as Promise<WidgetComponentModule>,
weather: () => import("./weather/component") as Promise<WidgetComponentModule>,
app: () => import("./app/component") as Promise<WidgetComponentModule>,
assistant: () => import("./assistant/component") as Promise<WidgetComponentModule>,
archiveTeamWarrior: () => import("./archive-team-warrior/component") as Promise<WidgetComponentModule>,
anchorNote: () => import("./anchor-note/component") as Promise<WidgetComponentModule>,
notebook: () => import("./notebook/component") as Promise<WidgetComponentModule>,
@@ -28,6 +28,7 @@ import { useScopedI18n } from "@homarr/translation/client";
import { WidgetEmptyState } from "../common/empty-state";
import { getSafeApplicationUrl, SAFE_NEW_TAB_REL } from "../common/application-url";
import { getUsableWidgetQueryData } from "../common/query-state";
import { WidgetQueryErrorIndicator } from "../common/query-state-indicator";
import type { WidgetComponentProps } from "../definition";
import { useWidgetRuntimeQueries } from "../runtime-hooks";
import { NoIntegrationDataError } from "../errors/no-data-integration";
@@ -45,18 +46,19 @@ export default function MediaMissingWidget({
}: WidgetComponentProps<"mediaMissing">) {
const t = useScopedI18n("widget.mediaMissing");
const isAdvanced = displayMode === "advanced";
const showMissing = isAdvanced || options.showMissing;
const showQueued = isAdvanced || options.showQueued;
const pageSize = isAdvanced ? Math.max(Number(options.pageSize), 50) : Number(options.pageSize);
const input = { integrationIds, pageSize };
useWidgetRuntimeQueries(widgetRuntimeRef, [getQueryKey(clientApi.widget.mediaOrganizer.getData, input, "query")]);
const data = getUsableWidgetQueryData(
clientApi.widget.mediaOrganizer.getData.useQuery(input, {
staleTime: 60 * 1000,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
}),
);
const [selectedTab, setSelectedTab] = useState<MediaMissingTab>(options.showMissing ? "missing" : "queued");
const activeTab = resolveMediaMissingTab(selectedTab, options.showMissing, options.showQueued);
const mediaQuery = clientApi.widget.mediaOrganizer.getData.useQuery(input, {
staleTime: 60 * 1000,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
});
const data = getUsableWidgetQueryData(mediaQuery);
const [selectedTab, setSelectedTab] = useState<MediaMissingTab>(showMissing ? "missing" : "queued");
const activeTab = resolveMediaMissingTab(selectedTab, showMissing, showQueued);
useEffect(() => {
if (activeTab !== null && activeTab !== selectedTab) setSelectedTab(activeTab);
@@ -64,7 +66,7 @@ export default function MediaMissingWidget({
if (!data) return <WidgetEmptyState />;
if (data.length === 0) throw new NoIntegrationDataError();
if (!options.showMissing && !options.showQueued)
if (!showMissing && !showQueued)
return (
<Center h="100%" p="sm">
<Text c="dimmed" size="sm" ta="center">
@@ -79,7 +81,7 @@ export default function MediaMissingWidget({
const queuedCount = data.reduce((sum, entry) => sum + entry.queuedCount, 0);
const failedIntegrations = data.filter((entry): entry is typeof entry & { error: string } => Boolean(entry.error));
const enabledPanelCount = Number(options.showMissing) + Number(options.showQueued);
const enabledPanelCount = Number(showMissing) + Number(showQueued);
const panelWidth = isAdvanced && enabledPanelCount > 1 ? width / enabledPanelCount : width;
const isThin = !isAdvanced && panelWidth > 0 && panelWidth < 160;
const isShort = !isAdvanced && height > 0 && height < 180;
@@ -102,7 +104,12 @@ export default function MediaMissingWidget({
) : (
<SimpleGrid cols={columns} spacing="xs" verticalSpacing="xs">
{entries.map(({ item, integrationId }) => (
<MediaCard key={`${integrationId}-${item.type}-${item.id}`} item={item} density={density} />
<MediaCard
key={`${integrationId}-${item.type}-${item.id}`}
item={item}
density={density}
showQueueDetails={isAdvanced}
/>
))}
</SimpleGrid>
)}
@@ -121,13 +128,17 @@ export default function MediaMissingWidget({
))}
</Group>
);
const queryFailure = <WidgetQueryErrorIndicator error={mediaQuery.error} label={t("name")} />;
if (isAdvanced) {
return (
<Stack h="100%" gap={0}>
{partialFailures}
<Group justify="flex-end" px="xs">
{queryFailure}
{partialFailures}
</Group>
<SimpleGrid cols={enabledPanelCount} spacing="sm" p="sm" style={{ flex: 1, minHeight: 0 }}>
{options.showMissing && (
{showMissing && (
<Paper withBorder radius="sm" style={{ minHeight: 0, overflow: "hidden" }}>
<Group p="xs" gap="xs">
<IconQuestionMark size={16} />
@@ -138,7 +149,7 @@ export default function MediaMissingWidget({
<Box h="calc(100% - 40px)">{renderPanel(missing, t("empty.missing"))}</Box>
</Paper>
)}
{options.showQueued && (
{showQueued && (
<Paper withBorder radius="sm" style={{ minHeight: 0, overflow: "hidden" }}>
<Group p="xs" gap="xs">
<IconDownload size={16} />
@@ -164,26 +175,29 @@ export default function MediaMissingWidget({
h="100%"
style={{ display: "flex", flexDirection: "column" }}
>
{partialFailures}
<Group justify="flex-end" px="xs">
{queryFailure}
{partialFailures}
</Group>
<Tabs.List grow>
{options.showMissing && (
{showMissing && (
<Tabs.Tab value="missing" px={isThin ? 6 : undefined} leftSection={<IconQuestionMark size={14} />}>
{tabLabel(t("tab.missing"), missing.length, missingCount)}
</Tabs.Tab>
)}
{options.showQueued && (
{showQueued && (
<Tabs.Tab value="queued" px={isThin ? 6 : undefined} leftSection={<IconDownload size={14} />}>
{tabLabel(t("tab.queued"), queued.length, queuedCount)}
</Tabs.Tab>
)}
</Tabs.List>
{options.showMissing && (
{showMissing && (
<Tabs.Panel value="missing" flex={1} style={{ overflow: "hidden" }}>
{activeTab === "missing" && renderPanel(missing, t("empty.missing"))}
</Tabs.Panel>
)}
{options.showQueued && (
{showQueued && (
<Tabs.Panel value="queued" flex={1} style={{ overflow: "hidden" }}>
{activeTab === "queued" && renderPanel(queued, t("empty.queued"))}
</Tabs.Panel>
@@ -307,7 +321,15 @@ const CardShell = ({
);
};
const MediaCard = ({ item, density }: { item: MissingMediaItem | QueuedMediaItem; density: Density }) => {
const MediaCard = ({
item,
density,
showQueueDetails,
}: {
item: MissingMediaItem | QueuedMediaItem;
density: Density;
showQueueDetails: boolean;
}) => {
const isQueued = "percentComplete" in item;
return (
@@ -324,6 +346,11 @@ const MediaCard = ({ item, density }: { item: MissingMediaItem | QueuedMediaItem
{item.type === "episode" ? item.title : item.year}
</Text>
)}
{isQueued && showQueueDetails && (
<Text fz="10px" c="dimmed" lineClamp={1} lh={1.1}>
{[item.status, item.timeLeft].filter(Boolean).join(" · ")}
</Text>
)}
</Stack>
{isQueued && <ProgressRing percent={Math.min(100, Math.max(0, item.percentComplete))} density={density} />}
</Group>
@@ -31,6 +31,7 @@ import { OverflowBadge } from "@homarr/ui";
import { WidgetEmptyState } from "../common/empty-state";
import type { WidgetComponentProps } from "../definition";
import { getSafeApplicationUrl, SAFE_NEW_TAB_REL } from "../common/application-url";
import { IntegrationErrorIndicator } from "../common/integration-error-indicator";
import { getUsableWidgetQueryData, isInitialWidgetQueryPending } from "../common/query-state";
import { WidgetQueryErrorIndicator, WidgetQueryLoadingState } from "../common/query-state-indicator";
import classes from "./component.module.css";
@@ -44,36 +45,43 @@ export default function MediaReleasesWidget({
}: WidgetComponentProps<"mediaReleases">) {
const t = useI18n();
const releasesQuery = clientApi.widget.mediaRelease.getMediaReleases.useQuery({ integrationIds });
const releases = getUsableWidgetQueryData(releasesQuery);
const response = getUsableWidgetQueryData(releasesQuery);
if (isInitialWidgetQueryPending(releasesQuery)) return <WidgetQueryLoadingState />;
if (!releases || releases.length === 0) return <WidgetEmptyState />;
if (!response) return <WidgetEmptyState />;
const { releases, failedIntegrations } = response;
const isAdvanced = displayMode === "advanced";
return (
<Box h="100%" pos="relative">
<ScrollArea h="100%">
<SimpleGrid cols={isAdvanced ? Math.max(1, Math.floor(width / 360)) : 1} p="xs" spacing="sm">
{releases.map((item, index) => (
<Fragment key={`${item.integration.id}:${item.id}`}>
{!isAdvanced && index !== 0 && options.layout === "poster" && <Divider />}
<Item item={item} options={options} isAdvanced={isAdvanced} width={width} height={height} />
</Fragment>
))}
</SimpleGrid>
</ScrollArea>
{releasesQuery.error && (
<Box pos="absolute" top={4} right={4}>
{releases.length === 0 ? (
<WidgetEmptyState />
) : (
<ScrollArea h="100%">
<SimpleGrid cols={isAdvanced ? Math.max(1, Math.floor(width / 360)) : 1} p="xs" spacing="sm">
{releases.map((item, index) => (
<Fragment key={`${item.integration.id}:${item.id}`}>
{!isAdvanced && index !== 0 && options.layout === "poster" && <Divider />}
<Item item={item} options={options} isAdvanced={isAdvanced} width={width} height={height} />
</Fragment>
))}
</SimpleGrid>
</ScrollArea>
)}
{(failedIntegrations.length > 0 || releasesQuery.error) && (
<Group pos="absolute" top={4} right={4} gap={0}>
<IntegrationErrorIndicator results={failedIntegrations} />
<WidgetQueryErrorIndicator error={releasesQuery.error} label={t("widget.mediaReleases.name")} />
</Box>
</Group>
)}
</Box>
);
}
interface ItemProps {
item: RouterOutputs["widget"]["mediaRelease"]["getMediaReleases"][number];
item: RouterOutputs["widget"]["mediaRelease"]["getMediaReleases"]["releases"][number];
options: WidgetComponentProps<"mediaReleases">["options"];
isAdvanced: boolean;
width: number;
@@ -213,7 +221,7 @@ const Item = ({ item, options, isAdvanced, width, height }: ItemProps) => {
/>
)}
{isAdvanced && item.description && (
<Text size="xs" c="dimmed" lineClamp={3}>
<Text size="xs" c="dimmed">
{item.description}
</Text>
)}
@@ -232,9 +240,17 @@ const Item = ({ item, options, isAdvanced, width, height }: ItemProps) => {
</Badge>
)}
{(isAdvanced || options.showSource) && (
<Avatar size="sm" radius="xl" src={getIconUrl(item.integration.kind)} alt={item.integration.name} />
)}
{(isAdvanced || options.showSource) &&
(isAdvanced ? (
<Group gap={4} wrap="nowrap">
<Avatar size="sm" radius="xl" src={getIconUrl(item.integration.kind)} alt="" />
<Text size="xs" fw={500} lineClamp={1}>
{item.integration.name}
</Text>
</Group>
) : (
<Avatar size="sm" radius="xl" src={getIconUrl(item.integration.kind)} alt={item.integration.name} />
))}
</Stack>
)}
</Group>
+16 -12
View File
@@ -37,6 +37,7 @@ import { useTranslatedMantineReactTable } from "@homarr/ui/hooks";
import type { WidgetComponentProps } from "../definition";
import { getUsableWidgetQueryData } from "../common/query-state";
import { IntegrationErrorIndicator } from "../common/integration-error-indicator";
import { WidgetQueryErrorIndicator } from "../common/query-state-indicator";
import classes from "./component.module.css";
type TranscodingDecision = NonNullable<NonNullable<StreamSession["currentlyPlaying"]>["metadata"]>["transcoding"];
@@ -74,16 +75,17 @@ export default function MediaServerWidget({
isEditMode,
displayMode,
}: WidgetComponentProps<"mediaServer">) {
const currentStreams =
getUsableWidgetQueryData(
clientApi.widget.mediaServer.getCurrentStreams.useQuery({
integrationIds,
showOnlyPlaying: options.showOnlyPlaying,
}),
) ?? [];
const currentStreamsQuery = clientApi.widget.mediaServer.getCurrentStreams.useQuery({
integrationIds,
showOnlyPlaying: options.showOnlyPlaying,
});
const currentStreamsData = getUsableWidgetQueryData(currentStreamsQuery);
const currentStreams = useMemo(() => currentStreamsData ?? [], [currentStreamsData]);
const t = useScopedI18n("widget.mediaServer");
const isAdvanced = displayMode === "advanced";
const showLocation = isAdvanced || options.showLocation;
const showBitrate = isAdvanced || options.showBitrate;
const [selectedRowId, setSelectedRowId] = useState<string | null>(null);
const columns = useMemo<MRT_ColumnDef<StreamSession>[]>(() => {
const result: MRT_ColumnDef<StreamSession>[] = [
@@ -142,8 +144,8 @@ export default function MediaServerWidget({
if (!currentlyPlaying) return null;
const status = getPlaybackStatus(currentlyPlaying.metadata?.transcoding);
const location = options.showLocation ? currentlyPlaying.location : null;
const bitrateLabel = options.showBitrate ? formatBitrate(currentlyPlaying.metadata?.bitrateKbps) : null;
const location = showLocation ? currentlyPlaying.location : null;
const bitrateLabel = showBitrate ? formatBitrate(currentlyPlaying.metadata?.bitrateKbps) : null;
return (
<Stack gap={4} align="flex-start">
@@ -175,7 +177,7 @@ export default function MediaServerWidget({
: []),
];
return result;
}, [isAdvanced, options.showBitrate, options.showLocation, selectedRowId, t, width]);
}, [isAdvanced, selectedRowId, showBitrate, showLocation, t, width]);
// Only render the flat list of sessions when the currentStreams change
// Otherwise it will always create a new array reference and cause the table to re-render
@@ -285,7 +287,7 @@ export default function MediaServerWidget({
(sum, session) => sum + (session.currentlyPlaying?.metadata?.bitrateKbps ?? 0),
0,
);
const totalBitrateLabel = options.showBitrate ? formatBitrate(totalBitrateKbps) : null;
const totalBitrateLabel = showBitrate ? formatBitrate(totalBitrateKbps) : null;
const hasFailedIntegrations = currentStreams.some(({ error }) => Boolean(error));
return (
@@ -300,12 +302,14 @@ export default function MediaServerWidget({
{t("summary.transcoding", { count: transcodingCount })}
</Badge>
<Group ml="auto">
<WidgetQueryErrorIndicator error={currentStreamsQuery.error} label={t("name")} />
<IntegrationErrorIndicator results={currentStreams} />
</Group>
</Group>
)}
{!isAdvanced && hasFailedIntegrations && (
{!isAdvanced && (hasFailedIntegrations || currentStreamsQuery.error) && (
<Group px="xs" justify="flex-end">
<WidgetQueryErrorIndicator error={currentStreamsQuery.error} label={t("name")} />
<IntegrationErrorIndicator results={currentStreams} />
</Group>
)}
@@ -4,6 +4,7 @@ import { useEffect, useState } from "react";
import type { ReactNode } from "react";
import { getQueryKey } from "@trpc/react-query";
import {
Box,
Center,
Divider,
Group,
@@ -26,6 +27,7 @@ import { views } from ".";
import { WidgetEmptyState } from "../common/empty-state";
import type { WidgetComponentProps } from "../definition";
import { getUsableWidgetQueryData } from "../common/query-state";
import { WidgetQueryErrorIndicator } from "../common/query-state-indicator";
import { useWidgetRuntimeQueries } from "../runtime-hooks";
import { HealthCheckStatus } from "./health-check-status";
import { QueuePanel } from "./panels/queue.panel";
@@ -66,7 +68,8 @@ export default function MediaTranscodingWidget({
useWidgetRuntimeQueries(widgetRuntimeRef, [
getQueryKey(clientApi.widget.mediaTranscoding.getDataAsync, input, "query"),
]);
const transcodingData = getUsableWidgetQueryData(clientApi.widget.mediaTranscoding.getDataAsync.useQuery(input));
const transcodingQuery = clientApi.widget.mediaTranscoding.getDataAsync.useQuery(input);
const transcodingData = getUsableWidgetQueryData(transcodingQuery);
const [view, setView] = useState<View>(options.defaultView);
const t = useI18n("widget.mediaTranscoding");
@@ -94,10 +97,16 @@ export default function MediaTranscodingWidget({
const queuePageCount = totalQueuePages ?? 1;
const isTiny = !isAdvanced && (width < 280 || height < 140);
const footerLayout = getTranscodingFooterLayout(width, height);
const queryIndicator = (
<Box pos="absolute" top={4} right={8} style={{ zIndex: 2 }}>
<WidgetQueryErrorIndicator error={transcodingQuery.error} label={t("name")} />
</Box>
);
if (isAdvanced) {
return (
<Stack gap="xs" h="100%" p="xs">
<Stack gap="xs" h="100%" p="xs" pos="relative">
{queryIndicator}
<ScrollArea h="100%" style={{ flex: 1 }}>
<SimpleGrid cols={width >= 1100 ? 3 : width >= 700 ? 2 : 1} spacing="sm">
<AdvancedPanel title={t("tab.workers")} icon={IconCpu2}>
@@ -127,7 +136,8 @@ export default function MediaTranscodingWidget({
}
return (
<Stack gap={4} h="100%">
<Stack gap={4} h="100%" pos="relative">
{queryIndicator}
{view === "workers" ? (
<WorkersPanel workers={transcodingData.data.workers} isTiny={isTiny} />
) : view === "queue" ? (
+14 -5
View File
@@ -70,6 +70,7 @@ import type { TablerIcon } from "@homarr/ui";
import type { WidgetComponentProps } from "../definition";
import actionTargetClasses from "../common/action-target.module.css";
import { createReadOnlyTaskItemTransaction, ReadOnlyTaskItem } from "./read-only-task-item";
import { getNotebookDisplay } from "./display";
import { NotebookTextDirection, setTextDirection } from "./text-direction";
import "@mantine/tiptap/styles.css";
@@ -98,6 +99,7 @@ export function Notebook({
boardId,
itemId,
height,
displayMode = "compact",
}: WidgetComponentProps<"notebook">) {
const [content, setContent] = useState(options.content);
const previousContentRef = useRef(options.content);
@@ -339,6 +341,13 @@ export function Notebook({
characters: documentText.length,
words: documentText.length === 0 ? 0 : documentText.split(/\s+/).length,
};
const display = getNotebookDisplay({
height,
isAdvanced: displayMode === "advanced",
isEditing,
isSaving,
showToolbar: options.showToolbar,
});
return (
<Box className="homarr-notebook" h="100%" onDoubleClick={handleDoubleClick}>
@@ -375,9 +384,9 @@ export function Notebook({
>
<RichTextEditor.Toolbar
style={{
display: isEditing && !isSaving && options.showToolbar === true ? "flex" : "none",
maxHeight: height < 180 ? "4.5rem" : "10rem",
overflowY: "auto",
display: display.showToolbar ? "flex" : "none",
maxHeight: display.toolbarMaxHeight,
overflowY: display.toolbarMaxHeight === undefined ? undefined : "auto",
}}
>
<RichTextEditor.ControlsGroup>
@@ -505,7 +514,7 @@ export function Notebook({
<RichTextEditor.Content />
</ScrollArea>
</RichTextEditor>
{(saveError || height >= 180) && (
{(saveError || display.showDocumentStats) && (
<Group pos="absolute" bottom={4} right={8} gap="xs" style={{ pointerEvents: saveError ? undefined : "none" }}>
{saveError && (
<Tooltip label={saveError} multiline>
@@ -521,7 +530,7 @@ export function Notebook({
</Text>
</Tooltip>
)}
{height >= 180 && (
{display.showDocumentStats && (
<Text size="xs" c="dimmed">
{t("widget.notebook.documentStats", documentStats)}
</Text>
@@ -9,21 +9,25 @@ import { useRequiredBoard } from "@homarr/boards/context";
import { useTimeAgo } from "@homarr/common";
import { useI18n } from "@homarr/translation/client";
import type { WidgetComponentProps } from "../definition";
import { getSafeApplicationUrl, SAFE_NEW_TAB_REL } from "../common/application-url";
import { getUsableWidgetQueryData } from "../common/query-state";
import { WidgetQueryErrorIndicator } from "../common/query-state-indicator";
import type { WidgetComponentProps } from "../definition";
import { getNotificationDisplay } from "./display";
export default function NotificationsWidget({
options,
integrationIds,
width,
height,
displayMode,
}: WidgetComponentProps<"notifications">) {
const notificationsQuery = clientApi.widget.notifications.getNotifications.useQuery({
...options,
integrationIds,
});
const notificationIntegrations = getUsableWidgetQueryData(notificationsQuery) ?? [];
const notificationData = getUsableWidgetQueryData(notificationsQuery);
const notificationIntegrations = useMemo(() => notificationData ?? [], [notificationData]);
const { isPending } = notificationsQuery;
const t = useI18n();
@@ -49,12 +53,23 @@ export default function NotificationsWidget({
const isDense = width < 280 || height < 180;
const isRoomy = width >= 360 && height >= 220;
const bodyLineClamp = height < 112 ? 1 : isDense ? 2 : height >= 300 ? 8 : 4;
const notificationDisplay = getNotificationDisplay({
displayMode,
hideLogos: options.hideLogos,
isRoomy,
bodyLineClamp,
});
const columns = width >= 720 ? 2 : 1;
const spacing = isRoomy ? "sm" : "xs";
return (
<ScrollArea className="scroll-area-w100" w="100%" h="100%" p="xs">
<Stack w="100%" gap="xs">
{notificationsQuery.error && (
<Group justify="flex-end">
<WidgetQueryErrorIndicator error={notificationsQuery.error} label={t("widget.notifications.name")} />
</Group>
)}
{failedIntegrations.length > 0 && (
<Group gap={4} wrap="wrap">
{failedIntegrations.map((integration) => (
@@ -95,7 +110,7 @@ export default function NotificationsWidget({
}}
>
<Flex gap={isDense ? "xs" : "sm"} align="flex-start" w="100%">
{!options.hideLogos && notification.source?.iconUrl && (
{notificationDisplay.showLogos && notification.source?.iconUrl && (
<Avatar
src={notification.source.iconUrl}
alt={notification.source.name}
@@ -113,7 +128,7 @@ export default function NotificationsWidget({
<Text
c="dimmed"
size={isDense ? "xs" : "sm"}
lineClamp={bodyLineClamp}
lineClamp={notificationDisplay.bodyLineClamp}
style={{ whiteSpace: "pre-line" }}
>
{notification.body}
@@ -121,7 +136,11 @@ export default function NotificationsWidget({
<InfoDisplay
date={notification.time}
source={isRoomy ? (notification.source?.name ?? notification.integrationName) : undefined}
source={
notificationDisplay.showSource
? (notification.source?.name ?? notification.integrationName)
: undefined
}
dense={isDense}
/>
</Flex>
+1 -1
View File
@@ -6,7 +6,7 @@ import { createWidgetDefinition, widgetQueryInputMatches } from "../definition";
import { optionsBuilder } from "../options";
export const { componentLoader, definition } = createWidgetDefinition("notifications", {
supportsAdvancedFocus: false,
supportsAdvancedFocus: true,
icon: IconMessage,
queryKey: [["widget", "notifications", "getNotifications"]],
queryMatcher: ({ input }, scope) =>
+36 -12
View File
@@ -190,18 +190,42 @@ export const { definition, componentLoader } = createWidgetDefinition("patchmon"
useCustomThresholds: {
shouldHide: (options) => !options.enableThresholdColors,
},
hostsNeedingUpdatesThresholdMode: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds },
hostsNeedingUpdatesWarningAt: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds },
hostsNeedingUpdatesCriticalAt: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds },
securityUpdatesThresholdMode: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds },
securityUpdatesWarningAt: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds },
securityUpdatesCriticalAt: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds },
hostsWithSecurityUpdatesThresholdMode: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds },
hostsWithSecurityUpdatesWarningAt: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds },
hostsWithSecurityUpdatesCriticalAt: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds },
upToDateHostsThresholdMode: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds },
upToDateHostsWarningAt: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds },
upToDateHostsCriticalAt: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds },
hostsNeedingUpdatesThresholdMode: {
shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds,
},
hostsNeedingUpdatesWarningAt: {
shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds,
},
hostsNeedingUpdatesCriticalAt: {
shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds,
},
securityUpdatesThresholdMode: {
shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds,
},
securityUpdatesWarningAt: {
shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds,
},
securityUpdatesCriticalAt: {
shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds,
},
hostsWithSecurityUpdatesThresholdMode: {
shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds,
},
hostsWithSecurityUpdatesWarningAt: {
shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds,
},
hostsWithSecurityUpdatesCriticalAt: {
shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds,
},
upToDateHostsThresholdMode: {
shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds,
},
upToDateHostsWarningAt: {
shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds,
},
upToDateHostsCriticalAt: {
shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds,
},
totalOutdatedPackagesThresholdMode: {
shouldHide: (options) =>
!options.enableThresholdColors || !options.useCustomThresholds || !options.showTotalOutdatedPackages,
+1 -1
View File
@@ -13,7 +13,7 @@ const relativeDateSchema = z
.or(z.literal(""));
export const { definition, componentLoader } = createWidgetDefinition("releases", {
supportsAdvancedFocus: false,
supportsAdvancedFocus: true,
icon: IconRocket,
queryKey: [["widget", "releases", "getLatest"]],
queryMatcher: ({ input }, scope) => widgetQueryInputMatches(input, { itemId: scope.itemId }),
+77 -10
View File
@@ -9,8 +9,10 @@ import { clientApi } from "@homarr/api/client";
import { useRequiredBoard } from "@homarr/boards/context";
import { useScopedI18n } from "@homarr/translation/client";
import type { WidgetComponentProps } from "../definition";
import { getSafeApplicationUrl, SAFE_NEW_TAB_REL } from "../common/application-url";
import { WidgetEmptyState } from "../common/empty-state";
import { WidgetQueryLoadingState } from "../common/query-state-indicator";
import type { WidgetComponentProps } from "../definition";
import { BaseWidgetError } from "../errors/base-component";
import classes from "./component.module.scss";
@@ -27,6 +29,7 @@ const useLiveFeed = (input: RouterInputs["widget"]["rssFeed"]["getFeeds"]) => {
hasError: false as const,
entries: normalizedData,
failedFeedCount: 0,
isPending: query.isPending,
isStale: Boolean(query.error),
};
}
@@ -35,11 +38,12 @@ const useLiveFeed = (input: RouterInputs["widget"]["rssFeed"]["getFeeds"]) => {
hasError: false as const,
entries: normalizedData?.entries ?? [],
failedFeedCount: normalizedData?.failedFeedCount ?? 0,
isPending: query.isPending,
isStale: Boolean(query.error),
};
};
export default function RssFeed({ options, width, height }: WidgetComponentProps<"rssFeed">) {
export default function RssFeed({ options, width, height, displayMode }: WidgetComponentProps<"rssFeed">) {
const feed = useLiveFeed({
urls: options.feedUrls,
maximumAmountPosts: typeof options.maximumAmountPosts === "number" ? options.maximumAmountPosts : 100,
@@ -57,6 +61,7 @@ export default function RssFeed({ options, width, height }: WidgetComponentProps
/>
);
}
if (feed.isPending) return <WidgetQueryLoadingState />;
const warning = feed.isStale
? t("warning.stale")
@@ -64,13 +69,35 @@ export default function RssFeed({ options, width, height }: WidgetComponentProps
? t("warning.partial", { count: feed.failedFeedCount })
: undefined;
if (feed.entries.length === 0) {
return (
<Flex direction="column" h="100%" p="xs">
{warning && (
<Alert role="presentation" color="orange" icon={<IconAlertTriangle aria-hidden size={16} />} p="xs">
<output>{warning}</output>
</Alert>
)}
<WidgetEmptyState />
</Flex>
);
}
const languageDir = options.enableRtl ? "RTL" : "LTR";
const isDense = width < 420 || height < 180;
const isTiny = width < 260 || height < 110;
const isRoomy = width >= 420 && height >= 240;
const isAdvanced = displayMode === "advanced";
const columns = width >= 720 && height >= 260 ? 2 : 1;
const descriptionLines = isRoomy ? Math.max(options.textLinesClamp, 6) : isDense ? 1 : options.textLinesClamp;
const entryDisplay = getRssEntryDisplay({
isAdvanced,
isDense,
isTiny,
hideDescription: options.hideDescription,
showPosterImage: options.showPosterImage,
descriptionLines,
});
const spacing = isRoomy ? "sm" : "xs";
return (
@@ -97,7 +124,7 @@ export default function RssFeed({ options, width, height }: WidgetComponentProps
title={feedEntry.title}
>
<Group wrap="nowrap" align="flex-start" gap={isDense ? "xs" : "md"}>
{feedEntry.enclosure !== undefined && options.showPosterImage && !isTiny && (
{feedEntry.enclosure !== undefined && entryDisplay.showImage && (
<Image
loading="lazy"
className={classes.poster}
@@ -111,18 +138,29 @@ export default function RssFeed({ options, width, height }: WidgetComponentProps
)}
<Flex gap={isRoomy ? "sm" : 6} direction="column" w="100%" miw={0}>
<Text dir={languageDir} fz={isRoomy ? "md" : "sm"} fw={600} lh={1.25} lineClamp={2}>
<Text
dir={languageDir}
fz={isRoomy ? "md" : "sm"}
fw={600}
lh={1.25}
lineClamp={isAdvanced ? undefined : 2}
>
{feedEntry.title}
</Text>
{!options.hideDescription && feedEntry.description && !isTiny && (
<Text dir={languageDir} c="dimmed" size="sm" lineClamp={descriptionLines}>
{entryDisplay.showDescription && feedEntry.description && (
<Text dir={languageDir} c="dimmed" size="sm" lineClamp={entryDisplay.descriptionLineClamp}>
{feedDescriptionToText(feedEntry.description)}
</Text>
)}
<InfoDisplay
source={!isDense ? getHostname(feedEntry.feedUrl) : undefined}
source={entryDisplay.showSource ? getHostname(feedEntry.feedUrl) : undefined}
date={feedEntry.published ? dayjs(feedEntry.published).fromNow() : undefined}
timestamp={
isAdvanced && feedEntry.published
? dayjs(feedEntry.published).format("YYYY-MM-DD HH:mm:ss Z")
: undefined
}
/>
</Flex>
</Group>
@@ -152,15 +190,44 @@ export const getHostname = (url: string): string => {
}
};
const InfoDisplay = ({ date, source }: { date?: string; source?: string }) => (
<Group gap={5} align="center" wrap="nowrap">
interface RssEntryDisplayInput {
isAdvanced: boolean;
isDense: boolean;
isTiny: boolean;
hideDescription: boolean;
showPosterImage: boolean;
descriptionLines: number;
}
export const getRssEntryDisplay = ({
isAdvanced,
isDense,
isTiny,
hideDescription,
showPosterImage,
descriptionLines,
}: RssEntryDisplayInput) => ({
showDescription: isAdvanced || (!hideDescription && !isTiny),
showImage: isAdvanced || (showPosterImage && !isTiny),
showSource: isAdvanced || !isDense,
descriptionLineClamp: isAdvanced ? undefined : descriptionLines,
});
const InfoDisplay = ({ date, timestamp, source }: { date?: string; timestamp?: string; source?: string }) => (
<Group gap={5} align="center" wrap={timestamp ? "wrap" : "nowrap"}>
{date && <IconClock size="1rem" color="var(--mantine-color-dimmed)" />}
{date && (
<Text size="xs" c="dimmed">
{date}
</Text>
)}
{date && source && <Text c="dimmed">•</Text>}
{timestamp && <Text c="dimmed">•</Text>}
{timestamp && (
<Text size="xs" c="dimmed" ff="monospace">
{timestamp}
</Text>
)}
{(date || timestamp) && source && <Text c="dimmed">•</Text>}
{source && (
<Text size="xs" c="dimmed" truncate="end">
{source}
+1 -1
View File
@@ -11,7 +11,7 @@ import { optionsBuilder } from "../options";
* - https://www.jsonfeed.org/version/1.1/
*/
export const { definition, componentLoader } = createWidgetDefinition("rssFeed", {
supportsAdvancedFocus: false,
supportsAdvancedFocus: true,
icon: IconRss,
queryKey: [["widget", "rssFeed", "getFeeds"]],
queryMatcher: ({ input }, scope) =>
+1 -1
View File
@@ -12,7 +12,7 @@ const timeRangeOptions = stockPriceTimeFrames.range;
const timeIntervalOptions = stockPriceTimeFrames.interval;
export const { definition, componentLoader } = createWidgetDefinition("stockPrice", {
supportsAdvancedFocus: false,
supportsAdvancedFocus: true,
icon: IconBuildingBank,
queryKey: [["widget", "stockPrice", "getPriceHistory"]],
queryMatcher: ({ input }, scope) =>
+103 -43
View File
@@ -9,16 +9,21 @@ import { formatBytesPair } from "@homarr/common";
import { useI18n } from "@homarr/translation/client";
import { WidgetEmptyState } from "../common/empty-state";
import { getUsableWidgetQueryData } from "../common/query-state";
import { IntegrationErrorIndicator } from "../common/integration-error-indicator";
import { getUsableWidgetQueryData, isInitialWidgetQueryPending } from "../common/query-state";
import { WidgetQueryErrorIndicator, WidgetQueryLoadingState } from "../common/query-state-indicator";
import type { WidgetComponentProps } from "../definition";
import { filterStorageVolumes, normalizeStorageDeviceName } from "../filter-storage-volumes";
import { NoIntegrationDataError } from "../errors/no-data-integration";
type DisplayMode = WidgetComponentProps<"systemDisks">["options"]["displayMode"];
type DiskDisplayMode = WidgetComponentProps<"systemDisks">["options"]["displayMode"];
export const clampPercentage = (percentage: number): number => Math.min(100, Math.max(0, percentage));
export const getDisplayText = (
item: { used: string; available: string; percentage: number },
displayMode: DisplayMode,
displayMode: DiskDisplayMode,
translatedFreeText?: string,
) => {
switch (displayMode) {
case "percentage":
@@ -27,27 +32,26 @@ export const getDisplayText = (
const usedInBytes = Number(item.used);
const availableInBytes = Number(item.available);
if (Number.isFinite(usedInBytes) && Number.isFinite(availableInBytes)) {
const { used, available } = formatBytesPair(usedInBytes, availableInBytes);
return `${used} / ${available}`;
const { used, available: total } = formatBytesPair(usedInBytes, usedInBytes + availableInBytes);
return `${used} / ${total}`;
}
return `${item.used} / ${item.available}`;
}
case "free":
return `${Math.round(100 - item.percentage)}% free`;
return translatedFreeText ?? `${Math.round(100 - clampPercentage(item.percentage))}% free`;
default:
return `${Math.round(item.percentage)}%`;
}
};
export const clampPercentage = (percentage: number): number => Math.min(100, Math.max(0, percentage));
const getAbsoluteText = (item: { used: string; available: string }) => {
const usedInBytes = Number(item.used);
const availableInBytes = Number(item.available);
if (!Number.isFinite(usedInBytes) || !Number.isFinite(availableInBytes)) return `${item.used} / ${item.available}`;
const { used, available } = formatBytesPair(usedInBytes, availableInBytes);
return `${used} / ${available}`;
};
export const getAdvancedDisplayTexts = (
item: { used: string; available: string; percentage: number },
translatedFreeText?: string,
) => ({
percentage: getDisplayText(item, "percentage"),
absolute: getDisplayText(item, "absolute"),
free: getDisplayText(item, "free", translatedFreeText),
});
interface SystemDiskCardProps {
deviceName: string;
@@ -58,6 +62,9 @@ interface SystemDiskCardProps {
showBackgroundBar: boolean;
integrationName?: string;
secondaryText?: string;
freeText?: string;
smartStatus?: string;
isAdvanced: boolean;
showSecondaryText: boolean;
showTemperature: boolean;
}
@@ -71,6 +78,9 @@ const SystemDiskCard = ({
showBackgroundBar,
integrationName,
secondaryText,
freeText,
smartStatus,
isAdvanced,
showSecondaryText,
showTemperature,
}: SystemDiskCardProps) => {
@@ -99,7 +109,9 @@ const SystemDiskCard = ({
}, []);
const unhealthyLabel = t("widget.systemDisks.status.unhealthy");
const hasHiddenTemperature = temperature !== null && temperature !== undefined && !showTemperature;
const hasTemperature = temperature !== null && temperature !== undefined;
const temperatureText = hasTemperature ? `${temperature}°C` : "—°C";
const hasHiddenTemperature = hasTemperature && !showTemperature;
const hasHiddenSecondaryText = Boolean(secondaryText && secondaryText !== displayText && !showSecondaryText);
const tooltipLabel = [
healthy ? displayText : `${displayText} (${unhealthyLabel})`,
@@ -141,11 +153,19 @@ const SystemDiskCard = ({
{secondaryText}
</Text>
)}
{isAdvanced && freeText && freeText !== displayText && (
<Text size="xs" c="dimmed">
{freeText}
</Text>
)}
{isAdvanced && (
<Text size="xs" c={healthy ? "dimmed" : "red"}>
{t("widget.systemDisks.status.smart")}: {smartStatus?.trim() || "—"}
</Text>
)}
</div>
<div style={{ flexShrink: 0 }}>
{showTemperature && temperature !== null && temperature !== undefined ? (
<Text size="sm">{temperature}°C</Text>
) : null}
{showTemperature && (hasTemperature || isAdvanced) ? <Text size="sm">{temperatureText}</Text> : null}
</div>
</Group>
<Box
@@ -170,12 +190,32 @@ export default function SystemResources({
options,
width,
height,
displayMode,
}: WidgetComponentProps<"systemDisks">) {
const t = useI18n();
const queryInput = { integrationIds };
const data =
getUsableWidgetQueryData(clientApi.widget.healthMonitoring.getSystemHealthStatus.useQuery(queryInput)) ?? [];
const healthQuery = clientApi.widget.healthMonitoring.getSystemHealthStatus.useQuery(queryInput);
const results = getUsableWidgetQueryData(healthQuery) ?? [];
const data = results.filter(
(entry): entry is typeof entry & { healthInfo: NonNullable<typeof entry.healthInfo> } => entry.healthInfo !== null,
);
const queryIndicators = (
<Group gap={0}>
<IntegrationErrorIndicator results={results} />
<WidgetQueryErrorIndicator error={healthQuery.error} label={t("widget.systemDisks.name")} />
</Group>
);
const emptyState = (
<Box h="100%" pos="relative">
<Box pos="absolute" top={4} right={8} style={{ zIndex: 2 }}>
{queryIndicators}
</Box>
<WidgetEmptyState />
</Box>
);
if (data.length === 0) return <WidgetEmptyState />;
if (isInitialWidgetQueryPending(healthQuery)) return <WidgetQueryLoadingState />;
if (data.length === 0) return emptyState;
const disks = data.flatMap((entry) => {
const fileSystem = filterStorageVolumes(
@@ -194,32 +234,52 @@ export default function SystemResources({
}));
});
if (data.every((entry) => entry.healthInfo.fileSystem.length === 0)) throw new NoIntegrationDataError();
if (disks.length === 0) return <WidgetEmptyState />;
const hasNoFileSystems = data.every((entry) => entry.healthInfo.fileSystem.length === 0);
const hasFailedSource = results.some((entry) => Boolean(entry.error));
if (hasNoFileSystems && !hasFailedSource && !healthQuery.error) throw new NoIntegrationDataError();
if (hasNoFileSystems || disks.length === 0) return emptyState;
const isAdvanced = displayMode === "advanced";
const minimumCardWidth = 260;
const columns = Math.max(1, Math.min(disks.length, Math.floor(width / minimumCardWidth)));
const cellWidth = width / columns;
return (
<ScrollArea h="100%">
<SimpleGrid cols={columns} spacing="xs" p="xs">
{disks.map(({ integrationId, integrationName, item, smartItem }) => (
<SystemDiskCard
key={`${integrationId}:${item.deviceName}`}
deviceName={item.deviceName}
percentage={item.percentage}
displayText={getDisplayText(item, options.displayMode)}
temperature={options.showTemperatureIfAvailable ? smartItem?.temperature : undefined}
healthy={smartItem?.healthy ?? true} // fall back to healthy if no information is available
showBackgroundBar={options.showBackgroundBar}
integrationName={data.length > 1 ? integrationName : undefined}
secondaryText={getAbsoluteText(item)}
showSecondaryText={height >= 160 && cellWidth >= 260}
showTemperature={height >= 100 && cellWidth >= 220}
/>
))}
</SimpleGrid>
</ScrollArea>
<Box h="100%" pos="relative">
<Box pos="absolute" top={4} right={8} style={{ zIndex: 2 }}>
{queryIndicators}
</Box>
<ScrollArea h="100%">
<SimpleGrid cols={columns} spacing="xs" p="xs">
{disks.map(({ integrationId, integrationName, item, smartItem }) => {
const freeText = t("widget.systemDisks.status.free", {
percentage: String(Math.round(100 - clampPercentage(item.percentage))),
});
const advancedDisplayTexts = getAdvancedDisplayTexts(item, freeText);
return (
<SystemDiskCard
key={`${integrationId}:${item.deviceName}`}
deviceName={item.deviceName}
percentage={item.percentage}
displayText={
isAdvanced ? advancedDisplayTexts.percentage : getDisplayText(item, options.displayMode, freeText)
}
temperature={isAdvanced || options.showTemperatureIfAvailable ? smartItem?.temperature : undefined}
healthy={smartItem?.healthy ?? true} // fall back to healthy if no information is available
showBackgroundBar={isAdvanced || options.showBackgroundBar}
integrationName={isAdvanced || data.length > 1 ? integrationName : undefined}
secondaryText={advancedDisplayTexts.absolute}
freeText={advancedDisplayTexts.free}
smartStatus={smartItem?.overallStatus}
isAdvanced={isAdvanced}
showSecondaryText={isAdvanced || (height >= 160 && cellWidth >= 260)}
showTemperature={isAdvanced || (height >= 100 && cellWidth >= 220)}
/>
);
})}
</SimpleGrid>
</ScrollArea>
</Box>
);
}
@@ -4,10 +4,13 @@ import { useEffect, useMemo, useRef, useState } from "react";
import { Box, Center, Group, Loader, ScrollArea, SimpleGrid, Stack, Text } from "@mantine/core";
import { clientApi } from "@homarr/api/client";
import { useScopedI18n } from "@homarr/translation/client";
import { WidgetEmptyState } from "../common/empty-state";
import { IntegrationErrorIndicator } from "../common/integration-error-indicator";
import type { WidgetComponentProps } from "../definition";
import { getUsableWidgetQueryData } from "../common/query-state";
import { WidgetQueryErrorIndicator } from "../common/query-state-indicator";
import { CombinedNetworkTrafficChart } from "./chart/combined-network-traffic";
import { SystemResourceCPUChart } from "./chart/cpu-chart";
import { SystemResourceGPUChart } from "./chart/gpu-chart";
@@ -16,6 +19,9 @@ import { NetworkTrafficChart } from "./chart/network-traffic";
const COMPACT_HISTORY_SIZE = 15;
const ADVANCED_HISTORY_SIZE = 60;
const ALL_SYSTEM_CHARTS = ["cpu", "memory", "gpu", "network"] as const;
type SystemChart = WidgetComponentProps<"systemResources">["options"]["visibleCharts"][number];
type ChartItem = {
cpu: number;
@@ -51,6 +57,26 @@ export const getCompactChartBudget = (height: number): number => {
return 4;
};
export const getVisibleSystemCharts = ({
configuredCharts,
hasGpu,
hasNetwork,
height,
isAdvanced,
}: {
configuredCharts: readonly SystemChart[];
hasGpu: boolean;
hasNetwork: boolean;
height: number;
isAdvanced: boolean;
}): SystemChart[] => {
const selectedCharts = isAdvanced ? ALL_SYSTEM_CHARTS : configuredCharts;
const availableCharts = selectedCharts.filter(
(chart) => (chart !== "gpu" || !isAdvanced || hasGpu) && (chart !== "network" || hasNetwork),
);
return isAdvanced ? [...availableCharts] : availableCharts.slice(0, getCompactChartBudget(height));
};
export default function SystemResources({
integrationIds,
options,
@@ -58,13 +84,23 @@ export default function SystemResources({
height,
displayMode,
}: WidgetComponentProps<"systemResources">) {
const t = useScopedI18n("widget.systemResources");
const healthQuery = clientApi.widget.healthMonitoring.getSystemHealthStatus.useQuery({ integrationIds });
const data = getUsableWidgetQueryData(healthQuery) ?? [];
const results = getUsableWidgetQueryData(healthQuery) ?? [];
const data = results.filter(
(entry): entry is typeof entry & { healthInfo: NonNullable<typeof entry.healthInfo> } => entry.healthInfo !== null,
);
const { dataUpdatedAt, isPending } = healthQuery;
const isAdvanced = displayMode === "advanced";
const integrationKey = useMemo(() => integrationIds.join("\u0000"), [integrationIds]);
const [historyByIntegration, setHistoryByIntegration] = useState<Record<string, ChartItem[]>>({});
const previousIntegrationKey = useRef(integrationKey);
const queryIndicators = (
<Group gap={0}>
<IntegrationErrorIndicator results={results} />
<WidgetQueryErrorIndicator error={healthQuery.error} label={t("name")} />
</Group>
);
useEffect(() => {
if (previousIntegrationKey.current === integrationKey) return;
@@ -102,6 +138,7 @@ export default function SystemResources({
key={entry.integrationId}
integrationName={entry.integrationName}
items={history}
hasGpu={entry.healthInfo.gpu.length > 0}
memoryCapacityInBytes={entry.healthInfo.memAvailableInBytes + entry.healthInfo.memUsedInBytes}
options={options}
width={availableWidth}
@@ -120,11 +157,23 @@ export default function SystemResources({
);
}
if (data.length === 0) return <WidgetEmptyState />;
if (data.length === 0) {
return (
<Box h="100%" pos="relative">
<Box pos="absolute" top={4} right={8} style={{ zIndex: 2 }}>
{queryIndicators}
</Box>
<WidgetEmptyState />
</Box>
);
}
if (!isAdvanced && data.length === 1 && data[0]) {
return (
<Box h="100%" p="xs">
<Box h="100%" p="xs" pos="relative">
<Box pos="absolute" top={4} right={8} style={{ zIndex: 2 }}>
{queryIndicators}
</Box>
{renderCharts(data[0], width, Math.max(0, height - 20))}
</Box>
);
@@ -133,17 +182,23 @@ export default function SystemResources({
const compactPanelHeight = Math.max(160, Math.floor(height / Math.min(data.length, 2)));
return (
<ScrollArea h="100%">
<SimpleGrid cols={panelColumns} spacing="xs" p="xs">
{data.map((entry) => renderCharts(entry, panelWidth, isAdvanced ? height : compactPanelHeight))}
</SimpleGrid>
</ScrollArea>
<Box h="100%" pos="relative">
<Box pos="absolute" top={4} right={8} style={{ zIndex: 2 }}>
{queryIndicators}
</Box>
<ScrollArea h="100%">
<SimpleGrid cols={panelColumns} spacing="xs" p="xs">
{data.map((entry) => renderCharts(entry, panelWidth, isAdvanced ? height : compactPanelHeight))}
</SimpleGrid>
</ScrollArea>
</Box>
);
}
interface SystemChartsProps {
integrationName: string;
items: ChartItem[];
hasGpu: boolean;
memoryCapacityInBytes: number;
options: WidgetComponentProps<"systemResources">["options"];
width: number;
@@ -155,6 +210,7 @@ interface SystemChartsProps {
const SystemCharts = ({
integrationName,
items,
hasGpu,
memoryCapacityInBytes,
options,
width,
@@ -163,9 +219,15 @@ const SystemCharts = ({
showTitle,
}: SystemChartsProps) => {
const networkItems = getNetworkHistory(items);
const availableCharts = options.visibleCharts.filter((chart) => chart !== "network" || networkItems.length > 0);
const visibleCharts = isAdvanced ? availableCharts : availableCharts.slice(0, getCompactChartBudget(height));
const visibleCharts = getVisibleSystemCharts({
configuredCharts: options.visibleCharts,
hasGpu,
hasNetwork: networkItems.length > 0,
height,
isAdvanced,
});
const showNetwork = visibleCharts.includes("network");
const labelDisplayMode = isAdvanced ? "textWithIcon" : options.labelDisplayMode;
const chartCount = visibleCharts.length;
const chartColumns = isAdvanced && width >= 560 ? 2 : 1;
const chartHeight = isAdvanced
@@ -192,7 +254,7 @@ const SystemCharts = ({
<SystemResourceCPUChart
cpuUsageOverTime={items.map((item) => item.cpu)}
hasShadow={options.hasShadow}
labelDisplayMode={options.labelDisplayMode}
labelDisplayMode={labelDisplayMode}
/>
</Box>
)}
@@ -202,7 +264,7 @@ const SystemCharts = ({
memoryUsageOverTime={items.map((item) => item.memory)}
totalCapacityInBytes={memoryCapacityInBytes}
hasShadow={options.hasShadow}
labelDisplayMode={options.labelDisplayMode}
labelDisplayMode={labelDisplayMode}
/>
</Box>
)}
@@ -211,7 +273,7 @@ const SystemCharts = ({
<SystemResourceGPUChart
gpuUsageOverTime={items.map((item) => item.gpu)}
hasShadow={options.hasShadow}
labelDisplayMode={options.labelDisplayMode}
labelDisplayMode={labelDisplayMode}
/>
</Box>
)}
@@ -222,13 +284,13 @@ const SystemCharts = ({
usageOverTime={networkItems.map((network) => network.down)}
isUp={false}
hasShadow={options.hasShadow}
labelDisplayMode={options.labelDisplayMode}
labelDisplayMode={labelDisplayMode}
/>
<NetworkTrafficChart
usageOverTime={networkItems.map((network) => network.up)}
isUp
hasShadow={options.hasShadow}
labelDisplayMode={options.labelDisplayMode}
labelDisplayMode={labelDisplayMode}
/>
</Group>
) : (
@@ -236,7 +298,7 @@ const SystemCharts = ({
<CombinedNetworkTrafficChart
usageOverTime={networkItems}
hasShadow={options.hasShadow}
labelDisplayMode={options.labelDisplayMode}
labelDisplayMode={labelDisplayMode}
/>
</Box>
))}
+28 -19
View File
@@ -5,38 +5,47 @@ import { createLanguageMapping } from "@homarr/translation";
import { loadAllWidgetDefinitions } from "../manifest";
const doesOptionRenderTranslatedCopy = (option: unknown) => {
if (typeof option !== "object" || option === null || !("type" in option)) return false;
return option.type !== "internal" && option.type !== "customWidgetConfiguration";
};
const widgetDefinitions = await loadAllWidgetDefinitions();
const enTranslation = await createLanguageMapping().en();
describe("Widget properties with description should have matching translations", () => {
for (const [key, definition] of widgetDefinitions) {
Object.entries(definition.createOptions({} as SettingsContextProps)).forEach(([optionKey, optionValue_]) => {
const optionValue = optionValue_ as { withDescription: boolean };
it(`should have matching translations for ${optionKey} option description of ${key} widget`, () => {
const option = enTranslation.default.widget[key].option;
if (!(optionKey in option)) {
throw new Error(`Option ${optionKey} not found in translation`);
}
const value = option[optionKey as keyof typeof option];
Object.entries(definition.createOptions({} as SettingsContextProps))
.filter(([, option]) => doesOptionRenderTranslatedCopy(option))
.forEach(([optionKey, optionValue_]) => {
const optionValue = optionValue_ as { withDescription: boolean };
it(`should have matching translations for ${optionKey} option description of ${key} widget`, () => {
const option = enTranslation.default.widget[key].option;
if (!(optionKey in option)) {
throw new Error(`Option ${optionKey} not found in translation`);
}
const value = option[optionKey as keyof typeof option];
expect("description" in value).toBe(optionValue.withDescription);
expect("description" in value).toBe(optionValue.withDescription);
});
});
});
}
});
describe("Widget properties should have matching name translations", () => {
for (const [key, definition] of widgetDefinitions) {
Object.keys(definition.createOptions({} as SettingsContextProps)).forEach((optionKey) => {
it(`should have matching translations for ${optionKey} option name of ${key} widget`, () => {
const option = enTranslation.default.widget[key].option;
if (!(optionKey in option)) {
throw new Error(`Option ${optionKey} not found in translation`);
}
const value = option[optionKey as keyof typeof option];
Object.entries(definition.createOptions({} as SettingsContextProps))
.filter(([, option]) => doesOptionRenderTranslatedCopy(option))
.forEach(([optionKey]) => {
it(`should have matching translations for ${optionKey} option name of ${key} widget`, () => {
const option = enTranslation.default.widget[key].option;
if (!(optionKey in option)) {
throw new Error(`Option ${optionKey} not found in translation`);
}
const value = option[optionKey as keyof typeof option];
expect("label" in value).toBe(true);
expect("label" in value).toBe(true);
});
});
});
}
});
+53 -28
View File
@@ -9,8 +9,10 @@ import { formatNumber } from "@homarr/common";
import { useScopedI18n } from "@homarr/translation/client";
import { WidgetEmptyState } from "../common/empty-state";
import { IntegrationErrorIndicator } from "../common/integration-error-indicator";
import type { WidgetComponentProps } from "../definition";
import { getUsableWidgetQueryData } from "../common/query-state";
import { WidgetQueryErrorIndicator } from "../common/query-state-indicator";
import { NoIntegrationDataError } from "../errors/no-data-integration";
import classes from "./component.module.css";
import { aggregateUptimeKumaDashboards } from "./aggregate";
@@ -128,12 +130,16 @@ interface UptimeKumaContentProps {
function UptimeKumaContent({ integrationIds, options, width, height, displayMode }: UptimeKumaContentProps) {
const t = useScopedI18n("widget.uptimeKuma");
const dashboardData = getUsableWidgetQueryData(clientApi.widget.uptimeKuma.getDashboard.useQuery({ integrationIds }));
const dashboardQuery = clientApi.widget.uptimeKuma.getDashboard.useQuery({ integrationIds });
const dashboardData = getUsableWidgetQueryData(dashboardQuery);
if (!dashboardData) return <WidgetEmptyState />;
const successfulDashboardData = dashboardData.flatMap((item) =>
item.dashboard === null ? [] : [{ ...item, dashboard: item.dashboard }],
);
const combined = aggregateUptimeKumaDashboards(dashboardData.map((item) => item.dashboard));
const monitors = dashboardData.flatMap((result) =>
const combined = aggregateUptimeKumaDashboards(successfulDashboardData.map((item) => item.dashboard));
const monitors = successfulDashboardData.flatMap((result) =>
result.dashboard.monitors.map((monitor) => ({
...monitor,
key: `${result.integrationId}:${monitor.id}`,
@@ -145,25 +151,22 @@ function UptimeKumaContent({ integrationIds, options, width, height, displayMode
const ringSize = getRingSize(width);
const iconSize = getIconSize(width);
const gridCols = getGridCols(width);
const isAdvanced = displayMode === "advanced";
const enabledStatKeys = Object.entries(statVisibilityByOption)
.filter(([optionKey]) => options[optionKey as keyof typeof options])
.filter(([optionKey]) => isAdvanced || options[optionKey as keyof typeof options])
.map(([, statKey]) => statKey);
const showHero = options.showAverageUptime;
const showRing = options.showUptimeRing && (displayMode === "advanced" || (width >= 170 && height >= 110));
const prioritizedStatKeys =
displayMode === "advanced"
? enabledStatKeys
: enabledStatKeys.toSorted(
(left, right) =>
getCompactStatPriority(left, combined[left]) - getCompactStatPriority(right, combined[right]),
);
const showHero = isAdvanced || options.showAverageUptime;
const showRing = isAdvanced || (options.showUptimeRing && width >= 170 && height >= 110);
const prioritizedStatKeys = isAdvanced
? enabledStatKeys
: enabledStatKeys.toSorted(
(left, right) => getCompactStatPriority(left, combined[left]) - getCompactStatPriority(right, combined[right]),
);
const visibleStatKeys = prioritizedStatKeys.slice(
0,
displayMode === "advanced"
? prioritizedStatKeys.length
: getCompactStatLimit(height, showHero, prioritizedStatKeys.length),
isAdvanced ? prioritizedStatKeys.length : getCompactStatLimit(height, showHero, prioritizedStatKeys.length),
);
const hasContent = showHero || visibleStatKeys.length > 0;
@@ -245,7 +248,17 @@ function UptimeKumaContent({ integrationIds, options, width, height, displayMode
</div>
);
if (displayMode === "compact") return summaryContent;
if (displayMode === "compact") {
return (
<Box h="100%" pos="relative">
<Group pos="absolute" top={4} right={8} gap={0} style={{ zIndex: 2 }}>
<IntegrationErrorIndicator results={dashboardData} />
<WidgetQueryErrorIndicator error={dashboardQuery.error} label={t("name")} />
</Group>
{summaryContent}
</Box>
);
}
const monitorList = (
<Stack gap="xs">
@@ -257,7 +270,7 @@ function UptimeKumaContent({ integrationIds, options, width, height, displayMode
<Text size="sm" fw={600} truncate>
{monitor.name}
</Text>
{dashboardData.length > 1 && (
{(isAdvanced || successfulDashboardData.length > 1) && (
<Text size="xs" c="dimmed">
{monitor.integrationName}
</Text>
@@ -274,20 +287,32 @@ function UptimeKumaContent({ integrationIds, options, width, height, displayMode
if (width < 760) {
return (
<ScrollArea h="100%">
<Stack gap="lg" p="md">
<Box h={Math.max(280, Math.min(420, height - 120))}>{summaryContent}</Box>
{monitorList}
</Stack>
</ScrollArea>
<Box h="100%" pos="relative">
<Group pos="absolute" top={4} right={8} gap={0} style={{ zIndex: 2 }}>
<IntegrationErrorIndicator results={dashboardData} />
<WidgetQueryErrorIndicator error={dashboardQuery.error} label={t("name")} />
</Group>
<ScrollArea h="100%">
<Stack gap="lg" p="md">
<Box h={Math.max(280, Math.min(420, height - 120))}>{summaryContent}</Box>
{monitorList}
</Stack>
</ScrollArea>
</Box>
);
}
return (
<SimpleGrid cols={2} spacing="lg" h="100%" p="md" style={{ gridTemplateRows: "minmax(0, 1fr)" }}>
{summaryContent}
<ScrollArea h="100%">{monitorList}</ScrollArea>
</SimpleGrid>
<Box h="100%" pos="relative">
<Group pos="absolute" top={4} right={8} gap={0} style={{ zIndex: 2 }}>
<IntegrationErrorIndicator results={dashboardData} />
<WidgetQueryErrorIndicator error={dashboardQuery.error} label={t("name")} />
</Group>
<SimpleGrid cols={2} spacing="lg" h="100%" p="md" style={{ gridTemplateRows: "minmax(0, 1fr)" }}>
{summaryContent}
<ScrollArea h="100%">{monitorList}</ScrollArea>
</SimpleGrid>
</Box>
);
}
+31 -12
View File
@@ -11,36 +11,49 @@ import type { WudContainerUpdate } from "@homarr/integrations";
import { useScopedI18n } from "@homarr/translation/client";
import { WidgetEmptyState } from "../common/empty-state";
import { getSafeApplicationUrl, SAFE_NEW_TAB_REL } from "../common/application-url";
import { WidgetQueryErrorIndicator } from "../common/query-state-indicator";
import type { WidgetComponentProps } from "../definition";
import classes from "./component.module.css";
export default function WudWidget({ integrationIds, options, width }: WidgetComponentProps<"wud">) {
export default function WudWidget({ integrationIds, options, width, displayMode }: WidgetComponentProps<"wud">) {
const integrationId = integrationIds[0];
if (!integrationId) return null;
return <WudWidgetContent integrationId={integrationId} options={options} width={width} />;
return (
<WudWidgetContent
integrationId={integrationId}
options={options}
width={width}
isAdvanced={displayMode === "advanced"}
/>
);
}
const WudWidgetContent = ({
integrationId,
options,
width,
isAdvanced,
}: {
integrationId: string;
options: WidgetComponentProps<"wud">["options"];
width: number;
isAdvanced: boolean;
}) => {
const t = useScopedI18n("widget.wud");
const [data] = clientApi.widget.wud.getStats.useSuspenseQuery({ integrationId });
const [data, statsQuery] = clientApi.widget.wud.getStats.useSuspenseQuery({ integrationId });
const board = useRequiredBoard();
const isTiny = width < 256;
const isTiny = !isAdvanced && width < 256;
const stats = data.stats;
if (stats.totalContainers === 0) return <WidgetEmptyState />;
const updatePercentage = Math.round((stats.updatesAvailable / stats.totalContainers) * 100);
const badgeColor = stats.updatesAvailable === 0 ? "green" : progressColor(updatePercentage);
const showUpdateList = options.showUpdateList && stats.updates.length > 0;
const showTitle = isAdvanced || options.showTitle;
const showRing = isAdvanced || options.showRing;
const showUpdateList = (isAdvanced || options.showUpdateList) && stats.updates.length > 0;
const ring = (
<RingProgress
@@ -73,7 +86,7 @@ const WudWidgetContent = ({
</Stack>
);
const tinyContent = options.showRing ? (
const tinyContent = showRing ? (
<Tooltip
label={
<Stack gap={2}>
@@ -102,7 +115,12 @@ const WudWidgetContent = ({
return (
<Stack p="xs" gap="xs" h="100%">
{options.showTitle && !isTiny && (
{Boolean(statsQuery.error) && (
<Group justify="flex-end">
<WidgetQueryErrorIndicator error={statsQuery.error} label={t("name")} />
</Group>
)}
{showTitle && !isTiny && (
<Group gap="xs" wrap="nowrap" justify="space-between" miw={0}>
<Group gap="xs" wrap="nowrap" miw={0}>
<Avatar size={20} radius="sm" src={getIconUrl("wud")} />
@@ -122,12 +140,12 @@ const WudWidgetContent = ({
tinyContent
) : options.layout === "horizontal" ? (
<Group justify="center" wrap="nowrap" gap="md">
{options.showRing && ring}
{showRing && ring}
{summary}
</Group>
) : (
<Stack align="center" gap="xs">
{options.showRing && ring}
{showRing && ring}
{summary}
</Stack>
)}
@@ -181,6 +199,7 @@ const UpdateCard = ({
className: string | undefined;
}) => {
const t = useScopedI18n("widget.wud");
const href = getSafeApplicationUrl(update.link);
const isDigestUpdate = isDigestVersion(update.newVersion);
const fullVersionText = buildVersionText(update.currentVersion, update.newVersion);
const versionText = isDigestUpdate
@@ -201,12 +220,12 @@ const UpdateCard = ({
</Text>
<Group gap={4} wrap="nowrap" style={{ flexShrink: 0 }}>
{showVersionTooltip ? <Tooltip label={fullVersionText}>{versionBadge}</Tooltip> : versionBadge}
{update.link && (
{href && (
<ActionIcon
component="a"
href={update.link}
href={href}
target="_blank"
rel="noreferrer noopener"
rel={SAFE_NEW_TAB_REL}
variant="subtle"
color="gray"
size="sm"