fix(custom-widgets): address review feedback
This commit is contained in:
9 files changed
+93
-63
No files matched your search
@@ -18,14 +18,13 @@ export const WidgetCustomWidgetSelectInput = ({
|
||||
const t = useWidgetInputTranslation(kind, property);
|
||||
const form = useFormContext();
|
||||
const board = useOptionalBoard();
|
||||
const currentValue = form.values.options[property] as string;
|
||||
const { data, isLoading } = clientApi.customWidget.available.useQuery(
|
||||
{ boardId: board?.id ?? "" },
|
||||
{ boardId: board?.id ?? "", currentId: currentValue || undefined },
|
||||
{ enabled: board !== null },
|
||||
);
|
||||
const [search, setSearch] = useState("");
|
||||
|
||||
const currentValue = form.values.options[property] as string;
|
||||
|
||||
const definitions = useMemo(() => (data ?? []).map((def) => ({ value: def.id, label: def.name })), [data]);
|
||||
|
||||
const filteredOptions = useMemo(
|
||||
|
||||
@@ -20,7 +20,7 @@ function appendParseError(prev: string[], message: string): string[] {
|
||||
return [...prev, message];
|
||||
}
|
||||
|
||||
const METHOD_COLORS: Record<string, string> = {
|
||||
export const CUSTOM_JSX_METHOD_COLORS: Record<string, string> = {
|
||||
GET: "blue",
|
||||
POST: "orange",
|
||||
PUT: "yellow",
|
||||
@@ -173,7 +173,7 @@ export default function CustomJsxDisplay({ data }: { data: Record<string, unknow
|
||||
{capability.id}
|
||||
</Text>
|
||||
<Group gap={4} wrap="nowrap">
|
||||
<Badge size="xs" color={METHOD_COLORS[capability.method] ?? "gray"} variant="light">
|
||||
<Badge size="xs" color={CUSTOM_JSX_METHOD_COLORS[capability.method] ?? "gray"} variant="light">
|
||||
{capability.method}
|
||||
</Badge>
|
||||
<Badge size="xs" color="gray" variant="outline">
|
||||
|
||||
@@ -185,7 +185,7 @@ export function SubFetch({
|
||||
|
||||
const result = query.data as RequestResult | undefined;
|
||||
const requestError =
|
||||
(query.error ? t("requestFailed") : null) ??
|
||||
(query.error && !result ? t("requestFailed") : null) ??
|
||||
(!result?.ok ? (result?.error ?? `${t("requestFailed")} (${result?.status ?? 0})`) : null);
|
||||
|
||||
if (!result && query.isPending) {
|
||||
|
||||
@@ -239,13 +239,25 @@ function isSafeUrl(url: unknown): boolean {
|
||||
function SafeAnchor(props: Record<string, unknown>) {
|
||||
const href = props.href;
|
||||
const safeHref = href && isSafeUrl(href) ? href : undefined;
|
||||
return createElement(Anchor as never, { ...sanitizeCustomJsxProps(props), href: safeHref });
|
||||
const sanitized = sanitizeCustomJsxProps(props);
|
||||
const opensNewWindow = sanitized.target === "_blank";
|
||||
return createElement(Anchor as never, {
|
||||
...sanitized,
|
||||
href: safeHref,
|
||||
rel: opensNewWindow ? "noopener noreferrer" : sanitized.rel,
|
||||
});
|
||||
}
|
||||
|
||||
function SafeNavLink(props: Record<string, unknown>) {
|
||||
const href = props.href;
|
||||
const safeHref = href && isSafeUrl(href) ? href : undefined;
|
||||
return createElement(NavLink as never, { ...sanitizeCustomJsxProps(props), href: safeHref });
|
||||
const sanitized = sanitizeCustomJsxProps(props);
|
||||
const opensNewWindow = sanitized.target === "_blank";
|
||||
return createElement(NavLink as never, {
|
||||
...sanitized,
|
||||
href: safeHref,
|
||||
rel: opensNewWindow ? "noopener noreferrer" : sanitized.rel,
|
||||
});
|
||||
}
|
||||
|
||||
function SafeButton(props: Record<string, unknown>) {
|
||||
@@ -301,7 +313,13 @@ function SafeCalendar(props: Record<string, unknown>) {
|
||||
}
|
||||
|
||||
function SafeMiniCalendar(props: Record<string, unknown>) {
|
||||
return createElement(MiniCalendar as never, { ...sanitizeCustomJsxProps(props), static: true });
|
||||
return createElement(MiniCalendar as never, {
|
||||
...sanitizeCustomJsxProps(props),
|
||||
style: { pointerEvents: "none" },
|
||||
previousControlProps: { disabled: true, tabIndex: -1 },
|
||||
nextControlProps: { disabled: true, tabIndex: -1 },
|
||||
getDayProps: () => ({ disabled: true, tabIndex: -1 }),
|
||||
});
|
||||
}
|
||||
|
||||
function SafeTree(props: Record<string, unknown>) {
|
||||
@@ -309,7 +327,12 @@ function SafeTree(props: Record<string, unknown>) {
|
||||
}
|
||||
|
||||
function SafeDatePicker(props: Record<string, unknown>) {
|
||||
return createElement(DatePicker as never, { ...sanitizeCustomJsxProps(props), static: true });
|
||||
return createElement(DatePicker as never, {
|
||||
...sanitizeCustomJsxProps(props),
|
||||
style: { pointerEvents: "none" },
|
||||
enableKeyboardNavigation: false,
|
||||
getDayProps: () => ({ disabled: true, tabIndex: -1 }),
|
||||
});
|
||||
}
|
||||
|
||||
function createSafeDateComponent(component: ComponentType<never>) {
|
||||
@@ -730,7 +753,7 @@ safeDate.toLocaleTimeString = createSafeCallable((v: string | number, locale?: s
|
||||
safeDate.getTime = createSafeCallable((v: string | number) => new Date(v).getTime());
|
||||
safeDate.getYear = createSafeCallable((v: string | number) => new Date(v).getFullYear());
|
||||
safeDate.getMonth = createSafeCallable((v: string | number) => new Date(v).getMonth());
|
||||
safeDate.getDay = createSafeCallable((v: string | number) => new Date(v).getDay());
|
||||
safeDate.getDay = createSafeCallable((v: string | number) => new Date(v).getUTCDay());
|
||||
Object.freeze(safeDate);
|
||||
|
||||
export const SAFE_BINDINGS = (apiData: unknown) => ({
|
||||
|
||||
@@ -838,7 +838,7 @@ class Interpreter {
|
||||
case "charAt":
|
||||
return { handled: true, value: receiver.charAt(numericArgument(args[0], 0)) };
|
||||
case "split": {
|
||||
const limit = Math.max(0, Math.min(2_000, numericArgument(args[1], 100)));
|
||||
const limit = Math.max(0, Math.min(2_000, numericArgument(args[1], 2_000)));
|
||||
const split = args[0] === undefined ? [receiver] : receiver.split(String(args[0]), limit);
|
||||
this.budget.collection(split.length);
|
||||
return { handled: true, value: split };
|
||||
|
||||
Reference in new issue
Block a user