From 2ec29841dafa0f7b91d588431cb06570bede878e Mon Sep 17 00:00:00 2001 From: Noah Overcash Date: Mon, 8 Jan 2024 15:49:53 -0500 Subject: [PATCH 1/4] Connected sources --- .../ApolloConnectedSource.d.ts | 16 +++ .../ConnectedSource/ConnectedSource.d.ts | 121 ++++++++++++++++++ .../StripesConnectedSource.d.ts | 18 +++ .../SearchAndSort/ConnectedSource/index.d.ts | 7 + 4 files changed, 162 insertions(+) create mode 100644 smart-components/lib/SearchAndSort/ConnectedSource/ApolloConnectedSource.d.ts create mode 100644 smart-components/lib/SearchAndSort/ConnectedSource/ConnectedSource.d.ts create mode 100644 smart-components/lib/SearchAndSort/ConnectedSource/StripesConnectedSource.d.ts create mode 100644 smart-components/lib/SearchAndSort/ConnectedSource/index.d.ts diff --git a/smart-components/lib/SearchAndSort/ConnectedSource/ApolloConnectedSource.d.ts b/smart-components/lib/SearchAndSort/ConnectedSource/ApolloConnectedSource.d.ts new file mode 100644 index 0000000..24e84c6 --- /dev/null +++ b/smart-components/lib/SearchAndSort/ConnectedSource/ApolloConnectedSource.d.ts @@ -0,0 +1,16 @@ +import { ApolloError } from 'apollo-client'; +import { ApolloConnectedSourceProps, ConnectedSource, StripesError } from './ConnectedSource'; +import Logger from '../../../../util/logger'; + +export default class ApolloConnectedSource implements ConnectedSource { + constructor(props: ApolloConnectedSourceProps, logger: Logger, resourceName?: string); + records(): unknown[]; + resultCount(): number; + totalCount(): number | null | undefined; + pending(): boolean; + loaded(): boolean; + failure(): ApolloError | null | undefined; + failureMessage(): string; + fetchMore(increment: number): void; + successfulMutations(): unknown[]; +} diff --git a/smart-components/lib/SearchAndSort/ConnectedSource/ConnectedSource.d.ts b/smart-components/lib/SearchAndSort/ConnectedSource/ConnectedSource.d.ts new file mode 100644 index 0000000..b2995ee --- /dev/null +++ b/smart-components/lib/SearchAndSort/ConnectedSource/ConnectedSource.d.ts @@ -0,0 +1,121 @@ +import { ApolloError } from 'apollo-client'; +import Logger from '../../../../util/logger'; +import { QueryFunction } from '../makeQueryFunction'; + +export interface ApolloConnectedSourceProps { + apolloResource?: string; + apolloRecordsKey: string; + queryFunction: QueryFunction; + parentData: { + // properties directly on parentData + loading?: boolean; + successfulMutations?: unknown[]; + error?: ApolloError; + fetchMore(params: { + variables: { + cql: string; + offset: number; + limit: number; + }; + // record key is `apolloResource` + updateQuery: ( + prev: Record, + params: { fetchMoreResult: unknown }, + ) => Record; + }): void; + } & { + // all within resource name (within recordsObj) + [resourceName: string]: { + totalRecords?: number; + } & { + // equals apolloRecordsKey + [recordsKey: string]: unknown[]; + }; + }; + parentResources: { + query: Record; + }; +} + +type StripesError = { + dataKey?: string; + httpStatus?: unknown; + message?: string; + module?: unknown; + resource?: unknown; + throwErrors?: unknown; +}; + +type StripesResourceType = { + resultCount: number; + notes?: string | boolean; + filters?: string; +} & { + // called recordsObj in code + [resourceName: string]: { + records?: unknown[]; + hasLoaded?: boolean; + isPending?: boolean; + failed?: StripesError; + other?: unknown; + successfulMutations?: unknown[]; + }; +}; +type StripesMutatorType = { + resultCount: { + replace: (count: number) => void; + }; + resultOffset: { + replace: (offset: number) => void; + }; + query: { + replace: (query: unknown) => void; + update: (query: unknown) => void; + }; +}; + +export interface StripesConnectedSourceProps { + // key is from resourceName + parentResources: StripesResourceType; + resources?: StripesResourceType; + parentMutator?: StripesMutatorType; + mutator?: StripesMutatorType; +} + +export interface ConnectedSource { + records(): unknown[]; + + /** Number of records retrieved so far */ + resultCount(): number; + /** + * Number of records in the result-set, available to be retrieved. + * + * For {@code StripesConnectedSource}, when there are > 10k results to a search, the `totalRecords` + * value comes back as `999999999`, so we use that value to indicate + * that the count is, in fact, undefined vs returning null to indicate + * that the count has not been calculated. + */ + totalCount(): number | null | undefined; + + /** True only during a request, false before and after */ + pending(): boolean; + + /** True only after a request, false before and during */ + loaded(): boolean; + + failure(): ApolloError | StripesError | undefined | null; + + failureMessage(): string; + + fetchMore(increment: number): void; + + successfulMutations(): unknown[]; +} + +export type ConnectedSourceProps = ApolloConnectedSourceProps | StripesConnectedSourceProps; + +export default function makeConnectedSource( + props: ConnectedSourceProps, + logger: Logger, + resourceName?: string, +): ConnectedSource | null; diff --git a/smart-components/lib/SearchAndSort/ConnectedSource/StripesConnectedSource.d.ts b/smart-components/lib/SearchAndSort/ConnectedSource/StripesConnectedSource.d.ts new file mode 100644 index 0000000..48cd111 --- /dev/null +++ b/smart-components/lib/SearchAndSort/ConnectedSource/StripesConnectedSource.d.ts @@ -0,0 +1,18 @@ +import { StripesConnectedSourceProps, ConnectedSource, StripesError } from './ConnectedSource'; +import Logger from '../../../../util/logger'; + +export default class StripesConnectedSource implements ConnectedSource { + constructor(props: StripesConnectedSourceProps, logger: Logger, resourceName?: string); + update(props: StripesConnectedSourceProps, resourceName?: string): void; + records(): unknown[]; + resultCount(): number; + totalCount(): number | null | undefined; + pending(): boolean; + loaded(): boolean; + failure(): StripesError | null | undefined; + failureMessage(): string; + fetchMore(increment: number): void; + fetchByBrowsePoint(browsePoint: unknown): void; + fetchOffset(index: number): void; + successfulMutations(): unknown[]; +} diff --git a/smart-components/lib/SearchAndSort/ConnectedSource/index.d.ts b/smart-components/lib/SearchAndSort/ConnectedSource/index.d.ts new file mode 100644 index 0000000..0112ad4 --- /dev/null +++ b/smart-components/lib/SearchAndSort/ConnectedSource/index.d.ts @@ -0,0 +1,7 @@ +export { + default, + ConnectedSource, + ConnectedSourceProps, + ApolloConnectedSourceProps, + StripesConnectedSourceProps, +} from './ConnectedSource'; From 6b612b0cde93de06cb1bb896917d5c2c56cc7a5d Mon Sep 17 00:00:00 2001 From: Noah Overcash Date: Mon, 8 Jan 2024 15:53:24 -0500 Subject: [PATCH 2/4] logger, doh --- util/logger.d.ts | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 util/logger.d.ts diff --git a/util/logger.d.ts b/util/logger.d.ts new file mode 100644 index 0000000..134bcb2 --- /dev/null +++ b/util/logger.d.ts @@ -0,0 +1,3 @@ +// TODO: actual typings for stripes logger +declare type Logger = (...args: any) => void; +export default Logger; From 01dff745ffbb27c04fd845a673d34b48e27f2c7f Mon Sep 17 00:00:00 2001 From: Noah Overcash Date: Mon, 8 Jan 2024 15:56:47 -0500 Subject: [PATCH 3/4] more deps --- package.json | 1 + .../lib/SearchAndSort/makeQueryFunction.d.ts | 52 +++++++++++++++++++ .../lib/SearchAndSort/nsQueryFunctions.d.ts | 32 ++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 smart-components/lib/SearchAndSort/makeQueryFunction.d.ts create mode 100644 smart-components/lib/SearchAndSort/nsQueryFunctions.d.ts diff --git a/package.json b/package.json index 1455bd0..10940f0 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ }, "dependencies": { "@folio/stripes-react-hotkeys": "^3.0.0", + "apollo-client": "^2.6.10", "ky": "^0.33.3", "moment": "^2.29.4", "popper.js": "^1.16.1", diff --git a/smart-components/lib/SearchAndSort/makeQueryFunction.d.ts b/smart-components/lib/SearchAndSort/makeQueryFunction.d.ts new file mode 100644 index 0000000..87f296a --- /dev/null +++ b/smart-components/lib/SearchAndSort/makeQueryFunction.d.ts @@ -0,0 +1,52 @@ +import { FilterGroupsConfig } from '../../../components'; +import Logger from '../../../util/logger'; +import { NsParamsType } from './nsQueryFunctions'; + +/** + * Returns a string, or null, which stripes-connect will use to construct a resource query. + * + * Accepts four params: + * @param queryParams An object containing the UI URL's query parameters (as accessed by ?{name}). + * @param pathComponents An object containing the UI URL's path components (as accessed by :{name}). + * @param resourceData An object containing the component's resources' data (as accessed by %{name}). + * @param logger A logger object. + */ +export type QueryFunction = ( + queryParams: Record, + pathComponents: Record, + resourceData: { query: Record }, + logger: Logger, +) => string | null; + +/** + * Builds a {@link QueryFunction} + * + * @param findAll CQL query to retrieve all records when there is a sort clause but no CQL query + * @param queryTemplate CQL query to interpolate, or function which will return CQL + * @param sortMap map from sort keys to CQL fields + * @param filterConfig list of filter objects, see {@link FilterGroupsConfig} + * @param failOnCondition one of the following: + * - 0 (or false (legacy)): do not fail even if query and filters and empty + * - 1 (or true (legacy)): fail if query is empty, whatever the filter state + * - 2: fail if both query and filters and empty + * @param nsParams namespace keys + * @param configOrEscape an object containing configuration parameters: + * - escape: whether to escape the query string (default true) + * - rightTrunc: whether to right-truncate the query string (default true) + * For backwards compatibility, this parameter may also be a boolean, in which case it is used as the `escape` configuration value. + */ +export default function makeQueryFunction( + findAll: string, + queryTemplate: + | string + | (( + nsQueryParams: Record, + pathComponents: Record, + queryObj: { query: Record }, + ) => string), + sortMap: Record, + filterConfig: FilterGroupsConfig, + failOnCondition: 0 | 1 | 2 | true | false, + nsParams: NsParamsType, + configOrEscape: boolean | { escape?: boolean; rightTrunc?: boolean }, +): QueryFunction; diff --git a/smart-components/lib/SearchAndSort/nsQueryFunctions.d.ts b/smart-components/lib/SearchAndSort/nsQueryFunctions.d.ts new file mode 100644 index 0000000..28c82c5 --- /dev/null +++ b/smart-components/lib/SearchAndSort/nsQueryFunctions.d.ts @@ -0,0 +1,32 @@ +export type NsParamsType = string | Record | undefined | null; + +export function getNsKey(key: string, params?: NsParamsType): string; + +/** + * + * Adds namespace / prefix to keys in whitelist for given values object + * + * @example + * ``` + * values = mapNsKeys({ query: "test", filters: 'active', userId: 1 }, 'users') + * // result: { "users.query" : "test", "users.filters": "active", userId: 1 } + * ``` + */ +export function mapNsKeys( + values: Record, + params?: NsParamsType, +): Record; + +/** + * Removes namespace / prefix from keys for given values object + * + * @example + * ``` + * values = removeNsKeys({ "users.query" : "test", "users.filters": "active" }, 'users') + * // result: { query: "test", filters: 'active' } + * ``` + */ +export function removeNsKeys( + values: Record, + params?: NsParamsType, +): Record; From 13b24f53f16a3fa327d01962947c1db29cab77a6 Mon Sep 17 00:00:00 2001 From: Noah Overcash Date: Mon, 8 Jan 2024 16:01:45 -0500 Subject: [PATCH 4/4] remove apollo dep --- package.json | 1 - .../ConnectedSource/ApolloConnectedSource.d.ts | 4 ++-- .../SearchAndSort/ConnectedSource/ConnectedSource.d.ts | 8 +++++++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 10940f0..1455bd0 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,6 @@ }, "dependencies": { "@folio/stripes-react-hotkeys": "^3.0.0", - "apollo-client": "^2.6.10", "ky": "^0.33.3", "moment": "^2.29.4", "popper.js": "^1.16.1", diff --git a/smart-components/lib/SearchAndSort/ConnectedSource/ApolloConnectedSource.d.ts b/smart-components/lib/SearchAndSort/ConnectedSource/ApolloConnectedSource.d.ts index 24e84c6..7bf89be 100644 --- a/smart-components/lib/SearchAndSort/ConnectedSource/ApolloConnectedSource.d.ts +++ b/smart-components/lib/SearchAndSort/ConnectedSource/ApolloConnectedSource.d.ts @@ -1,6 +1,5 @@ -import { ApolloError } from 'apollo-client'; -import { ApolloConnectedSourceProps, ConnectedSource, StripesError } from './ConnectedSource'; import Logger from '../../../../util/logger'; +import { ApolloConnectedSourceProps, ApolloError, ConnectedSource } from './ConnectedSource'; export default class ApolloConnectedSource implements ConnectedSource { constructor(props: ApolloConnectedSourceProps, logger: Logger, resourceName?: string); @@ -10,6 +9,7 @@ export default class ApolloConnectedSource implements ConnectedSource { pending(): boolean; loaded(): boolean; failure(): ApolloError | null | undefined; + failureMessage(): string; fetchMore(increment: number): void; successfulMutations(): unknown[]; diff --git a/smart-components/lib/SearchAndSort/ConnectedSource/ConnectedSource.d.ts b/smart-components/lib/SearchAndSort/ConnectedSource/ConnectedSource.d.ts index b2995ee..192d444 100644 --- a/smart-components/lib/SearchAndSort/ConnectedSource/ConnectedSource.d.ts +++ b/smart-components/lib/SearchAndSort/ConnectedSource/ConnectedSource.d.ts @@ -1,7 +1,13 @@ -import { ApolloError } from 'apollo-client'; import Logger from '../../../../util/logger'; import { QueryFunction } from '../makeQueryFunction'; +type ApolloError = { + message: string; + graphQLErrors: unknown[]; + networkError: Error | null; + extraInfo: any; +}; + export interface ApolloConnectedSourceProps { apolloResource?: string; apolloRecordsKey: string;