diff --git a/apps/console/src/components/SnapshotBanner.tsx b/apps/console/src/components/SnapshotBanner.tsx new file mode 100644 index 000000000..e24c19c8c --- /dev/null +++ b/apps/console/src/components/SnapshotBanner.tsx @@ -0,0 +1,45 @@ +import { IconClock } from "@probo/ui"; +import { useTranslate } from "@probo/i18n"; +import { useLazyLoadQuery, graphql } from "react-relay"; +import type { SnapshotBannerQuery } from "./__generated__/SnapshotBannerQuery.graphql"; + +const snapshotQuery = graphql` + query SnapshotBannerQuery($snapshotId: ID!) { + node(id: $snapshotId) { + ... on Snapshot { + id + name + createdAt + } + } + } +`; + +type Props = { + snapshotId: string; +}; + +export function SnapshotBanner({ snapshotId }: Props) { + const { __, dateFormat } = useTranslate(); + + const data = useLazyLoadQuery(snapshotQuery, { snapshotId }); + const snapshot = data.node; + + if (!snapshot) { + return null; + } + + return ( +
+ +
+
+ {__("Snapshot")} {snapshot.name} +
+

+ {__("You are viewing a snapshot of data from")} {dateFormat(snapshot.createdAt, { year: "numeric", month: "short", day: "numeric" })} +

+
+
+ ); +} diff --git a/apps/console/src/components/__generated__/SnapshotBannerQuery.graphql.ts b/apps/console/src/components/__generated__/SnapshotBannerQuery.graphql.ts new file mode 100644 index 000000000..5cd8f56a6 --- /dev/null +++ b/apps/console/src/components/__generated__/SnapshotBannerQuery.graphql.ts @@ -0,0 +1,144 @@ +/** + * @generated SignedSource<> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type SnapshotBannerQuery$variables = { + snapshotId: string; +}; +export type SnapshotBannerQuery$data = { + readonly node: { + readonly createdAt?: any; + readonly id?: string; + readonly name?: string; + }; +}; +export type SnapshotBannerQuery = { + response: SnapshotBannerQuery$data; + variables: SnapshotBannerQuery$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "snapshotId" + } +], +v1 = [ + { + "kind": "Variable", + "name": "id", + "variableName": "snapshotId" + } +], +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v3 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null +}, +v4 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null +}; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "SnapshotBannerQuery", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "kind": "InlineFragment", + "selections": [ + (v2/*: any*/), + (v3/*: any*/), + (v4/*: any*/) + ], + "type": "Snapshot", + "abstractKey": null + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "SnapshotBannerQuery", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + (v2/*: any*/), + { + "kind": "InlineFragment", + "selections": [ + (v3/*: any*/), + (v4/*: any*/) + ], + "type": "Snapshot", + "abstractKey": null + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "8f21371ececf96444bb6b00e52783573", + "id": null, + "metadata": {}, + "name": "SnapshotBannerQuery", + "operationKind": "query", + "text": "query SnapshotBannerQuery(\n $snapshotId: ID!\n) {\n node(id: $snapshotId) {\n __typename\n ... on Snapshot {\n id\n name\n createdAt\n }\n id\n }\n}\n" + } +}; +})(); + +(node as any).hash = "1602d5b6c0ae4a3122998e4d3419af05"; + +export default node; diff --git a/apps/console/src/components/form/SnapshotTypeOptions.tsx b/apps/console/src/components/form/SnapshotTypeOptions.tsx new file mode 100644 index 000000000..98fc7531d --- /dev/null +++ b/apps/console/src/components/form/SnapshotTypeOptions.tsx @@ -0,0 +1,17 @@ +import { useTranslate } from "@probo/i18n"; +import { Option } from "@probo/ui"; +import { snapshotTypes, getSnapshotTypeLabel } from "@probo/helpers"; + +export function SnapshotTypeOptions() { + const { __ } = useTranslate(); + + return ( + <> + {snapshotTypes.map((type) => ( + + ))} + + ); +} diff --git a/apps/console/src/components/form/VendorsMultiSelectField.tsx b/apps/console/src/components/form/VendorsMultiSelectField.tsx index bf35f9def..993576887 100644 --- a/apps/console/src/components/form/VendorsMultiSelectField.tsx +++ b/apps/console/src/components/form/VendorsMultiSelectField.tsx @@ -1,23 +1,32 @@ import { Avatar, Field, Option, Select, Badge, Button, IconCrossLargeX } from "@probo/ui"; import { Suspense, useState, type ComponentProps } from "react"; import { useTranslate } from "@probo/i18n"; -import { type Control, Controller } from "react-hook-form"; +import { type Control, Controller, type FieldValues } from "react-hook-form"; import { useVendors } from "/hooks/graph/VendorGraph.ts"; import { faviconUrl } from "@probo/helpers"; +import type { Path } from "react-hook-form"; -type Props = { +type Vendor = { + id: string; + name: string; + websiteUrl: string | null | undefined; +}; + +type Props = { organizationId: string; - control: Control; + control: Control; name: string; label?: string; error?: string; + selectedVendors?: Vendor[]; } & ComponentProps; -export function VendorsMultiSelectField({ +export function VendorsMultiSelectField({ organizationId, control, + selectedVendors = [], ...props -}: Props) { +}: Props) { return ( ); } -function VendorsMultiSelectWithQuery( - props: Pick +function VendorsMultiSelectWithQuery( + props: Pick, "organizationId" | "control" | "name" | "disabled" | "selectedVendors"> ) { const { __ } = useTranslate(); - const { name, organizationId, control } = props; + const { name, organizationId, control, selectedVendors = [] } = props; const vendors = useVendors(organizationId); const [isOpen, setIsOpen] = useState(false); + const allVendors = [...vendors]; + if (props.disabled) { + selectedVendors.forEach(selectedVendor => { + if (!allVendors.find(v => v.id === selectedVendor.id)) { + allVendors.push(selectedVendor); + } + }); + } + return ( <> } render={({ field }) => { - const selectedVendorIds = Array.isArray(field.value) ? field.value : []; - const selectedVendors = vendors.filter(v => selectedVendorIds.includes(v.id)); - const availableVendors = vendors.filter(v => !selectedVendorIds.includes(v.id)); + const selectedVendorIds = (Array.isArray(field.value) ? field.value : []) as string[]; + + const selectedVendors = allVendors.filter(v => selectedVendorIds.includes(v.id)); + const availableVendors = allVendors.filter(v => !selectedVendorIds.includes(v.id)); const handleAddVendor = (vendorId: string) => { const newValue = [...selectedVendorIds, vendorId]; @@ -65,7 +85,7 @@ function VendorsMultiSelectWithQuery( return (
- {availableVendors.length > 0 && ( + {availableVendors.length > 0 && !props.disabled && ( +