refactor(opal): Move the dependency-free raw inputs into Opal (#14617)

This commit is contained in:
Raunak Bhagat authored and GitHub committed 2026-09-10 01:05:52 +00:00
1 parent ff5e0b36bf
commit 8a0e43b7ee
52 files changed
+333 -315

No files matched your search

+1
View File
@@ -151,6 +151,7 @@
"@radix-ui/react-tabs": "^1.0.0",
"@radix-ui/react-tooltip": "^1.0.0",
"@tanstack/react-table": "^8.0.0",
"date-fns": "^4.0.0",
"formik": "^2.0.0",
"next": ">=14.0.0",
"react": "^18.0.0 || ^19.0.0",
+2 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@onyx-ai/opal",
"version": "0.0.0",
"description": "Opal — Onyx's Typescript component library and design system.",
"description": "Opal \u2014 Onyx's Typescript component library and design system.",
"license": "MIT",
"repository": {
"type": "git",
@@ -94,6 +94,7 @@
"@radix-ui/react-slot": "^1.0.0",
"@radix-ui/react-tooltip": "^1.0.0",
"@tanstack/react-table": "^8.0.0",
"date-fns": "^4.0.0",
"formik": "^2.0.0",
"next": ">=14.0.0",
"react": "^18.0.0 || ^19.0.0",
+13 -7
View File
@@ -14,12 +14,15 @@ The barrel file at `index.ts` re-exports each component and its prop types. Each
## Components
| Component | Description | Docs |
|-----------|-------------|------|
| [Button](./buttons/button/) | Label and/or icon-only stateless button | [README](./buttons/button/README.md) |
| [SelectButton](./buttons/select-button/) | Stateful toggle button with optional foldable content | [README](./buttons/select-button/README.md) |
| [OpenButton](./buttons/open-button/) | Trigger button with rotating chevron for popovers | [README](./buttons/open-button/README.md) |
| [Tag](./tag/) | Small colored label for status/category metadata | [README](./tag/README.md) |
| Component | Description | Docs |
| ---------------------------------------------- | ------------------------------------------------------------ | ---------------------------------------------- |
| [Button](./buttons/button/) | Label and/or icon-only stateless button | [README](./buttons/button/README.md) |
| [SelectButton](./buttons/select-button/) | Stateful toggle button with optional foldable content | [README](./buttons/select-button/README.md) |
| [OpenButton](./buttons/open-button/) | Trigger button with rotating chevron for popovers | [README](./buttons/open-button/README.md) |
| [Tag](./tag/) | Small colored label for status/category metadata | [README](./tag/README.md) |
| [DateRangePicker](./inputs/date-range-picker/) | Preset date-range strip with a custom-range calendar popover | [README](./inputs/date-range-picker/README.md) |
| [InputFile](./inputs/input-file/) | Text field that doubles as a file picker | [README](./inputs/input-file/README.md) |
| [ListFieldInput](./inputs/list-field-input/) | Type-and-Enter list builder with removable chips below | [README](./inputs/list-field-input/README.md) |
## Adding new components
@@ -30,5 +33,8 @@ The barrel file at `index.ts` re-exports each component and its prop types. Each
5. Add a `README.md` inside the component directory with architecture, props, and usage examples
6. In `components/index.ts`, re-export the component:
```ts
export { TextInput, type TextInputProps } from "@opal/components/inputs/text-input/components";
export {
TextInput,
type TextInputProps,
} from "@opal/components/inputs/text-input/components";
```
+21
View File
@@ -54,6 +54,27 @@ export {
type TextButtonProps,
} from "@opal/components/buttons/text-button/components";
/* DateRangePicker */
export {
DateRangePicker,
rangeForInclusiveDays,
THIRTY_DAYS,
type DateRange,
type DateRangePickerValue,
} from "@opal/components/inputs/date-range-picker/components";
/* InputFile */
export {
default as InputFile,
type InputFileProps,
} from "@opal/components/inputs/input-file/components";
/* ListFieldInput */
export {
ListFieldInput,
type ListFieldInputProps,
} from "@opal/components/inputs/list-field-input/components";
/* Text */
export {
Text,
@@ -3,7 +3,7 @@ import type { Meta, StoryObj } from "@storybook/react-vite";
import {
DateRangePicker,
type DateRange,
} from "@/refresh-components/DateRangePicker";
} from "@opal/components/inputs/date-range-picker/components";
const meta: Meta<typeof DateRangePicker> = {
title: "components/DateRangePicker",
@@ -1,6 +1,6 @@
import { render, screen } from "@tests/setup/test-utils";
import userEvent from "@testing-library/user-event";
import { DateRangePicker } from "@/refresh-components/DateRangePicker";
import { DateRangePicker } from "@opal/components";
describe("DateRangePicker", () => {
beforeEach(() => {
@@ -0,0 +1,18 @@
# DateRangePicker
**Import:** `import { DateRangePicker, rangeForInclusiveDays, type DateRange } from "@opal/components";`
A preset-strip date-range control: 1D / 7D / 1M / 3M buttons plus a "Custom" trigger that opens
the Opal `Calendar` in a popover for an arbitrary range. The active custom range renders as its
formatted span (e.g. "Mar 3 – Apr 1"). Built on `SelectButton`, `Popover`, and `Calendar`.
## Props
| Prop | Type | Default | Description |
| --------------- | ---------------------------- | ------- | ------------------------------------------- |
| `value` | `DateRange` | — | Controlled range (or unset) |
| `onValueChange` | `(value: DateRange) => void` | — | Fires on preset pick or custom-range commit |
| `size` | `"md" \| "sm"` | `"md"` | Button size |
All labels — preset names, the group and custom-range aria labels — come from `OpalStrings`
(`dateRange*` keys), bridged from the `opal.dateRange` catalog namespace.
@@ -1,8 +1,10 @@
import { memo, useState } from "react";
import { useTranslations } from "next-intl";
import { endOfDay, format, isSameDay, startOfDay, subDays } from "date-fns";
import { Calendar, Popover, SelectButton } from "@opal/components";
import { Calendar } from "@opal/components/calendar/components";
import { Popover } from "@opal/components/popover/components";
import { SelectButton } from "@opal/components/buttons/select-button/components";
import { SvgCalendar } from "@opal/icons";
import { useOpalStrings, type OpalStrings } from "@opal/strings";
export const THIRTY_DAYS = "1M";
@@ -66,25 +68,18 @@ function rangesMatch(left: DateRange, right: DateRange): boolean {
type SelectorSize = "md" | "sm";
type DateRangeTranslator = ReturnType<
typeof useTranslations<"common.dateRange">
>;
// Display labels are looked up per preset so the stable `label` ids used for
// range matching stay untranslated.
function presetDisplayLabel(
t: DateRangeTranslator,
preset: DatePreset
): string {
function presetDisplayLabel(strings: OpalStrings, preset: DatePreset): string {
switch (preset.inclusiveDays) {
case 1:
return t("preset.oneDay");
return strings.dateRangeOneDay;
case 7:
return t("preset.sevenDays");
return strings.dateRangeSevenDays;
case 30:
return t("preset.oneMonth");
return strings.dateRangeOneMonth;
case 90:
return t("preset.threeMonths");
return strings.dateRangeThreeMonths;
default:
return preset.label;
}
@@ -99,7 +94,7 @@ export const DateRangePicker = memo(function DateRangePicker({
onValueChange: (value: DateRange) => void;
size?: SelectorSize;
}) {
const t = useTranslations("common.dateRange");
const strings = useOpalStrings();
const buttonSize = size === "sm" ? "sm" : "md";
const [isOpen, setIsOpen] = useState(false);
const [draftRange, setDraftRange] = useState<DraftDateRange>(value);
@@ -114,7 +109,7 @@ export const DateRangePicker = memo(function DateRangePicker({
const customLabel =
customActive && value
? `${format(value.from, value.from.getFullYear() === value.to.getFullYear() ? "MMM d" : "MMM d, y")} – ${format(value.to, value.from.getFullYear() === value.to.getFullYear() ? "MMM d" : "MMM d, y")}`
: t("custom.label");
: strings.dateRangeCustom;
function selectPreset(preset: DatePreset) {
const range = rangeForPreset(preset);
@@ -129,7 +124,7 @@ export const DateRangePicker = memo(function DateRangePicker({
<div
className="inline-flex max-w-full shrink-0 items-center overflow-x-auto rounded-12 border border-border-02 bg-background-tint-03 p-0.5"
role="group"
aria-label={t("group.ariaLabel")}
aria-label={strings.dateRange}
data-testid="admin-date-range-selector"
>
{PRESETS.map((preset) => {
@@ -143,7 +138,7 @@ export const DateRangePicker = memo(function DateRangePicker({
aria-pressed={active}
onClick={() => selectPreset(preset)}
>
{presetDisplayLabel(t, preset)}
{presetDisplayLabel(strings, preset)}
</SelectButton>
);
})}
@@ -164,11 +159,11 @@ export const DateRangePicker = memo(function DateRangePicker({
rightIcon={hasCustomRange ? undefined : SvgCalendar}
aria-label={
value
? t("customRange.ariaLabel", {
from: format(value.from, "MMM d, y"),
to: format(value.to, "MMM d, y"),
})
: t("chooseCustom.ariaLabel")
? strings.dateRangeCustomRange(
format(value.from, "MMM d, y"),
format(value.to, "MMM d, y")
)
: strings.dateRangeChooseCustom
}
aria-pressed={customActive}
aria-haspopup="dialog"
@@ -1,10 +1,10 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
import React from "react";
import InputFile from "./InputFile";
import InputFile from "@opal/components/inputs/input-file/components";
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
const meta: Meta<typeof InputFile> = {
title: "refresh-components/inputs/InputFile",
title: "opal/components/InputFile",
component: InputFile,
tags: ["autodocs"],
decorators: [
@@ -0,0 +1,24 @@
# InputFile
**Import:** `import { InputFile, type InputFileProps } from "@opal/components";`
A text field that doubles as a file picker: type a value directly, or attach a file via the
paperclip action and the field displays the file's name and carries its text content. Clearing
returns to typed mode. Built on `InputTypeIn`; the attach/clear actions are `Button`s in the
right slot.
## Props
Extends `InputTypeInProps` minus the props the component owns itself —
`type`, `rightChildren`, `value`, `onChange`, `readOnly`, `clearButton` —
plus:
| Prop | Type | Description |
| -------------------- | ------------------------------- | ------------------------------------------------------ |
| `setValue` | `(value: string) => void` | Receives the typed text or the selected file's content |
| `onValueSet` | callback | Fires after a value lands |
| `accept` | `string` | File-picker accept filter |
| `maxSizeKb` | `number` | Reject files above this size |
| `onFileSizeExceeded` | `({ file, maxSizeKb }) => void` | Called when a file is rejected for size |
The attach/clear aria labels come from `OpalStrings` (`attachFile` / `clearFile`).
@@ -1,11 +1,22 @@
"use client";
import React, { useRef, useState } from "react";
import { useTranslations } from "next-intl";
import { InputTypeIn, type InputTypeInProps } from "@opal/components";
import { Button } from "@opal/components";
import { noProp } from "@/lib/utils";
import InputTypeIn, {
type InputTypeInProps,
} from "@opal/components/inputs/input-type-in/components";
import { Button } from "@opal/components/buttons/button/components";
import { SvgPaperclip, SvgX } from "@opal/icons";
import { useOpalStrings } from "@opal/strings";
// Stops the click reaching the input chrome, which would re-open the picker.
function noProp(
f?: (event: React.MouseEvent) => void
): React.MouseEventHandler {
return (event) => {
event.stopPropagation();
f?.(event);
};
}
export interface InputFileProps extends Omit<
InputTypeInProps,
@@ -43,7 +54,7 @@ export default function InputFile({
placeholder,
...rest
}: InputFileProps) {
const t = useTranslations("common.inputFile");
const strings = useOpalStrings();
const [displayValue, setDisplayValue] = useState<string>("");
const [selectedFileName, setSelectedFileName] = useState<string | null>(null);
const [isFileMode, setIsFileMode] = useState<boolean>(false);
@@ -131,7 +142,7 @@ export default function InputFile({
type="button"
prominence="tertiary"
size="sm"
aria-label={t("clearButton.ariaLabel")}
aria-label={strings.clearFile}
/>
) : (
<Button
@@ -141,7 +152,7 @@ export default function InputFile({
type="button"
prominence="tertiary"
size="sm"
aria-label={t("attachButton.ariaLabel")}
aria-label={strings.attachFile}
/>
);
@@ -1,10 +1,10 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
import React from "react";
import { ListFieldInput } from "./ListFieldInput";
import { ListFieldInput } from "@opal/components";
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
const meta: Meta<typeof ListFieldInput> = {
title: "refresh-components/inputs/ListFieldInput",
title: "opal/components/ListFieldInput",
component: ListFieldInput,
tags: ["autodocs"],
decorators: [
@@ -0,0 +1,18 @@
# ListFieldInput
**Import:** `import { ListFieldInput, type ListFieldInputProps } from "@opal/components";`
A list-of-strings input: type a value, press Enter, and it lands as a removable `Tag` chip below
the field. Duplicates are ignored; IME composition is respected. Unlike `InputTags`, the chips
render _under_ the input rather than inline within it — use this when the list is the content and
the field is just the entry point (e.g. a list of domains or scopes in a form).
## Props
| Prop | Type | Default | Description |
| ------------- | ---------------------------- | ------- | ------------------------------- |
| `values` | `string[]` | — | The list to display |
| `onChange` | `(values: string[]) => void` | — | Fires with the updated list |
| `placeholder` | `string` | `""` | Input placeholder |
| `disabled` | `boolean` | `false` | Disables input and chip removal |
| `error` | `boolean` | `false` | Error chrome on the input |
@@ -1,6 +1,10 @@
"use client";
import { useState, KeyboardEvent } from "react";
import { InputTypeIn, Tag } from "@opal/components";
interface ListFieldInputProps {
import InputTypeIn from "@opal/components/inputs/input-type-in/components";
import { Tag } from "@opal/components/tag/components";
export interface ListFieldInputProps {
values: string[];
onChange: (values: string[]) => void;
placeholder?: string;
@@ -26,7 +30,7 @@ export function ListFieldInput({
}: ListFieldInputProps) {
const [inputValue, setInputValue] = useState("");
const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
function handleKeyDown(e: KeyboardEvent<HTMLInputElement>) {
if (e.key === "Enter" && !e.nativeEvent.isComposing && inputValue.trim()) {
e.preventDefault();
const trimmedValue = inputValue.trim();
@@ -38,11 +42,11 @@ export function ListFieldInput({
setInputValue("");
}
};
}
const removeValue = (indexToRemove: number) => {
function removeValue(indexToRemove: number) {
onChange(values.filter((_, index) => index !== indexToRemove));
};
}
return (
<div className="flex flex-col w-full space-y-2 mb-4">
+20
View File
@@ -13,8 +13,18 @@ export type OpalStrings = {
copied: string;
copyCode: string;
clear: string;
attachFile: string;
clearFile: string;
clearFilter: string;
date: string;
dateRange: string;
dateRangeOneDay: string;
dateRangeSevenDays: string;
dateRangeOneMonth: string;
dateRangeThreeMonths: string;
dateRangeCustom: string;
dateRangeChooseCustom: string;
dateRangeCustomRange: (from: string, to: string) => string;
time: string;
edit: string;
search: string;
@@ -72,8 +82,18 @@ export const defaultOpalStrings: OpalStrings = {
copied: "Copied!",
copyCode: "Copy code",
clear: "Clear",
attachFile: "Attach file",
clearFile: "Clear file",
clearFilter: "Clear filter",
date: "Date",
dateRange: "Date range",
dateRangeOneDay: "1D",
dateRangeSevenDays: "7D",
dateRangeOneMonth: "1M",
dateRangeThreeMonths: "3M",
dateRangeCustom: "Custom",
dateRangeChooseCustom: "Choose a custom range",
dateRangeCustomRange: (from, to) => `Custom range: ${from} to ${to}`,
time: "Time",
edit: "Edit",
search: "Search...",
@@ -4,7 +4,7 @@ import { useState } from "react";
import { useLocale, useTranslations } from "next-intl";
import { Button, Card } from "@opal/components";
import Text from "@/refresh-components/texts/Text";
import InputFile from "@/refresh-components/inputs/InputFile";
import { InputFile } from "@opal/components";
import { Section } from "@/layouts/general-layouts";
import { InputVertical } from "@opal/layouts";
import { SvgXCircle, SvgCheckCircle, SvgXOctagon } from "@opal/icons";
@@ -9,7 +9,7 @@ import { Form, Formik } from "formik";
import { User } from "@/lib/types";
import { Button, Text } from "@opal/components";
import { Section, toast } from "@opal/layouts";
import InputFile from "@/refresh-components/inputs/InputFile";
import { InputFile } from "@opal/components";
import InputTypeInField from "@/refresh-components/form/InputTypeInField";
import {
parseOauthAppCredentialJson,
@@ -1,6 +1,6 @@
import { Button, Text } from "@opal/components";
import { Section, toast } from "@opal/layouts";
import InputFile from "@/refresh-components/inputs/InputFile";
import { InputFile } from "@opal/components";
import InputTypeInField from "@/refresh-components/form/InputTypeInField";
import React, { useState, useEffect } from "react";
import { useTranslations } from "next-intl";
@@ -30,7 +30,7 @@ import {
DateRangePicker,
rangeForInclusiveDays,
type DateRange,
} from "@/refresh-components/DateRangePicker";
} from "@opal/components";
import { formatCalendarDay } from "@/lib/dateUtils";
import {
formatCurrencyFromCents as formatDollars,
+1 -1
View File
@@ -1,7 +1,7 @@
import { renderHook } from "@testing-library/react";
import useSWR from "swr";
import { useUserUsage } from "@/app/app/settings/usage/lib";
import { rangeForInclusiveDays } from "@/refresh-components/DateRangePicker";
import { rangeForInclusiveDays } from "@opal/components";
jest.mock("swr", () => jest.fn());
@@ -14,7 +14,7 @@ import {
Text,
Tooltip,
} from "@opal/components";
import { ListFieldInput } from "@/refresh-components/inputs/ListFieldInput";
import { ListFieldInput } from "@opal/components";
import InputKeyValue, {
KeyValue,
} from "@/refresh-components/inputs/InputKeyValue";
@@ -4,7 +4,7 @@ import { toast } from "@opal/layouts";
import { Button } from "@opal/components";
import { useRef, useState } from "react";
import { useTranslations } from "next-intl";
import type { DateRange } from "@/refresh-components/DateRangePicker";
import type { DateRange } from "@opal/components";
import { withRequestId, withDateRange } from "./utils";
import {
CHECK_QUERY_HISTORY_EXPORT_STATUS_URL,
@@ -17,7 +17,7 @@ import { Section } from "@/layouts/general-layouts";
import { timestampToReadableDate } from "@/lib/dateUtils";
import { Dispatch, SetStateAction, useState } from "react";
import { Feedback, TaskStatus } from "@/lib/types";
import { DateRange } from "@/refresh-components/DateRangePicker";
import { DateRange } from "@opal/components";
import { PageSelector } from "@/components/PageSelector";
import Link from "next/link";
import type { Route } from "next";
@@ -11,7 +11,7 @@ import {
DateRange,
DateRangePicker,
rangeForInclusiveDays,
} from "@/refresh-components/DateRangePicker";
} from "@opal/components";
import { useCallback, useState } from "react";
const route = ADMIN_ROUTES.QUERY_HISTORY;
@@ -1,4 +1,4 @@
import type { DateRange } from "@/refresh-components/DateRangePicker";
import type { DateRange } from "@opal/components";
import { START_QUERY_HISTORY_EXPORT_URL } from "./constants";
export const withRequestId = (url: string, requestId: string): string =>
@@ -2,7 +2,7 @@
import { useAdminRouteTitle } from "@/lib/adminNavLabels";
import { useTranslations } from "next-intl";
import { DateRangePicker } from "@/refresh-components/DateRangePicker";
import { DateRangePicker } from "@opal/components";
import { useTimeRange } from "@/lib/usage/hooks";
import PerUserUsagePanel from "@/views/admin/PerUserUsagePanel";
import { ADMIN_ROUTES } from "@/lib/admin-routes";
@@ -2,12 +2,8 @@
import { useEffect, useState, useMemo } from "react";
import { useLocale, useTranslations } from "next-intl";
import { Card, Text } from "@opal/components";
import { Card, DateRange, DateRangePicker, Text } from "@opal/components";
import { Section } from "@opal/layouts";
import {
DateRangePicker,
DateRange,
} from "@/refresh-components/DateRangePicker";
import { useAgents } from "@/lib/agents/hooks";
import AgentAvatar from "@/refresh-components/avatars/AgentAvatar";
import {
@@ -29,7 +29,7 @@ import { DropdownMenuItemWithTooltip } from "@/components/ui/dropdown-menu-with-
import { toast } from "@opal/layouts";
import { Badge } from "@/components/ui/badge";
import { ListFieldInput } from "@/refresh-components/inputs/ListFieldInput";
import { ListFieldInput } from "@opal/components";
import { SvgSettings, SvgSimpleLoader } from "@opal/icons";
export interface FederatedConnectorFormProps {
@@ -1,4 +1,4 @@
import { DateRangePickerValue } from "@/refresh-components/DateRangePicker";
import { DateRangePickerValue } from "@opal/components";
import { useTranslations } from "next-intl";
import { FiCalendar, FiChevronDown, FiXCircle } from "react-icons/fi";
import { CustomDropdown } from "../Dropdown";
@@ -3,7 +3,7 @@ import { DocumentSetSummary, Tag, ValidSources } from "@/lib/types";
import { SourceMetadata } from "@/lib/search/interfaces";
import { FiBook, FiBookmark, FiMap, FiX } from "react-icons/fi";
import { SearchDateRangeSelector } from "@/components/dateRangeSelectors/SearchDateRangeSelector";
import { DateRangePickerValue } from "@/refresh-components/DateRangePicker";
import { DateRangePickerValue } from "@opal/components";
import { listSourceMetadata } from "@/lib/sources";
import { SourceIcon } from "@/components/SourceIcon";
import { FilterDropdown } from "@/components/search/filtering/FilterDropdown";
+11
View File
@@ -26,8 +26,19 @@ export default function OpalStringsBridge({
copied: t("common.copied"),
copyCode: t("common.copyCode"),
clear: t("common.clear"),
attachFile: t("inputFile.attachFile"),
clearFile: t("inputFile.clearFile"),
clearFilter: t("common.clearFilter"),
date: t("common.date"),
dateRange: t("dateRange.label"),
dateRangeOneDay: t("dateRange.oneDay"),
dateRangeSevenDays: t("dateRange.sevenDays"),
dateRangeOneMonth: t("dateRange.oneMonth"),
dateRangeThreeMonths: t("dateRange.threeMonths"),
dateRangeCustom: t("dateRange.custom"),
dateRangeChooseCustom: t("dateRange.chooseCustom"),
dateRangeCustomRange: (from, to) =>
t("dateRange.customRange", { from, to }),
time: t("common.time"),
edit: t("common.edit"),
search: t("common.search"),
+14 -26
View File
@@ -10862,29 +10862,11 @@
"anyTime": {
"text": "أي وقت..."
},
"chooseCustom": {
"ariaLabel": "اختيار نطاق مخصص"
},
"clearButton": {
"ariaLabel": "مسح"
},
"custom": {
"label": "مخصص"
},
"customRange": {
"ariaLabel": "نطاق مخصص: من {from} إلى {to}"
},
"date": {
"label": "التاريخ"
},
"group": {
"ariaLabel": "النطاق الزمني"
},
"preset": {
"oneDay": "يوم",
"oneMonth": "شهر",
"sevenDays": "7 أيام",
"threeMonths": "3 أشهر"
}
},
"deleteButton": {
@@ -11183,14 +11165,6 @@
"tooltip": "إزالة"
}
},
"inputFile": {
"attachButton": {
"ariaLabel": "إرفاق ملف"
},
"clearButton": {
"ariaLabel": "مسح الملف"
}
},
"inputImage": {
"dropRejected": {
"fallback": "تم رفض الملف"
@@ -12801,6 +12775,16 @@
"showFullMessage": "عرض الرسالة كاملة",
"time": "الوقت"
},
"dateRange": {
"chooseCustom": "اختيار نطاق مخصص",
"custom": "مخصص",
"customRange": "نطاق مخصص: من {from} إلى {to}",
"label": "النطاق الزمني",
"oneDay": "يوم",
"oneMonth": "شهر",
"sevenDays": "7 أيام",
"threeMonths": "3 أشهر"
},
"input": {
"day": "اليوم",
"hidePassword": "إخفاء كلمة المرور",
@@ -12812,6 +12796,10 @@
"valueCannotBeRevealed": "لا يمكن إظهار القيمة",
"year": "السنة"
},
"inputFile": {
"attachFile": "إرفاق ملف",
"clearFile": "مسح الملف"
},
"pagination": {
"goToPage": "الانتقال إلى صفحة",
"nextPage": "الصفحة التالية",
+14 -26
View File
@@ -10862,29 +10862,11 @@
"anyTime": {
"text": "Beliebiger Zeitraum..."
},
"chooseCustom": {
"ariaLabel": "Benutzerdefinierten Zeitraum wählen"
},
"clearButton": {
"ariaLabel": "Zurücksetzen"
},
"custom": {
"label": "Benutzerdefiniert"
},
"customRange": {
"ariaLabel": "Benutzerdefinierter Zeitraum: {from} bis {to}"
},
"date": {
"label": "Datum"
},
"group": {
"ariaLabel": "Datumsbereich"
},
"preset": {
"oneDay": "1T",
"oneMonth": "1M",
"sevenDays": "7T",
"threeMonths": "3M"
}
},
"deleteButton": {
@@ -11183,14 +11165,6 @@
"tooltip": "Entfernen"
}
},
"inputFile": {
"attachButton": {
"ariaLabel": "Datei anhängen"
},
"clearButton": {
"ariaLabel": "Datei entfernen"
}
},
"inputImage": {
"dropRejected": {
"fallback": "Datei abgelehnt"
@@ -12801,6 +12775,16 @@
"showFullMessage": "Vollständige Nachricht anzeigen",
"time": "Uhrzeit"
},
"dateRange": {
"chooseCustom": "Benutzerdefinierten Zeitraum wählen",
"custom": "Benutzerdefiniert",
"customRange": "Benutzerdefinierter Zeitraum: {from} bis {to}",
"label": "Datumsbereich",
"oneDay": "1T",
"oneMonth": "1M",
"sevenDays": "7T",
"threeMonths": "3M"
},
"input": {
"day": "Tag",
"hidePassword": "Passwort verbergen",
@@ -12812,6 +12796,10 @@
"valueCannotBeRevealed": "Wert kann nicht angezeigt werden",
"year": "Jahr"
},
"inputFile": {
"attachFile": "Datei anhängen",
"clearFile": "Datei entfernen"
},
"pagination": {
"goToPage": "Zu Seite springen",
"nextPage": "Nächste Seite",
+14 -26
View File
@@ -10862,29 +10862,11 @@
"anyTime": {
"text": "Any time..."
},
"chooseCustom": {
"ariaLabel": "Choose a custom range"
},
"clearButton": {
"ariaLabel": "Clear"
},
"custom": {
"label": "Custom"
},
"customRange": {
"ariaLabel": "Custom range: {from} to {to}"
},
"date": {
"label": "Date"
},
"group": {
"ariaLabel": "Date range"
},
"preset": {
"oneDay": "1D",
"oneMonth": "1M",
"sevenDays": "7D",
"threeMonths": "3M"
}
},
"deleteButton": {
@@ -11183,14 +11165,6 @@
"tooltip": "Remove"
}
},
"inputFile": {
"attachButton": {
"ariaLabel": "Attach file"
},
"clearButton": {
"ariaLabel": "Clear file"
}
},
"inputImage": {
"dropRejected": {
"fallback": "File rejected"
@@ -12801,6 +12775,16 @@
"showFullMessage": "Show the full message",
"time": "Time"
},
"dateRange": {
"chooseCustom": "Choose a custom range",
"custom": "Custom",
"customRange": "Custom range: {from} to {to}",
"label": "Date range",
"oneDay": "1D",
"oneMonth": "1M",
"sevenDays": "7D",
"threeMonths": "3M"
},
"input": {
"day": "Day",
"hidePassword": "Hide password",
@@ -12812,6 +12796,10 @@
"valueCannotBeRevealed": "Value cannot be revealed",
"year": "Year"
},
"inputFile": {
"attachFile": "Attach file",
"clearFile": "Clear file"
},
"pagination": {
"goToPage": "Go to page",
"nextPage": "Next page",
+14 -26
View File
@@ -10862,29 +10862,11 @@
"anyTime": {
"text": "Cualquier fecha..."
},
"chooseCustom": {
"ariaLabel": "Elegir un rango personalizado"
},
"clearButton": {
"ariaLabel": "Borrar"
},
"custom": {
"label": "Personalizado"
},
"customRange": {
"ariaLabel": "Rango personalizado: {from} a {to}"
},
"date": {
"label": "Fecha"
},
"group": {
"ariaLabel": "Rango de fechas"
},
"preset": {
"oneDay": "1D",
"oneMonth": "1M",
"sevenDays": "7D",
"threeMonths": "3M"
}
},
"deleteButton": {
@@ -11183,14 +11165,6 @@
"tooltip": "Eliminar"
}
},
"inputFile": {
"attachButton": {
"ariaLabel": "Adjuntar archivo"
},
"clearButton": {
"ariaLabel": "Quitar archivo"
}
},
"inputImage": {
"dropRejected": {
"fallback": "Archivo rechazado"
@@ -12801,6 +12775,16 @@
"showFullMessage": "Mostrar el mensaje completo",
"time": "Hora"
},
"dateRange": {
"chooseCustom": "Elegir un rango personalizado",
"custom": "Personalizado",
"customRange": "Rango personalizado: {from} a {to}",
"label": "Rango de fechas",
"oneDay": "1D",
"oneMonth": "1M",
"sevenDays": "7D",
"threeMonths": "3M"
},
"input": {
"day": "Día",
"hidePassword": "Ocultar contraseña",
@@ -12812,6 +12796,10 @@
"valueCannotBeRevealed": "El valor no se puede mostrar",
"year": "Año"
},
"inputFile": {
"attachFile": "Adjuntar archivo",
"clearFile": "Quitar archivo"
},
"pagination": {
"goToPage": "Ir a la página",
"nextPage": "Página siguiente",
+14 -26
View File
@@ -10862,29 +10862,11 @@
"anyTime": {
"text": "N'importe quand..."
},
"chooseCustom": {
"ariaLabel": "Choisir une plage personnalisée"
},
"clearButton": {
"ariaLabel": "Effacer"
},
"custom": {
"label": "Personnalisé"
},
"customRange": {
"ariaLabel": "Plage personnalisée : {from} à {to}"
},
"date": {
"label": "Date"
},
"group": {
"ariaLabel": "Plage de dates"
},
"preset": {
"oneDay": "1J",
"oneMonth": "1M",
"sevenDays": "7J",
"threeMonths": "3M"
}
},
"deleteButton": {
@@ -11183,14 +11165,6 @@
"tooltip": "Supprimer"
}
},
"inputFile": {
"attachButton": {
"ariaLabel": "Joindre un fichier"
},
"clearButton": {
"ariaLabel": "Effacer le fichier"
}
},
"inputImage": {
"dropRejected": {
"fallback": "Fichier refusé"
@@ -12801,6 +12775,16 @@
"showFullMessage": "Afficher le message complet",
"time": "Heure"
},
"dateRange": {
"chooseCustom": "Choisir une plage personnalisée",
"custom": "Personnalisé",
"customRange": "Plage personnalisée : {from} à {to}",
"label": "Plage de dates",
"oneDay": "1J",
"oneMonth": "1M",
"sevenDays": "7J",
"threeMonths": "3M"
},
"input": {
"day": "Jour",
"hidePassword": "Masquer le mot de passe",
@@ -12812,6 +12796,10 @@
"valueCannotBeRevealed": "La valeur ne peut pas être affichée",
"year": "Année"
},
"inputFile": {
"attachFile": "Joindre un fichier",
"clearFile": "Effacer le fichier"
},
"pagination": {
"goToPage": "Aller à la page",
"nextPage": "Page suivante",
+14 -26
View File
@@ -10862,29 +10862,11 @@
"anyTime": {
"text": "期間指定なし..."
},
"chooseCustom": {
"ariaLabel": "カスタム範囲を選択"
},
"clearButton": {
"ariaLabel": "クリア"
},
"custom": {
"label": "カスタム"
},
"customRange": {
"ariaLabel": "カスタム範囲: {from}〜{to}"
},
"date": {
"label": "日付"
},
"group": {
"ariaLabel": "日付範囲"
},
"preset": {
"oneDay": "1日",
"oneMonth": "1ヶ月",
"sevenDays": "7日",
"threeMonths": "3ヶ月"
}
},
"deleteButton": {
@@ -11183,14 +11165,6 @@
"tooltip": "削除"
}
},
"inputFile": {
"attachButton": {
"ariaLabel": "ファイルを添付"
},
"clearButton": {
"ariaLabel": "ファイルをクリア"
}
},
"inputImage": {
"dropRejected": {
"fallback": "ファイルが拒否されました"
@@ -12801,6 +12775,16 @@
"showFullMessage": "メッセージ全体を表示",
"time": "時刻"
},
"dateRange": {
"chooseCustom": "カスタム範囲を選択",
"custom": "カスタム",
"customRange": "カスタム範囲: {from}〜{to}",
"label": "日付範囲",
"oneDay": "1日",
"oneMonth": "1ヶ月",
"sevenDays": "7日",
"threeMonths": "3ヶ月"
},
"input": {
"day": "日",
"hidePassword": "パスワードを非表示",
@@ -12812,6 +12796,10 @@
"valueCannotBeRevealed": "値を表示できません",
"year": "年"
},
"inputFile": {
"attachFile": "ファイルを添付",
"clearFile": "ファイルをクリア"
},
"pagination": {
"goToPage": "ページへ移動",
"nextPage": "次のページ",
+14 -26
View File
@@ -10862,29 +10862,11 @@
"anyTime": {
"text": "모든 기간..."
},
"chooseCustom": {
"ariaLabel": "사용자 지정 범위 선택"
},
"clearButton": {
"ariaLabel": "지우기"
},
"custom": {
"label": "사용자 지정"
},
"customRange": {
"ariaLabel": "사용자 지정 범위: {from}부터 {to}까지"
},
"date": {
"label": "날짜"
},
"group": {
"ariaLabel": "날짜 범위"
},
"preset": {
"oneDay": "1일",
"oneMonth": "1개월",
"sevenDays": "7일",
"threeMonths": "3개월"
}
},
"deleteButton": {
@@ -11183,14 +11165,6 @@
"tooltip": "제거"
}
},
"inputFile": {
"attachButton": {
"ariaLabel": "파일 첨부"
},
"clearButton": {
"ariaLabel": "파일 지우기"
}
},
"inputImage": {
"dropRejected": {
"fallback": "파일이 거부되었습니다"
@@ -12801,6 +12775,16 @@
"showFullMessage": "전체 메시지 보기",
"time": "시간"
},
"dateRange": {
"chooseCustom": "사용자 지정 범위 선택",
"custom": "사용자 지정",
"customRange": "사용자 지정 범위: {from}부터 {to}까지",
"label": "날짜 범위",
"oneDay": "1일",
"oneMonth": "1개월",
"sevenDays": "7일",
"threeMonths": "3개월"
},
"input": {
"day": "일",
"hidePassword": "비밀번호 숨기기",
@@ -12812,6 +12796,10 @@
"valueCannotBeRevealed": "값을 표시할 수 없습니다",
"year": "년"
},
"inputFile": {
"attachFile": "파일 첨부",
"clearFile": "파일 지우기"
},
"pagination": {
"goToPage": "페이지로 이동",
"nextPage": "다음 페이지",
+14 -26
View File
@@ -10862,29 +10862,11 @@
"anyTime": {
"text": "Qualquer data..."
},
"chooseCustom": {
"ariaLabel": "Escolher um intervalo personalizado"
},
"clearButton": {
"ariaLabel": "Limpar"
},
"custom": {
"label": "Personalizado"
},
"customRange": {
"ariaLabel": "Intervalo personalizado: {from} a {to}"
},
"date": {
"label": "Data"
},
"group": {
"ariaLabel": "Intervalo de datas"
},
"preset": {
"oneDay": "1D",
"oneMonth": "1M",
"sevenDays": "7D",
"threeMonths": "3M"
}
},
"deleteButton": {
@@ -11183,14 +11165,6 @@
"tooltip": "Remover"
}
},
"inputFile": {
"attachButton": {
"ariaLabel": "Anexar arquivo"
},
"clearButton": {
"ariaLabel": "Limpar arquivo"
}
},
"inputImage": {
"dropRejected": {
"fallback": "Arquivo rejeitado"
@@ -12801,6 +12775,16 @@
"showFullMessage": "Mostrar a mensagem completa",
"time": "Hora"
},
"dateRange": {
"chooseCustom": "Escolher um intervalo personalizado",
"custom": "Personalizado",
"customRange": "Intervalo personalizado: {from} a {to}",
"label": "Intervalo de datas",
"oneDay": "1D",
"oneMonth": "1M",
"sevenDays": "7D",
"threeMonths": "3M"
},
"input": {
"day": "Dia",
"hidePassword": "Ocultar senha",
@@ -12812,6 +12796,10 @@
"valueCannotBeRevealed": "O valor não pode ser exibido",
"year": "Ano"
},
"inputFile": {
"attachFile": "Anexar arquivo",
"clearFile": "Limpar arquivo"
},
"pagination": {
"goToPage": "Ir para a página",
"nextPage": "Próxima página",
+14 -26
View File
@@ -10862,29 +10862,11 @@
"anyTime": {
"text": "任何时间..."
},
"chooseCustom": {
"ariaLabel": "选择自定义范围"
},
"clearButton": {
"ariaLabel": "清除"
},
"custom": {
"label": "自定义"
},
"customRange": {
"ariaLabel": "自定义范围:{from}至{to}"
},
"date": {
"label": "日期"
},
"group": {
"ariaLabel": "日期范围"
},
"preset": {
"oneDay": "1天",
"oneMonth": "1个月",
"sevenDays": "7天",
"threeMonths": "3个月"
}
},
"deleteButton": {
@@ -11183,14 +11165,6 @@
"tooltip": "移除"
}
},
"inputFile": {
"attachButton": {
"ariaLabel": "附加文件"
},
"clearButton": {
"ariaLabel": "清除文件"
}
},
"inputImage": {
"dropRejected": {
"fallback": "文件被拒绝"
@@ -12801,6 +12775,16 @@
"showFullMessage": "显示完整消息",
"time": "时间"
},
"dateRange": {
"chooseCustom": "选择自定义范围",
"custom": "自定义",
"customRange": "自定义范围:{from}至{to}",
"label": "日期范围",
"oneDay": "1天",
"oneMonth": "1个月",
"sevenDays": "7天",
"threeMonths": "3个月"
},
"input": {
"day": "日",
"hidePassword": "隐藏密码",
@@ -12812,6 +12796,10 @@
"valueCannotBeRevealed": "无法显示该值",
"year": "年"
},
"inputFile": {
"attachFile": "附加文件",
"clearFile": "清除文件"
},
"pagination": {
"goToPage": "跳转到页面",
"nextPage": "下一页",
+1 -1
View File
@@ -20,7 +20,7 @@ import {
useRef,
useState,
} from "react";
import { DateRangePickerValue } from "@/refresh-components/DateRangePicker";
import { DateRangePickerValue } from "@opal/components";
import { SourceMetadata } from "./search/interfaces";
import {
getProviderOverrideForAgent,
+1 -1
View File
@@ -1,4 +1,4 @@
import { DateRangePickerValue } from "@/refresh-components/DateRangePicker";
import { DateRangePickerValue } from "@opal/components";
import { Tag, ValidSources } from "../types";
import { Agent } from "@/lib/agents/types";
+1 -1
View File
@@ -6,7 +6,7 @@ import { errorHandlingFetcher } from "@/lib/fetcher";
import { SWR_KEYS } from "@/lib/swr-keys";
import type { Tag, ValidSources } from "@/lib/types";
import type { SourceMetadata } from "@/lib/search/interfaces";
import type { DateRangePickerValue } from "@/refresh-components/DateRangePicker";
import type { DateRangePickerValue } from "@opal/components";
import { getConfiguredSources } from "@/lib/sources";
import type { SearchFilters } from "@/lib/searchFilters/types";
+1 -1
View File
@@ -1,6 +1,6 @@
import type { Tag } from "@/lib/types";
import type { SourceMetadata } from "@/lib/search/interfaces";
import type { DateRangePickerValue } from "@/refresh-components/DateRangePicker";
import type { DateRangePickerValue } from "@opal/components";
/** What is selected, without the means to change it. */
export interface SearchFiltersSelection {
+1 -1
View File
@@ -1,6 +1,6 @@
import type { Tag } from "@/lib/types";
import type { SourceMetadata } from "@/lib/search/interfaces";
import type { DateRangePickerValue } from "@/refresh-components/DateRangePicker";
import type { DateRangePickerValue } from "@opal/components";
import type { SearchFiltersRequest } from "@/lib/searchFilters/types";
/** Freezes a live selection into the shape the backend receives. */
+1 -1
View File
@@ -19,7 +19,7 @@ import {
THIRTY_DAYS,
type DateRangePickerValue,
rangeForInclusiveDays,
} from "@/refresh-components/DateRangePicker";
} from "@opal/components";
export function useTimeRange() {
return useState<DateRangePickerValue>({
+1 -1
View File
@@ -7,7 +7,7 @@ import type { RichStr } from "@opal/types";
import AreaChart from "@/refresh-components/AreaChart";
import { formatCalendarDay } from "@/lib/dateUtils";
import { getDatesList } from "@/lib/usage/utils";
import { DateRange } from "@/refresh-components/DateRangePicker";
import { DateRange } from "@opal/components";
import { ChartSeries, ChartState } from "@/sections/usage/interfaces";
const CHART_BODY_HEIGHT = 20;
@@ -6,7 +6,7 @@ import * as Yup from "yup";
import { FormikField } from "@/refresh-components/form/FormikField";
import { FormField } from "@/refresh-components/form/FormField";
import { InputTypeIn } from "@opal/components";
import InputFile from "@/refresh-components/inputs/InputFile";
import { InputFile } from "@opal/components";
import InputSelect from "@/refresh-components/inputs/InputSelect";
import InlineExternalLink from "@/refresh-components/InlineExternalLink";
import { ImageGenFormWrapper } from "@/views/admin/ImageGenerationPage/forms/ImageGenFormWrapper";
+1 -1
View File
@@ -5,7 +5,7 @@ import { useLocale, useTranslations } from "next-intl";
import { Card, MessageCard, Text } from "@opal/components";
import { SvgX } from "@opal/icons";
import { PageLoader, Section } from "@opal/layouts";
import type { DateRange } from "@/refresh-components/DateRangePicker";
import type { DateRange } from "@opal/components";
import { formatCalendarDay } from "@/lib/dateUtils";
import { useUsageExport } from "@/lib/usage/userUsage";
import { formatCost, formatTokens } from "@/lib/utils";
@@ -10,7 +10,7 @@ import {
resolveChartState,
useLoggedChartError,
} from "@/sections/usage/AnalyticsChart";
import { DateRangePickerValue } from "@/refresh-components/DateRangePicker";
import { DateRangePickerValue } from "@opal/components";
import { formatTokenCount } from "@/lib/format";
interface TimeRangeProps {
@@ -17,7 +17,7 @@ import {
chartSeries,
resolveChartState,
} from "@/sections/usage/AnalyticsChart";
import { DateRangePickerValue } from "@/refresh-components/DateRangePicker";
import { DateRangePickerValue } from "@opal/components";
import { Agent } from "@/lib/agents/types";
interface PersonaPickerProps {
@@ -2,7 +2,7 @@
import { useAdminRouteTitle } from "@/lib/adminNavLabels";
import { useTranslations } from "next-intl";
import { DateRangePicker } from "@/refresh-components/DateRangePicker";
import { DateRangePicker } from "@opal/components";
import { useTimeRange } from "@/lib/usage/hooks";
import {
FeedbackChart,