fix: require advanced widget focus opt-in
This commit is contained in:
1 parent
ae515584cc
commit
38d30acb87
25 files changed
+56
-29
No files matched your search
@@ -3,41 +3,44 @@ import { describe, expect, test } from "vitest";
|
||||
import { supportsAdvancedFocus } from "./definition";
|
||||
import { widgetImports } from ".";
|
||||
|
||||
const compactOnlyWidgetKinds = [
|
||||
"app",
|
||||
"bazarr",
|
||||
"beszelAlerts",
|
||||
"beszelSystemGrid",
|
||||
"beszelSystemStats",
|
||||
"beszelSystemTable",
|
||||
"coolify",
|
||||
"dnsHoleControls",
|
||||
"dnsHoleSummary",
|
||||
"iframe",
|
||||
"indexerManager",
|
||||
"mediaRequests-requestList",
|
||||
"mediaRequests-requestStats",
|
||||
"minecraftServerStatus",
|
||||
"networkControllerSummary",
|
||||
"notebook",
|
||||
"notifications",
|
||||
"paperlessNgx",
|
||||
"patchmon",
|
||||
"releases",
|
||||
"rssFeed",
|
||||
"stockPrice",
|
||||
"systemDisks",
|
||||
"video",
|
||||
"vpn",
|
||||
const advancedFocusWidgetKinds = [
|
||||
"anchorNote",
|
||||
"archiveTeamWarrior",
|
||||
"audioStats",
|
||||
"bookmarks",
|
||||
"calendar",
|
||||
"clock",
|
||||
"dockerContainers",
|
||||
"downloads",
|
||||
"firewall",
|
||||
"healthMonitoring",
|
||||
"immich-albumCarousel",
|
||||
"immich-serverStats",
|
||||
"mediaMissing",
|
||||
"mediaReleases",
|
||||
"mediaServer",
|
||||
"mediaTranscoding",
|
||||
"networkControllerStatus",
|
||||
"smartHome-entityState",
|
||||
"smartHome-executeAutomation",
|
||||
"speedtestTracker",
|
||||
"systemResources",
|
||||
"timetable",
|
||||
"tracearr",
|
||||
"traefik",
|
||||
"umami",
|
||||
"ups",
|
||||
"uptimeKuma",
|
||||
"weather",
|
||||
] as const;
|
||||
|
||||
describe("advanced focus support", () => {
|
||||
test("is reserved for widgets with a distinct advanced experience", () => {
|
||||
const actualCompactOnlyKinds = Object.entries(widgetImports)
|
||||
.filter(([, widgetImport]) => !supportsAdvancedFocus(widgetImport.definition))
|
||||
const actualAdvancedFocusKinds = Object.entries(widgetImports)
|
||||
.filter(([, widgetImport]) => supportsAdvancedFocus(widgetImport.definition))
|
||||
.map(([kind]) => kind)
|
||||
.toSorted();
|
||||
|
||||
expect(actualCompactOnlyKinds).toEqual([...compactOnlyWidgetKinds].toSorted());
|
||||
expect(actualAdvancedFocusKinds).toEqual([...advancedFocusWidgetKinds].toSorted());
|
||||
});
|
||||
});
|
||||
@@ -5,6 +5,7 @@ import { optionsBuilder } from "../options";
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("archiveTeamWarrior", {
|
||||
icon: IconArchive,
|
||||
supportsAdvancedFocus: true,
|
||||
maxIntegrations: 1,
|
||||
createOptions() {
|
||||
return optionsBuilder.from((factory) => ({
|
||||
|
||||
@@ -13,6 +13,7 @@ const hideUnlessAudiobookshelf = {
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("audioStats", {
|
||||
icon: IconHeadphones,
|
||||
supportsAdvancedFocus: true,
|
||||
queryKeys: [[["widget", "audioStats", "getStats"]], [["widget", "mediaServer", "getCurrentStreams"]]],
|
||||
queryMatcher: matchesWidgetRuntimeQuery,
|
||||
supportedIntegrations: ["navidrome", "audiobookshelf"],
|
||||
|
||||
@@ -9,6 +9,7 @@ import { optionsBuilder } from "../options";
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("calendar", {
|
||||
icon: IconCalendar,
|
||||
supportsAdvancedFocus: true,
|
||||
queryKey: [["widget", "calendar", "findAllEvents"]],
|
||||
queryMatcher: matchesWidgetRuntimeQuery,
|
||||
createOptions() {
|
||||
|
||||
@@ -6,6 +6,7 @@ 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;
|
||||
|
||||
@@ -25,6 +25,7 @@ const columnTranslationKeyMap = {
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("dockerContainers", {
|
||||
icon: IconBrandDocker,
|
||||
supportsAdvancedFocus: true,
|
||||
queryKey: [["docker", "getContainers"]],
|
||||
refetchInterval: 30,
|
||||
createOptions() {
|
||||
|
||||
@@ -42,6 +42,7 @@ const sortColumns = [
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("downloads", {
|
||||
icon: IconDownload,
|
||||
supportsAdvancedFocus: true,
|
||||
queryKey: [["widget", "downloads", "getJobsAndStatuses"]],
|
||||
queryMatcher: ({ input }, scope) =>
|
||||
widgetQueryInputMatches(input, {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { optionsBuilder } from "../options";
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("firewall", {
|
||||
icon: IconWall,
|
||||
supportsAdvancedFocus: true,
|
||||
refetchInterval: 5,
|
||||
createOptions() {
|
||||
return optionsBuilder.from(() => ({}));
|
||||
|
||||
@@ -51,6 +51,7 @@ const createOptions = () =>
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("immich-albumCarousel", {
|
||||
icon: IconPhoto,
|
||||
supportsAdvancedFocus: true,
|
||||
queryKey: [["widget", "immich", "getAlbum"]],
|
||||
queryMatcher: ({ input }, scope) =>
|
||||
widgetQueryInputMatches(input, {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { optionsBuilder } from "../../options";
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("immich-serverStats", {
|
||||
icon: IconGraphFilled,
|
||||
supportsAdvancedFocus: true,
|
||||
queryKeys: [[["widget", "immich", "getServerStats"]], [["widget", "immich", "getAlbums"]]],
|
||||
queryMatcher: matchesWidgetRuntimeQuery,
|
||||
refetchInterval: null,
|
||||
|
||||
@@ -9,6 +9,7 @@ const pageSizeOptions = ["10", "20", "30", "50"] as const;
|
||||
|
||||
export const { componentLoader, definition } = createWidgetDefinition("mediaMissing", {
|
||||
icon: IconMovie,
|
||||
supportsAdvancedFocus: true,
|
||||
queryKey: [["widget", "mediaOrganizer", "getData"]],
|
||||
queryMatcher: matchesWidgetRuntimeQuery,
|
||||
createOptions() {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { optionsBuilder } from "../options";
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("mediaReleases", {
|
||||
icon: IconTicket,
|
||||
supportsAdvancedFocus: true,
|
||||
queryKey: [["widget", "mediaRelease"]],
|
||||
refetchInterval: null,
|
||||
createOptions() {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { optionsBuilder } from "../options";
|
||||
|
||||
export const { componentLoader, definition } = createWidgetDefinition("mediaServer", {
|
||||
icon: IconVideo,
|
||||
supportsAdvancedFocus: true,
|
||||
queryKey: [["widget", "mediaServer", "getCurrentStreams"]],
|
||||
queryMatcher: ({ input }, scope) =>
|
||||
widgetQueryInputMatches(input, {
|
||||
|
||||
@@ -11,6 +11,7 @@ export const views = ["workers", "queue", "statistics"] as const;
|
||||
|
||||
export const { componentLoader, definition } = createWidgetDefinition("mediaTranscoding", {
|
||||
icon: IconTransform,
|
||||
supportsAdvancedFocus: true,
|
||||
queryKey: [["widget", "mediaTranscoding", "getDataAsync"]],
|
||||
queryMatcher: matchesWidgetRuntimeQuery,
|
||||
maxIntegrations: 1,
|
||||
|
||||
@@ -7,6 +7,7 @@ import { optionsBuilder } from "../../options";
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("networkControllerStatus", {
|
||||
icon: IconTopologyFull,
|
||||
supportsAdvancedFocus: true,
|
||||
queryKey: [["widget", "networkController"]],
|
||||
refetchInterval: null,
|
||||
createOptions() {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { optionsBuilder } from "../../options";
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("smartHome-executeAutomation", {
|
||||
icon: IconBinaryTree,
|
||||
supportsAdvancedFocus: true,
|
||||
maxIntegrations: 1,
|
||||
createOptions() {
|
||||
return optionsBuilder.from((factory) => ({
|
||||
|
||||
@@ -5,6 +5,7 @@ import { optionsBuilder } from "../options";
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("speedtestTracker", {
|
||||
icon: IconSpeedboat,
|
||||
supportsAdvancedFocus: true,
|
||||
refetchInterval: null,
|
||||
createOptions() {
|
||||
return optionsBuilder.from(
|
||||
|
||||
@@ -14,6 +14,7 @@ const labelDisplayModeOptions = {
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("systemResources", {
|
||||
icon: IconGraphFilled,
|
||||
supportsAdvancedFocus: true,
|
||||
queryKey: [["widget", "healthMonitoring"]],
|
||||
refetchInterval: 5,
|
||||
supportedIntegrations: ["dashDot", "openmediavault", "truenas", "unraid", "glances", "synology"],
|
||||
|
||||
@@ -9,6 +9,7 @@ import { optionsBuilder } from "../options";
|
||||
|
||||
export const { componentLoader, definition } = createWidgetDefinition("timetable", {
|
||||
icon: IconBusStop,
|
||||
supportsAdvancedFocus: true,
|
||||
errors: {
|
||||
BAD_REQUEST: {
|
||||
icon: IconWorldOff,
|
||||
|
||||
@@ -5,6 +5,7 @@ import { optionsBuilder } from "../options";
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("tracearr", {
|
||||
icon: IconActivityHeartbeat,
|
||||
supportsAdvancedFocus: true,
|
||||
refetchInterval: 5,
|
||||
createOptions() {
|
||||
return optionsBuilder.from((factory) => ({
|
||||
|
||||
@@ -5,6 +5,7 @@ import { optionsBuilder } from "../options";
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("traefik", {
|
||||
icon: IconRoute,
|
||||
supportsAdvancedFocus: true,
|
||||
createOptions() {
|
||||
return optionsBuilder.from((factory) => ({
|
||||
showTcp: factory.switch({
|
||||
|
||||
@@ -8,6 +8,7 @@ export const timeFrameValues = ["today", "24h", "7d", "30d", "month", "lastMonth
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("umami", {
|
||||
icon: IconChartBar,
|
||||
supportsAdvancedFocus: true,
|
||||
queryKeys: [
|
||||
[["widget", "umami", "getVisitorStats"]],
|
||||
[["widget", "umami", "getActiveVisitors"]],
|
||||
|
||||
@@ -7,6 +7,7 @@ import { optionsBuilder } from "../options";
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("ups", {
|
||||
icon: IconBatteryCharging,
|
||||
supportsAdvancedFocus: true,
|
||||
createOptions() {
|
||||
return optionsBuilder.from((factory) => ({
|
||||
showBattery: factory.switch({
|
||||
|
||||
@@ -5,6 +5,7 @@ import { optionsBuilder } from "../options";
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("uptimeKuma", {
|
||||
icon: IconHeartbeat,
|
||||
supportsAdvancedFocus: true,
|
||||
createOptions() {
|
||||
return optionsBuilder.from((factory) => ({
|
||||
showAverageUptime: factory.switch({
|
||||
|
||||
@@ -7,6 +7,7 @@ import { optionsBuilder } from "../options";
|
||||
|
||||
export const { definition, componentLoader } = createWidgetDefinition("weather", {
|
||||
icon: IconCloud,
|
||||
supportsAdvancedFocus: true,
|
||||
queryKey: [["widget", "weather", "atLocation"]],
|
||||
queryMatcher: ({ input }, scope) => {
|
||||
const location = scope.options.location;
|
||||
|
||||
Reference in new issue
Block a user