fix(ci): add css module types and resolve typecheck/lint warnings in UI and modals
This commit is contained in:
7 files changed
+130
-118
No files matched your search
@@ -161,7 +161,7 @@ describe("Advanced Add App - Modal Subcomponents", () => {
|
||||
await act(async () =>
|
||||
root.render(
|
||||
<MantineProvider>
|
||||
<WidgetItem item={item} isSelected={false} connectionStatus="ready" onSelect={onSelect} />
|
||||
<WidgetItem item={item} disabled={false} loading={false} connectionStatus="ready" onSelect={onSelect} />
|
||||
</MantineProvider>,
|
||||
),
|
||||
);
|
||||
@@ -192,7 +192,13 @@ describe("Advanced Add App - Modal Subcomponents", () => {
|
||||
await act(async () =>
|
||||
root.render(
|
||||
<MantineProvider>
|
||||
<WidgetItem item={item} isSelected={true} connectionStatus="noConnectionRequired" onSelect={vi.fn()} />
|
||||
<WidgetItem
|
||||
item={item}
|
||||
disabled={false}
|
||||
loading={false}
|
||||
connectionStatus="noConnectionRequired"
|
||||
onSelect={vi.fn()}
|
||||
/>
|
||||
</MantineProvider>,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useMemo, useRef, useState } from "react";
|
||||
import {
|
||||
Avatar,
|
||||
Badge,
|
||||
@@ -66,7 +66,7 @@ interface ItemSelectModalContentProps {
|
||||
initialSearch?: string;
|
||||
}
|
||||
|
||||
interface WidgetItemData {
|
||||
export interface WidgetItemData {
|
||||
kind: WidgetKind;
|
||||
supportedIntegrations: IntegrationKind[];
|
||||
icon: TablerIcon;
|
||||
@@ -556,7 +556,7 @@ export const WidgetItem = ({
|
||||
);
|
||||
};
|
||||
|
||||
const ConnectionStatusBadge = ({ status }: { status: WidgetConnectionStatus }) => {
|
||||
export const ConnectionStatusBadge = ({ status }: { status: WidgetConnectionStatus }) => {
|
||||
if (status === "noConnectionRequired") return null;
|
||||
const t = useI18n();
|
||||
const color = status === "ready" ? "green" : status === "needsSetup" ? "yellow" : "gray";
|
||||
@@ -568,7 +568,7 @@ const ConnectionStatusBadge = ({ status }: { status: WidgetConnectionStatus }) =
|
||||
);
|
||||
};
|
||||
|
||||
const SupportedIntegrations = ({ integrations }: { integrations: IntegrationKind[] }) => {
|
||||
export const SupportedIntegrations = ({ integrations }: { integrations: IntegrationKind[] }) => {
|
||||
if (integrations.length === 0) {
|
||||
return (
|
||||
<Text size="xs" c="dimmed" fs="italic">
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
declare const classes: {
|
||||
readonly root: string;
|
||||
readonly header: string;
|
||||
readonly body: string;
|
||||
readonly footer: string;
|
||||
};
|
||||
export default classes;
|
||||
@@ -3,7 +3,7 @@
|
||||
import { act, createRef } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import type { Root } from "react-dom/client";
|
||||
import { Badge, MantineProvider, Text } from "@mantine/core";
|
||||
import { Badge, MantineProvider } from "@mantine/core";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { SelectableCard } from "./selectable-card";
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
factory,
|
||||
Group,
|
||||
LoadingOverlay,
|
||||
Stack,
|
||||
Text,
|
||||
Tooltip,
|
||||
useProps,
|
||||
@@ -54,124 +53,126 @@ const varsResolver = createVarsResolver<SelectableCardFactory>((_theme, { radius
|
||||
},
|
||||
}));
|
||||
|
||||
export const SelectableCard = factory<SelectableCardFactory>((_props, ref) => {
|
||||
const props = useProps("SelectableCard", defaultProps, _props);
|
||||
const {
|
||||
classNames,
|
||||
className,
|
||||
style,
|
||||
styles,
|
||||
unstyled,
|
||||
vars,
|
||||
attributes,
|
||||
icon,
|
||||
title,
|
||||
topRight,
|
||||
description,
|
||||
footerLeft,
|
||||
footerRight,
|
||||
selected,
|
||||
loading = false,
|
||||
disabled = false,
|
||||
children,
|
||||
type = "button",
|
||||
...others
|
||||
} = props;
|
||||
export const SelectableCard = factory<SelectableCardFactory>(
|
||||
(_props: SelectableCardProps, ref: React.ForwardedRef<HTMLButtonElement>) => {
|
||||
const props = useProps("SelectableCard", defaultProps, _props);
|
||||
const {
|
||||
classNames,
|
||||
className,
|
||||
style,
|
||||
styles,
|
||||
unstyled,
|
||||
vars,
|
||||
attributes,
|
||||
icon,
|
||||
title,
|
||||
topRight,
|
||||
description,
|
||||
footerLeft,
|
||||
footerRight,
|
||||
selected,
|
||||
loading = false,
|
||||
disabled = false,
|
||||
children,
|
||||
type = "button",
|
||||
...others
|
||||
} = props;
|
||||
|
||||
const getStyles = useStyles<SelectableCardFactory>({
|
||||
name: "SelectableCard",
|
||||
classes,
|
||||
props,
|
||||
className,
|
||||
style,
|
||||
classNames,
|
||||
styles,
|
||||
unstyled,
|
||||
vars,
|
||||
attributes,
|
||||
varsResolver,
|
||||
});
|
||||
const getStyles = useStyles<SelectableCardFactory>({
|
||||
name: "SelectableCard",
|
||||
classes,
|
||||
props,
|
||||
className,
|
||||
style,
|
||||
classNames,
|
||||
styles,
|
||||
unstyled,
|
||||
vars,
|
||||
attributes,
|
||||
varsResolver,
|
||||
});
|
||||
|
||||
return (
|
||||
<Box
|
||||
component="button"
|
||||
type={type}
|
||||
ref={ref}
|
||||
disabled={disabled || loading}
|
||||
data-selected={selected || undefined}
|
||||
aria-pressed={selected !== undefined ? selected : undefined}
|
||||
{...getStyles("root")}
|
||||
{...others}
|
||||
>
|
||||
<LoadingOverlay visible={loading} loaderProps={{ size: "sm" }} />
|
||||
return (
|
||||
<Box
|
||||
component="button"
|
||||
type={type}
|
||||
ref={ref}
|
||||
disabled={disabled || loading}
|
||||
data-selected={selected || undefined}
|
||||
aria-pressed={selected !== undefined ? selected : undefined}
|
||||
{...getStyles("root")}
|
||||
{...others}
|
||||
>
|
||||
<LoadingOverlay visible={loading} loaderProps={{ size: "sm" }} />
|
||||
|
||||
{/* Header Section: Inset background with Title that never elides before the category */}
|
||||
{(icon || title || topRight) && (
|
||||
<Box {...getStyles("header")}>
|
||||
<Group
|
||||
justify="space-between"
|
||||
align="center"
|
||||
wrap="nowrap"
|
||||
gap="xs"
|
||||
style={{ width: "100%", overflow: "hidden" }}
|
||||
>
|
||||
<Group gap="xs" wrap="nowrap" style={{ flex: "1 1 auto", minWidth: 0, overflow: "hidden" }}>
|
||||
{icon}
|
||||
{typeof title === "string" ? (
|
||||
<Text
|
||||
fw={700}
|
||||
size="md"
|
||||
{/* Header Section: Inset background with Title that never elides before the category */}
|
||||
{(icon || title || topRight) && (
|
||||
<Box {...getStyles("header")}>
|
||||
<Group
|
||||
justify="space-between"
|
||||
align="center"
|
||||
wrap="nowrap"
|
||||
gap="xs"
|
||||
style={{ width: "100%", overflow: "hidden" }}
|
||||
>
|
||||
<Group gap="xs" wrap="nowrap" style={{ flex: "1 1 auto", minWidth: 0, overflow: "hidden" }}>
|
||||
{icon}
|
||||
{typeof title === "string" ? (
|
||||
<Text
|
||||
fw={700}
|
||||
size="md"
|
||||
style={{
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
) : (
|
||||
title
|
||||
)}
|
||||
</Group>
|
||||
{topRight && (
|
||||
<Box
|
||||
style={{
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
minWidth: 0,
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
) : (
|
||||
title
|
||||
{topRight}
|
||||
</Box>
|
||||
)}
|
||||
</Group>
|
||||
{topRight && (
|
||||
<Box
|
||||
style={{
|
||||
minWidth: 0,
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
{topRight}
|
||||
</Box>
|
||||
)}
|
||||
</Group>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Body: Custom Children or Default Description */}
|
||||
{children ? (
|
||||
<Box {...getStyles("body")}>{children}</Box>
|
||||
) : description !== undefined ? (
|
||||
<Box {...getStyles("body")}>
|
||||
<Tooltip label={description} multiline w={260} disabled={!description}>
|
||||
<Text size="sm" c="dimmed" lineClamp={2} lh={1.35}>
|
||||
{description || "No description provided"}
|
||||
</Text>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
) : null}
|
||||
{/* Body: Custom Children or Default Description */}
|
||||
{children ? (
|
||||
<Box {...getStyles("body")}>{children}</Box>
|
||||
) : description !== undefined ? (
|
||||
<Box {...getStyles("body")}>
|
||||
<Tooltip label={description} multiline w={260} disabled={!description}>
|
||||
<Text size="sm" c="dimmed" lineClamp={2} lh={1.35}>
|
||||
{description || "No description provided"}
|
||||
</Text>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
) : null}
|
||||
|
||||
{/* Footer Section: Inset Dashed Bottom Meta */}
|
||||
{(footerLeft || footerRight) && (
|
||||
<Box {...getStyles("footer")}>
|
||||
<Group justify="space-between" align="center" wrap="nowrap" gap="xs" style={{ width: "100%" }}>
|
||||
<Box style={{ minWidth: 0, flexShrink: 1 }}>{footerLeft}</Box>
|
||||
<Box style={{ minWidth: 0, flexShrink: 0 }}>{footerRight}</Box>
|
||||
</Group>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
{/* Footer Section: Inset Dashed Bottom Meta */}
|
||||
{(footerLeft || footerRight) && (
|
||||
<Box {...getStyles("footer")}>
|
||||
<Group justify="space-between" align="center" wrap="nowrap" gap="xs" style={{ width: "100%" }}>
|
||||
<Box style={{ minWidth: 0, flexShrink: 1 }}>{footerLeft}</Box>
|
||||
<Box style={{ minWidth: 0, flexShrink: 0 }}>{footerRight}</Box>
|
||||
</Group>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
SelectableCard.displayName = "@homarr/ui/SelectableCard";
|
||||
SelectableCard.classes = classes;
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
IconBuildingBank,
|
||||
IconBusStop,
|
||||
IconCalendar,
|
||||
IconCalendarWeek,
|
||||
IconChartBar,
|
||||
IconClock,
|
||||
IconClockPlay,
|
||||
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
IconBuildingBank,
|
||||
IconBusStop,
|
||||
IconCalendar,
|
||||
IconCalendarWeek,
|
||||
IconChartAreaLine,
|
||||
IconChartBar,
|
||||
IconClock,
|
||||
|
||||
Reference in new issue
Block a user