From cda1276f486e0c4646fa2cc00c371e0554424fd1 Mon Sep 17 00:00:00 2001 From: Amir Karbasi Date: Tue, 5 Mar 2024 21:38:50 -0500 Subject: [PATCH] Expose report API --- src/Client.ts | 3 + src/index.ts | 12 +++ src/services/Auth.ts | 18 ++++- src/services/{Query.ts => Report.ts} | 115 +++++++++++++++++---------- 4 files changed, 106 insertions(+), 42 deletions(-) rename src/services/{Query.ts => Report.ts} (59%) diff --git a/src/Client.ts b/src/Client.ts index b2f017e..96366a4 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -1,5 +1,6 @@ import Auth from "@/services/Auth"; import Model from "@/services/Model"; +import Report from "@/services/Report"; import AppConfig, { WebAppProperties } from "@/services/utils/AppConfig"; /** @@ -10,6 +11,7 @@ export default class Client { auth!: Auth; model!: Model; + report!: Report; /** @hidden */ constructor(appConfig: AppConfig) { @@ -37,6 +39,7 @@ export default class Client { client.auth = new Auth(appConfig, useCredentials); client.model = new Model(appConfig, client.auth); + client.report = new Report(appConfig, client.auth); if (useCredentials) { await client.model.Init(); diff --git a/src/index.ts b/src/index.ts index 4364eeb..222423e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -28,6 +28,13 @@ import { MonthlyRecurrence, YearlyRecurrence, } from "@/services/utils/helpers/Recurrence"; +import Report, { + ReportListResults, + ReportData, + ReportListFilters, + ReportDetails, +} from "@/services/Report"; + import Client from "@/Client"; export { @@ -57,6 +64,11 @@ export { User, UpdateRecordResponse, CreateRecordResponse, + ReportListResults, + ReportData, + ReportDetails, + ReportListFilters, + Report, }; export default Client; diff --git a/src/services/Auth.ts b/src/services/Auth.ts index b30ae73..895d00f 100644 --- a/src/services/Auth.ts +++ b/src/services/Auth.ts @@ -194,13 +194,29 @@ export default class Auth { } } + /** + * Simple method for generating a redirect URL for the frontend. + * + * @remarks + * Used with frontend frameworks to redirect the user to the login URL. Once authenticated, they will return to their previous page. + * This flow is also supported by SSO-enabled environments. + * + * @param url The page that the user should be redirected to after a successful authentication. + * @returns The full URL that the user should be redirected for reauthentication. + */ + generateLoginUrl(url: string) { + return `${ + this.appConfig.tririgaUrl + }/p/websignon?redirectUrl=${encodeURIComponent(url)}`; + } + /** * A helper method for building the basic request options object. * * @remarks * This method is used to append the required cookie and useCredentials values to the request options. * - * @param additionalOptions Custom request options from the caller + * @param additionalOptions Custom request options from the caller. * @returns A `RequestInit` object with the required headers and user specified options. */ generateRequestHeaders(additionalOptions?: RequestInit): RequestInit { diff --git a/src/services/Query.ts b/src/services/Report.ts similarity index 59% rename from src/services/Query.ts rename to src/services/Report.ts index 72e0587..bf640b6 100644 --- a/src/services/Query.ts +++ b/src/services/Report.ts @@ -1,7 +1,7 @@ import Auth from "./Auth"; import AppConfig from "./utils/AppConfig"; -interface QueryDetails { +export interface ReportDetails { formId: number; reportId: number; moduleName: string; @@ -13,8 +13,8 @@ interface QueryDetails { boNames: string; } -export interface QueryListResults { - data?: QueryDetails[]; +export interface ReportListResults { + data?: ReportDetails[]; totalPageCount: number; resultsPerPage: number; hasNextPage: boolean; @@ -23,17 +23,17 @@ export interface QueryListResults { totalCount: number; } -interface QueryColumnDefinitions { +interface ReportColumnDefinitions { [key: string]: unknown; } -export interface QueryMetadata { - columnDefinitions: QueryColumnDefinitions[]; +export interface ReportMetadata { + columnDefinitions: ReportColumnDefinitions[]; } -export interface QueryData { +export interface ReportData { data: { [key: string]: string }[]; - headers: QueryColumnDefinitions[]; + headers: ReportColumnDefinitions[]; hasNext: boolean; hasPrevious: boolean; pageNumber: number; @@ -42,8 +42,20 @@ export interface QueryData { totalSize: number; } -/** Platform 4.2+.The Query class is used to retrieve and execute TRIRIGA queries. */ -export default class Query { +export interface ReportListFilters { + title?: string; + name?: string; + tag?: string; + moduleId?: string; + moduleIdName?: string; + boId?: string; + boIdName?: string; + formId?: string; + formIdName?: string; +} + +/** Platform 4.2+. The Report class is used to retrieve and execute TRIRIGA queries. */ +export default class Report { appConfig: AppConfig; auth: Auth; @@ -59,24 +71,29 @@ export default class Query { * @remarks * An async function that returns the results of system reports. The authenticated user must have access to system reports to view this data. * - * @param pageNumber The current page number + * @param pageNumber The current page number as a zero-based value * @param perPage The total number of reports per page - * @returns A `QueryListResults` object with the query details + * @param filters The object that is used to filter the result set + * @returns A `ReportListResults` object with the report details * * @throws Error if the query list could not be retrieved. This is caused by connectivity, session or user permission issues. */ async getQueryList( - pageNumber: number, - perPage: number - ): Promise { + pageNumber: number = 0, + perPage: number = 50, + filters?: ReportListFilters + ): Promise { // Ensure that the CSRF Token is still valid if (await this.auth.updateCsrfToken()) { const queryParams = { objectId: "1200000", actionId: "1200501", managerReportType: "SystemReport", + _: "", + reportType: "-1", currentPageNumber: pageNumber.toString(), noOfReports: perPage.toString(), + ...filters, }; const headers: HeadersInit = {}; @@ -97,36 +114,36 @@ export default class Query { if (req.ok) { const resp = await req.json(); if (resp.length > 1) { - const results: QueryListResults = { + const results: ReportListResults = { totalPageCount: resp[1].TotalNumberOfPages, resultsPerPage: resp[1].ResultsPerPage, hasNextPage: resp[1].IsNext, hasPreviousPage: resp[1].IsPrevious, currentPageNumber: resp[1].currentPageNumber, totalCount: resp[1].TotalResultCnt, - data: resp[0] as QueryDetails[], + data: resp[0] as ReportDetails[], }; return results; } } } - throw new Error("Could not retrieve query list"); + throw new Error("Could not retrieve report list"); } /** - * Retrieves the query metadata + * Retrieves the report metadata * * @remarks - * The query metadata will contain details surrounding the columns. + * The report metadata will contain details surrounding the columns. * - * @param templateId The unique query ID - * @returns A `QueryMetadata` object + * @param templateId The unique report ID + * @returns A `ReportMetadata` object * - * @throws Error if the query is not found or if the client encounters connectivity issues. + * @throws Error if the report is not found or if the client encounters connectivity issues. */ - async getQueryDefinition(templateId: number): Promise { - const queryMetadata: QueryMetadata = { columnDefinitions: [] }; + async getReportDefinition(templateId: number): Promise { + const reportMetadata: ReportMetadata = { columnDefinitions: [] }; const reqOptions = this.auth.generateRequestHeaders(); const urlParams = new URLSearchParams({ reportTemplId: templateId.toString(), @@ -142,35 +159,35 @@ export default class Query { throw new Error(resp["error_message"]); } if (resp["gridConfig"] && resp["gridConfig"]["columns"].length > 0) { - queryMetadata.columnDefinitions = resp["gridConfig"]["columns"]; + reportMetadata.columnDefinitions = resp["gridConfig"]["columns"]; } - return queryMetadata; + return reportMetadata; } - throw new Error("Could not determine query metadata"); + throw new Error("Could not determine report metadata"); } /** - * Returns the query data for a specific page. + * Returns the report data for a specific page. * * @remarks - * This method is used to retrieve data from a specific query. It will return an object that contains the data with the defined columns. + * This method is used to retrieve data from a specific report. It will return an object that contains the data with the defined columns. * - * @param templateId The unique query ID + * @param templateId The unique report ID * @param pageNumber The current page number * @param pageSize The page size - * @returns A `QueryData` object containing record details for the current page. + * @returns A `ReportData` object containing record details for the current page. * * @throws Error if the input is invalid or if the client encounters connectivity issues. */ - async getQueryData( + async getReportData( templateId: number, pageNumber = 0, pageSize = 50 - ): Promise { - const queryMetadata = await this.getQueryDefinition(templateId); + ): Promise { + const reportMetadata = await this.getReportDefinition(templateId); - if (queryMetadata.columnDefinitions.length > 0) { + if (reportMetadata.columnDefinitions.length > 0) { const reqOptions = this.auth.generateRequestHeaders(); const urlParams = new URLSearchParams({ reportTemplId: templateId.toString(), @@ -184,9 +201,9 @@ export default class Query { if (req.ok) { const resp = await req.json(); - const queryData: QueryData = { + const reportData: ReportData = { data: resp["data"], - headers: queryMetadata.columnDefinitions, + headers: reportMetadata.columnDefinitions, hasNext: resp["result_has_next"], hasPrevious: resp["result_has_previous"], pageNumber: resp["result_page_number"], @@ -194,12 +211,28 @@ export default class Query { resultSize: resp["result_count"], totalSize: resp["result_total_size"], }; - return queryData; + return reportData; } - throw new Error("Could not retrieve query data"); + throw new Error("Could not retrieve report data"); } - throw Error("Invalid query metadata"); + throw Error("Invalid report metadata"); } + + // private generateReportFilterObject( + // input: ReportListFilters = {} + // ): ReportListFilters { + // const filters = input; + + // if (filters.formIdName && !filters.formId) { + // filters.formId = "-1"; + // } + + // if (filters.moduleIdName && !filters.moduleId) { + // filters.moduleId = ""; + // } + + // return filters; + // } }