From 09540fef29f234be0f93846843a7a0940176b6b1 Mon Sep 17 00:00:00 2001 From: "Joseph T. French" Date: Thu, 15 Oct 2026 22:54:18 -0500 Subject: [PATCH] feat(ledger): listInformationBlockSummaries, the block list as identities and counts The rows, filters, order and page of listInformationBlocks, read by the server in one query instead of an envelope build per block. The call that fills a picker: factCount > 0 marks a block whose envelope carries facts. Waits on the robosystems release carrying #1834. --- clients/LedgerClient.test.ts | 29 ++++ clients/LedgerClient.ts | 40 ++++++ clients/graphql/generated/graphql.ts | 125 ++++++++++++++++++ .../queries/ledger/informationBlock.ts | 37 ++++++ 4 files changed, 231 insertions(+) diff --git a/clients/LedgerClient.test.ts b/clients/LedgerClient.test.ts index 855291d..a82cc03 100644 --- a/clients/LedgerClient.test.ts +++ b/clients/LedgerClient.test.ts @@ -784,6 +784,35 @@ describe('LedgerClient', () => { await client.listInformationBlocks('graph_1', { blockType: 'forecast', entityId: 'ent_sub' }) expect(variablesOf(0)).toMatchObject({ blockType: 'forecast', entityId: 'ent_sub' }) }) + + it('listInformationBlockSummaries returns identities and counts', async () => { + mockFetch.mockResolvedValueOnce( + gqlResponse({ + informationBlockSummaries: [ + { + id: 'str_1', + blockType: 'schedule', + name: 'Depreciation', + displayName: 'Schedule', + category: 'Close', + taxonomyId: 'tax_1', + taxonomyName: 'My CoA', + entityId: 'ent_parent', + factCount: 12, + connectionCount: 3, + }, + ], + }) + ) + const rows = await client.listInformationBlockSummaries('graph_1', { + limit: 200, + entityId: 'ent_sub', + }) + expect(rows).toHaveLength(1) + expect(rows[0].factCount).toBe(12) + expect(rows[0]).not.toHaveProperty('facts') + expect(variablesOf(0)).toMatchObject({ limit: 200, entityId: 'ent_sub' }) + }) }) describe('getMappingCoverage', () => { diff --git a/clients/LedgerClient.ts b/clients/LedgerClient.ts index 523beae..c3a80a8 100644 --- a/clients/LedgerClient.ts +++ b/clients/LedgerClient.ts @@ -209,6 +209,7 @@ import { GetLedgerTrialBalanceDocument, ListChartTemplatesDocument, ListInformationBlocksDocument, + ListInformationBlockSummariesDocument, ListLedgerAccountsDocument, ListLedgerAgentsDocument, ListLedgerBankAccountsDocument, @@ -252,6 +253,7 @@ import { type GetLedgerTrialBalanceQuery, type ListChartTemplatesQuery, type ListInformationBlocksQuery, + type ListInformationBlockSummariesQuery, type ListLedgerAccountsQuery, type ListLedgerAgentsQuery, type ListLedgerBlockedSourceGraphsQuery, @@ -339,6 +341,8 @@ export type LedgerMappingCoverage = NonNullable export type InformationBlockList = ListInformationBlocksQuery['informationBlocks'] +export type InformationBlockSummaryList = + ListInformationBlockSummariesQuery['informationBlockSummaries'] export type InformationBlockElement = InformationBlock['elements'][number] export type InformationBlockConnection = InformationBlock['connections'][number] export type InformationBlockFact = InformationBlock['facts'][number] @@ -1675,6 +1679,42 @@ export class LedgerClient { return blocks ?? [] } + /** + * List Information Blocks as identities and counts, one row per block — + * the rows, filters, order and page of `listInformationBlocks`, read in + * one query instead of an envelope build per block. The call that fills + * a picker: `factCount > 0` marks a block whose envelope carries facts + * (a library-seeded structure variant carries none); a block's atoms + * come from `getInformationBlock`. + */ + async listInformationBlockSummaries( + graphId: string, + options?: { + blockType?: string + category?: string + limit?: number + offset?: number + scenarioId?: string + entityId?: string | null + } + ): Promise { + const rows = await this.gqlQuery( + graphId, + ListInformationBlockSummariesDocument, + { + blockType: options?.blockType ?? null, + category: options?.category ?? null, + limit: options?.limit ?? null, + offset: options?.offset ?? null, + scenarioId: options?.scenarioId ?? null, + entityId: options?.entityId ?? null, + }, + 'List information block summaries', + (data) => data.informationBlockSummaries + ) + return rows ?? [] + } + // ── Schedules ────────────────────────────────────────────────────── /** diff --git a/clients/graphql/generated/graphql.ts b/clients/graphql/generated/graphql.ts index 6fe0d80..2f6ffeb 100644 --- a/clients/graphql/generated/graphql.ts +++ b/clients/graphql/generated/graphql.ts @@ -1196,6 +1196,30 @@ export type ListInformationBlocksQuery = { }> } +export type ListInformationBlockSummariesQueryVariables = Exact<{ + blockType: string | null | undefined + category: string | null | undefined + limit: number | null | undefined + offset: number | null | undefined + scenarioId: string | null | undefined + entityId: string | null | undefined +}> + +export type ListInformationBlockSummariesQuery = { + informationBlockSummaries: Array<{ + id: string + blockType: string + name: string + displayName: string + category: string + taxonomyId: string | null + taxonomyName: string | null + entityId: string | null + factCount: number + connectionCount: number + }> +} + export type ListLedgerJournalEntriesQueryVariables = Exact<{ startDate: string | null | undefined endDate: string | null | undefined @@ -5528,6 +5552,107 @@ export const ListInformationBlocksDocument = { }, ], } as unknown as DocumentNode +export const ListInformationBlockSummariesDocument = { + kind: 'Document', + definitions: [ + { + kind: 'OperationDefinition', + operation: 'query', + name: { kind: 'Name', value: 'ListInformationBlockSummaries' }, + variableDefinitions: [ + { + kind: 'VariableDefinition', + variable: { kind: 'Variable', name: { kind: 'Name', value: 'blockType' } }, + type: { kind: 'NamedType', name: { kind: 'Name', value: 'String' } }, + }, + { + kind: 'VariableDefinition', + variable: { kind: 'Variable', name: { kind: 'Name', value: 'category' } }, + type: { kind: 'NamedType', name: { kind: 'Name', value: 'String' } }, + }, + { + kind: 'VariableDefinition', + variable: { kind: 'Variable', name: { kind: 'Name', value: 'limit' } }, + type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } }, + }, + { + kind: 'VariableDefinition', + variable: { kind: 'Variable', name: { kind: 'Name', value: 'offset' } }, + type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } }, + }, + { + kind: 'VariableDefinition', + variable: { kind: 'Variable', name: { kind: 'Name', value: 'scenarioId' } }, + type: { kind: 'NamedType', name: { kind: 'Name', value: 'String' } }, + }, + { + kind: 'VariableDefinition', + variable: { kind: 'Variable', name: { kind: 'Name', value: 'entityId' } }, + type: { kind: 'NamedType', name: { kind: 'Name', value: 'String' } }, + }, + ], + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'informationBlockSummaries' }, + arguments: [ + { + kind: 'Argument', + name: { kind: 'Name', value: 'blockType' }, + value: { kind: 'Variable', name: { kind: 'Name', value: 'blockType' } }, + }, + { + kind: 'Argument', + name: { kind: 'Name', value: 'category' }, + value: { kind: 'Variable', name: { kind: 'Name', value: 'category' } }, + }, + { + kind: 'Argument', + name: { kind: 'Name', value: 'limit' }, + value: { kind: 'Variable', name: { kind: 'Name', value: 'limit' } }, + }, + { + kind: 'Argument', + name: { kind: 'Name', value: 'offset' }, + value: { kind: 'Variable', name: { kind: 'Name', value: 'offset' } }, + }, + { + kind: 'Argument', + name: { kind: 'Name', value: 'scenarioId' }, + value: { kind: 'Variable', name: { kind: 'Name', value: 'scenarioId' } }, + }, + { + kind: 'Argument', + name: { kind: 'Name', value: 'entityId' }, + value: { kind: 'Variable', name: { kind: 'Name', value: 'entityId' } }, + }, + ], + selectionSet: { + kind: 'SelectionSet', + selections: [ + { kind: 'Field', name: { kind: 'Name', value: 'id' } }, + { kind: 'Field', name: { kind: 'Name', value: 'blockType' } }, + { kind: 'Field', name: { kind: 'Name', value: 'name' } }, + { kind: 'Field', name: { kind: 'Name', value: 'displayName' } }, + { kind: 'Field', name: { kind: 'Name', value: 'category' } }, + { kind: 'Field', name: { kind: 'Name', value: 'taxonomyId' } }, + { kind: 'Field', name: { kind: 'Name', value: 'taxonomyName' } }, + { kind: 'Field', name: { kind: 'Name', value: 'entityId' } }, + { kind: 'Field', name: { kind: 'Name', value: 'factCount' } }, + { kind: 'Field', name: { kind: 'Name', value: 'connectionCount' } }, + ], + }, + }, + ], + }, + }, + ], +} as unknown as DocumentNode< + ListInformationBlockSummariesQuery, + ListInformationBlockSummariesQueryVariables +> export const ListLedgerJournalEntriesDocument = { kind: 'Document', definitions: [ diff --git a/clients/graphql/queries/ledger/informationBlock.ts b/clients/graphql/queries/ledger/informationBlock.ts index f55528b..328943d 100644 --- a/clients/graphql/queries/ledger/informationBlock.ts +++ b/clients/graphql/queries/ledger/informationBlock.ts @@ -521,3 +521,40 @@ export const LIST_INFORMATION_BLOCKS = gql` } } ` + +/** + * List Information Blocks as identities and counts, one row per block — + * the rows, filters, order and page of `ListInformationBlocks`, read in + * one query instead of an envelope build per block. The document a + * picker fills from. + */ +export const LIST_INFORMATION_BLOCK_SUMMARIES = gql` + query ListInformationBlockSummaries( + $blockType: String + $category: String + $limit: Int + $offset: Int + $scenarioId: String + $entityId: String + ) { + informationBlockSummaries( + blockType: $blockType + category: $category + limit: $limit + offset: $offset + scenarioId: $scenarioId + entityId: $entityId + ) { + id + blockType + name + displayName + category + taxonomyId + taxonomyName + entityId + factCount + connectionCount + } + } +`