UNPKG

@leanix/reporting

Version:

Library for writing LeanIX EAM reports

1,362 lines (1,360 loc) 109 kB
declare const lx: lxr.LxCustomReportLib; declare module lxr { interface HostReportSetup extends ReportSetup { settings: HostReportSetupSettings; } interface HostReportSetupSettings extends ReportSetupSettings { features: Feature[]; } type FeatureType = 'FUNCTIONAL' | 'QUOTA'; type FeatureStatus = 'DISABLED' | 'ENABLED'; interface Feature { id?: string; name?: string; type?: FeatureType; description?: string; status?: FeatureStatus; quota?: number; roles?: string[]; customized?: boolean; } /** * Entry class of the LeanIX Reporting Library. * An instance of this class is globally available as `lx` variable. * * @example * ```js * // The sequence to initialise the library for a report looks like this: * lx.init() * .then(function (setupInfo) { * // Process setupInfo and create config object * var config = {}; * lx.ready(config); * }); * ``` */ export class LxCustomReportLib { table: ReportLibTable; get latestPublishedState(): any; readonly dataModelHelpers: DataModelHelpers; private messenger; private _currentSetup; private latestFacetsResults; private _latestPublishedState; private customDropdownCallbacks; private latestMouseEvent; private latestFocusedElement; constructor(); /** * Starts initialisation of the reporting framework. Returns a promise * which is resolved once initialisation with the framework is finished. The * resolved promise contains a {@link ReportSetup} instance with information * provided to you through the framework. * With that information you should be able to set up your report properly. Once * that is done the {@link LxCustomReportLib.ready} function needs be called to signal * that the report is ready to receive and process data and user events. * * @return A promise that resolves to the ReportSetup object */ init(): Promise<ReportSetup>; /** * Signals that the custom report is ready. A configuration must be provided * to tell the framework about the requirements of the report (most importantly which data it needs). * The provided configuration acts as an interface between the report code * and the report framework. * * @param {ReportConfiguration} [configuration={}] Configuration object */ ready(configuration?: ReportConfiguration): void; /** * Getter to receive the current state of the report setup. * The object is only available if the report already called a successful init() {@link LxCustomReportLib.init}. */ get currentSetup(): HostReportSetup; /** * In case the report has new requirements towards the report framework it can * update the configuration that was initially passed to {@link LxCustomReportLib.ready}. * * @param configuration */ updateConfiguration(configuration: ReportConfiguration): void; /** * A static tableConfig should be returned via {@link ReportConfiguration.tableConfigCallback}, * but if the tableConfig is dynamic, this function can be used to update it at any time. * * Hint: if the provided attribute is a string field name, which is not present in the data model, this * field would be ignored, and not shown as a table column. * * @param tableConfig */ updateTableConfig(tableConfig: ReportTableConfig): void; /** * Execute a custom GraphQL query to the LeanIX GraphQL API. * * @param query GraphQL query * @param variables GraphQL variables * @return A promise that resolves to the resulting data * @example * ```js * lx.executeGraphQL(`{ * allFactSheets(factSheetType: ITComponent) { * edges { * node { * id * name * type * description * } * } * } * }`) * ``` */ executeGraphQL(query: string, variables?: string, trackingKey?: string): Promise<any>; /** * Get projections from the impact service. * * @param attributes Fact Sheet attributes that the projection items should include. * @param filters Filter definition for the projection items * @param pointsOfView Amount of different point of views that the projection should include. * * @beta */ getProjections(attributes: ProjectionAttribute[], filters: ProjectionFilter[], pointsOfView: PointOfViewInput[]): Promise<ProjectionsResponse>; /** * Get all Fact Sheets from the GraphQL endpoint. * * @param factSheetType Fact Sheet type that needs to match. * @param attributes Fact Sheet attributes that the response should include. * @param facetSelection Filter definition for the Fact Sheets, if Composite Filters are defined, they are used instead of the normal Facet Filters. * @param pointsOfView A record of different point of views and their associated keys that the response should include and will return the Fact Sheets per each point of view key. * @param options Optional options to further specify the Fact Sheets * * @beta */ getAllFactSheets(factSheetType: string, attributes: AttributeDescription[], facetSelection: ReportFacetsSelection, pointsOfView: Record<string, GraphQLPointOfViewInput>, options?: GraphQLOptions): Promise<ReportAllFactSheetsResponse>; /** * Get a list of measurements from the metrics service. * * @param nameOnly Set this to true to receive only the measurement names * @return A promise that resolves to an array of measurements * * @beta */ getMetricsMeasurements(nameOnly?: boolean): Promise<MetricsMeasurement[]>; /** * Get raw data for a metrics time series. * * @param query A metrics service query * @return A promise that resolves to the raw series data * * @beta */ getMetricsRawSeries(query: string): Promise<number[][]>; /** * Allows making XHR requests through the parent's origin. * * @param method The HTTP method for the request. GET, PUT, and POST requests are permitted. * For POST and PUT requests, not every endpoint is allowed. * @param path Relative URL for the request. * @param body Optional body for POST and PUT requests. Defaults to an empty object. * @param responseType The expected type of the response. Can be 'text' or 'blob'. Defaults to 'text'. * @param extendedHandling Optional boolean to add a custom header for extended request handling. * If true, adds 'x-gateway-handle-request: EXTENDED' header. Defaults to false. * @return A promise that resolves to the returned data. */ executeParentOriginXHR(method: 'GET' | 'POST' | 'PUT', path: string, body?: any, responseType?: 'text' | 'blob', extendedHandling?: boolean): Promise<any>; /** * Get the current filter result. * * @return Current filter result */ getFilterResult(): any[]; /** * Show a dialog to the user to select one or more Fact Sheets. * * @param config Configures the Fact Sheet selection. * @return A promise that resolves to the selected Fact Sheet(s) * or to `false` if the user canceled the selection */ requestFactSheetSelection(config: FactSheetSelectionConfig): Promise<false | any | any[]>; /** * Show a customisable configuration dialog to the user, in which the user can adjust report settings. * * @param fields An object containing the form fields to be displayed in this dialog. * @param values An object with the same keys as __fields__ containing the initial values of those fields. * @return A promise that resolves to the configuration confirmed by the user or to `false` if the user canceled the configuration * @example * ```js * const fields = { * level: { * type: 'SingleSelect', * label: 'Level to be displayed', * options: [ * { value: '1', label: 'First level' }, * { value: '2', label: 'Both levels' } * ] * }, * hideEmpty: { * type: 'Checkbox', * label: 'Hide empty elements' * } * }; * const initialValues = { * level: '2', * hideEmpty: false * }; * * lx.openFormModal(fields, initialValues).then((values) => { * if (values) { * console.log('Selection:', values.level, values.hideEmpty); * } else { * console.log('Selection cancelled'); * } * }); * ``` */ openFormModal(fields: FormModalFields, values: FormModalValues, update?: (form: FormModal) => FormModal): Promise<FormModalValues | false>; /** * Show a customisable configuration dialog to the user, in which the user can adjust report settings. * * @param formModal An object {@link FormModal} containing the form fields, values, optional messages and optional valid flag. * @param update Callback function called on form update. * @return A promise that resolves to the configuration confirmed by the user or to `false` if the user canceled the configuration * @example * ```js * const fields = { * level: { * type: 'SingleSelect', * label: 'Level to be displayed', * options: [ * { value: '1', label: 'First level' }, * { value: '2', label: 'Both levels' } * ] * }, * hideEmpty: { * type: 'Checkbox', * label: 'Hide empty elements' * } * }; * const values = { * level: '2', * hideEmpty: false * }; * * const messages = { * level: {type: 'error', message:'example message'} * } * * const update = (formModal: lxr.FormModal): lxr.FormModal => {return createFormModal()} * * lx.openFormModal({fields, values, messages, valid: true}, updated).then((values) => { * if (values) { * console.log('Selection:', values.level, values.hideEmpty); * } else { * console.log('Selection cancelled'); * } * }); * ``` */ openFormModal(formModal: FormModal, update?: (form: FormModal) => FormModal): Promise<FormModalValues | false>; private doOpenFormModal; /** * Shows an overlaying sidepane with the provided elements. * * @beta */ openSidePane(sidePaneElements: SidePaneElements, update?: (factSheetUpdate: FactSheetUpdate) => void, onClick?: (sidepaneClick: SidePaneClick) => void): void; /** * This method allows you to open any link in a new browser tab. Only Chrome and Safari * allows you to open a new tab out of an iframe. Since reports run inside an iframe, * they are not allowed to open links in other browsers. * Therefore, the framework allows you to request to open a link. * This will show a popup box outside the iframe containing the link. * The user can click on it in order to open the link in a new tab. * * It is not possible to directly open the link outside the iframe, * since some browsers (e.g. Firefox) show a popup warning * whenever a link is opened via a message coming from an iframe. * * @param url Link-URL * @param @deprecated _target (target is ignored due to new popup behavior) * @example * ```js * lx.openLink(this.baseUrl + '/factsheet/Application/28fe4aa2-6e46-41a1-a131-72afb3acf256'); * // The baseUrl can be found in the setup returned by lx.init() like this: * // lx.init().then(setup => { this.baseUrl = setup.settings.baseUrl }); * ``` */ openLink(url: string, _target?: string): void; /** * Navigate to a route within the LeanIX single-page app. * * @param url Relative URL within LeanIX to navigate to */ openRouterLink(url: string): void; /** * Navigate to inventory using provided filters * * @param filters Specified filters will be applied to inventory */ navigateToInventory(filters: NavigateToInventoryFilters): void; /** * In case the report has some sort of internal state it should be published * to the framework. The state will be persisted when the user saves a certain * report configuration. Once that report configuration is restored the framework * will pass the saved state to the report on initialisation * ({@link LxCustomReportLib.init} and {@link ReportSetup.savedState}) * * @param state Custom report state */ publishState(state: any): void; /** * This function opens a "new" instance of the report in a separate tab. * The state and facet filter parameters can be used as initial values for the new opened instance of the report. * * @param state Custom report state * @param facetSelection Facet filter selection ({@link UISelection.facets}) * @param name Preset name of the new report opened in new tab. If not set, falls back to default name. * * @beta */ openReportInNewTab(state: any, facetSelection: ContextFacetsSelectionState[], name?: string): void; /** * Show a spinner on top of the report. Call {@link LxCustomReportLib.hideSpinner} to hide it again. */ showSpinner(): void; /** * This method allows reports to check on users' workspace permissions. * Therefore, reports can enable features according to given workspace permissions. * See: [Authorization Model]{@link https://docs-eam.leanix.net/docs/authorization-model} * @param permissions Shiro permissions string array to check (example: `['BOOKMARKS:CREATE:VISUALIZER', 'BOOKMARKS:CREATE:REPORTS']` creation of diagram bookmarks) * @returns Promise of all requested permissions as key-value pair of the requested user permissions. */ hasPermission(permissions: string[]): Promise<{ [permissionKey: string]: boolean; }>; /** * Hide the spinner that was previously shown via {@link LxCustomReportLib.showSpinner}. */ hideSpinner(): void; /** * @deprecated. UI Elements are created on {@link ReportConfiguration.ui}. * * Display a button to toggle edit mode. Call {@link LxCustomReportLib.hideEditToggle} to hide it again. * {@link ReportConfiguration.allowEditing} and {@link ReportConfiguration.toggleEditingCallback} need to be set * to enable edit mode. */ showEditToggle(): void; /** * @deprecated. UI Elements are created or removed on {@link ReportConfiguration.ui}. * * Hide the button shown via {@link LxCustomReportLib.showEditToggle}. */ hideEditToggle(): void; /** * Send list of Fact Sheets that could not be displayed in the report due to missing data. * A warning will be shown the user to inform them of this. * * @param excludedFactSheets List of excluded Fact Sheets */ sendExcludedFactSheets(excludedFactSheets: any[]): void; /** * Display a custom legend for a given number of items. If a legend from a view is currently * displayed, the calls to this function are ignored. * * @param items Legend items to be displayed * @exampleHide the spinner that was previously shown via * ```js * lx.showLegend([ * { label: 'foo', bgColor: '#ff0000' }, * { label: 'bar', bgColor: '#0000ff' } * ]) * ``` */ showLegend(items: LegendItem[]): void; /** * Show toastr of different types, with a custom message and a optional title. * * @param {ToastrType} type toastr type * @param {string} message message content * @param {string} [title] optional title * @example * ```js * lx.showToastr('error', 'Something went wrong'); * lx.showToastr('warning', 'This is a warning', 'Attention'); * ``` */ showToastr(type: ToastrType, message: string, title?: string): void; /** * Track report framework events with amplitude tracking. * * @param {ReportEvent} event event type and content * @example * ```js * lx.trackReportEvent( * { * type: 'DataChange' * reportType: 'net.leanix.matrix' * baseFactSheetType: 'Application' * view: 'lifecycle' * cluster: ['relApplicationToBusinessCapability'] * drilldown: ['relToChild'] * } * ); * ``` */ trackReportEvent(event: ReportEvent): void; /** * Returns the translation of a custom translation key according to the user's current language. * If the translation key can be resolved to a translated string interpolation will be applied. * If the translation key resolves to an object the object will be returned. * * @param key Translation key * @param interpolationData Interpolation data * @return Translation string or object * @example * ```js * // For the custom translation json * { * "header": { * "title": "The title", * "subtitle": "Subtitle", * "description": "Hello {{name}}" * } * } * * lx.translateCustomKey('header.title') // => 'The title' * lx.translateCustomKey('header') // => { "title": "The title", "subtitle": "Subtitle", "description": "Hello {{name}}" } * lx.translateCustomKey('header.description', { name: 'John' }) // => 'Hello John' * ``` */ translateCustomKey(key: string, interpolationData?: Record<string, string | number>): string | any; /** * Returns the translation of a Fact Sheet type in singular or plural form. * If multiplicity is not provided the singular version will be returned. * * @param fsType Fact Sheet type * @param grammaticalNumber Grammatical number, i.e., 'singular' or 'plural'. Defaults to 'singular'. * @return Translation * @example * ```js * lx.translateFactSheetType('BusinessCapability') // => 'Business Capability' * lx.translateFactSheetType('BusinessCapability', 'plural') // => 'Business Capabilities' * ``` */ translateFactSheetType(fsType: string, grammaticalNumber?: 'singular' | 'plural'): string; /** * Returns the translation of a field on a Fact Sheet. * In case the field is not present in the translation model, the fieldName would be returned. * * @param fsType Fact Sheet type * @param fieldName Name of the Fact Sheet field * @return Translation * @example * ```js * lx.translateField('Application', 'release') // => 'Release' * ``` */ translateField(fsType: string, fieldName: string): string; /** * Returns the translation of a field value for fields with predefined set of values (e.g. Single Select). * In case the field value is not present in the translation model, the value would be returned. * * @param fsType Fact Sheet type * @param fieldName Name of the Fact Sheet field * @param value Value of this field * @return Translation * @example * ```js * lx.translateFieldValue('Application', 'functionalSuitability', 'appropriate') // => 'Appropriate' * ``` */ translateFieldValue(fsType: string, fieldName: string, value: string): string; /** * Returns the translation of the items a Fact Sheet relation links to. * In case the relation is not present in the translation model, the relationName would be returned. * * @param relationName Name of the relation * @return Translation * @example * ```js * lx.translateRelation('relDataObjectToApplication') // => 'Applications' * lx.translateRelation('relToChild') // => 'Children' * ``` */ translateRelation(relationName: string): string; /** * Returns the translation of a field present in a relation. * In case the relation is not present in the translation model, the fieldName would be returned. * * @param relationName Name of the relation * @param fieldName Field of the relation * @return Translation * @example * ```js * lx.translateRelationField('relDataObjectToApplication', 'usage') // => 'Usage' * lx.translateRelationField('relApplicationToBusinessCapability', 'functionalSuitability') // => 'Functional Fit' * ``` */ translateRelationField(relationName: string, fieldName: string): string; /** * Returns the translation of a field value for fields with predefined set of values (e.g. Single Select) * present in a relation. In case the relation, fieldName or fieldValue is not present in the translation model, the fieldValue would be returned. * * @param relationName Name of the relation * @param fieldName Field of the relation * @param fieldValue Value of this field * @return Translation * @example * ```js * lx.translateRelationFieldValue('relApplicationToBusinessCapability', 'functionalSuitability', 'appropriate') // => 'Appropriate' * ``` */ translateRelationFieldValue(relationName: string, fieldName: string, fieldValue: string): string; /** * Check if a given Feature is enabled for the current Workspace. * * @param featureId Feature identifier * @return Boolean expressing if the feature is enabled. */ isFeatureEnabled(featureId: string): Promise<boolean>; /** * Returns a formatted currency number according to the users currency settings. * * @param value Value to be formatted * @param minimumFractionDigits Minimum number of digits to use for the fraction * @param compact Defines whether to show compact display * @param locale Defines locale info 'de-DE', 'en-EN' * @param maximumFractionDigits Maximum number of digits to use for the fraction. When specified, * restricts the number of decimal places shown (useful for rounding). * @return Currency string * @example * ```js * lx.formatCurrency(123.50, 2) => '€123.50' * lx.formatCurrency(12333.50, 0, true) => '€12K' * lx.formatCurrencyWithoutCode(10255, 0, true, undefined, 1) => '€10.3K' * lx.formatCurrency(1288893.50, 2, true, 'de-DE') => '1,29 Mio. €' * ``` */ formatCurrency(value: number, minimumFractionDigits?: number, compact?: boolean, locale?: string, maximumFractionDigits?: number): string; /** * Returns the configured or default meta data for a field at a Fact Sheet. * * @param fsType Fact Sheet type * @param fieldName Name of a Fact Sheet field or relation * @return Meta data * @example * ```js * lx.getFactSheetFieldMetaData('Application', 'functionalSuitability') * // Returns: * // { * // values: { * // perfect: { * // bgColor: '#fff', * // color: '#000' * // } * // ... * // } * // } * // Getting the actual background color for a field value: * lx.getFactSheetFieldMetaData('Application', 'functionalSuitability').values['perfect'].bgColor * ``` */ getFactSheetFieldMetaData(fsType: string, fieldName: string): FieldViewMetaData | undefined; /** * Returns the configured or default meta data for a field of a Fact Sheet relation. * * @param fsType Fact Sheet type * @param relationName Name of the directed relation * @param fieldName Name of a field on the relation * @return Meta data * @example * ```js * lx.getFactSheetRelationFieldMetaData('Application', 'relApplicationToITComponent', 'technicalSuitability') * // Returns: * // { * // values: { * // fullyAppropriate: { * // bgColor: '#fff', * // color: '#000' * // } * // ... * // } * // } * * // Getting the actual background color for a field value: * lx.getFactSheetRelationFieldMetaData( * 'Application', * 'relApplicationToITComponent', * 'technicalSuitability' * ).values['perfect'].bgColor * ``` */ getFactSheetRelationFieldMetaData(fsType: string, relationName: string, fieldName: string): FieldViewMetaData; private setupPerformanceObserver; private createReportRequirements; private mountCallbacks; private mountUISelectionCallback; private mountUISelectionUpdateCallback; private mountUIElementsButtonClickCallback; private mountUIButtonCallback; private mountFacetsCallbacks; private mountFacetsResultCallback; private validateConfig; private mountSetupCallback; private mountCustomDropdownSelectionCallbacks; private mountExportDataCallback; private mountTableConfigCallback; private mountFormModalUpdate; private mountSidepaneFactSheetUpdate; private mountSidepaneClick; private mountSidepaneClose; private mountCallback; private getLocationQuery; private createReportExportData; private getCurrentStyles; private encodeAllImages; private encodeImage; private encodeSvgImage; private translateHtmlTags; private replaceInterpolations; private mountDomEventPublishing; private mountErrorEventPublishing; private waitForElement; } export const lxCustomReportLib: LxCustomReportLib; export {}; export class DataModelHelpers { getRelationDefinition(enrichedDataModel: EnrichedDataModel, directionalRelation: string): RelationDataModel | null; isConstrainingRelation(enrichedDataModel: EnrichedDataModel, relationName: string): boolean; } export type PaperOrientation = 'portrait' | 'landscape'; export interface BaseExportData { name: string; content: string; styles?: string; } export interface SvgExportData extends BaseExportData { inputType: 'SVG'; outputType: 'SVG'; } export interface RasterImageExportData extends BaseExportData { inputType: 'SVG' | 'HTML'; outputType: 'JPEG' | 'PNG'; } export interface PdfExportData extends BaseExportData { inputType: 'SVG' | 'HTML'; outputType: 'PDF'; fitHorizontally?: boolean; fitVertically?: boolean; /** @default 'A4' */ format?: PaperFormat; /** @default 'portrait' */ orientation?: PaperOrientation; /** @default { top: 0, right: 0, bottom: 0, left: 0 } */ margin?: PageMargin; footer?: string; header?: string; } export type PaperFormat = 'A0' | 'A1' | 'A2' | 'A3' | 'A4' | 'Letter'; export interface PageMargin { /** @default '0' */ top?: number; /** @default '0' */ right?: number; /** @default '0' */ bottom?: number; /** @default '0' */ left?: number; } export type ImageExportData = RasterImageExportData | SvgExportData; export type ExportData = PdfExportData | ImageExportData; export interface ExportInitialData { title?: string; data: string; styles: string; fileNameSuffix?: string; inputType: ExportData['inputType']; paperSize: { format: 'a0' | 'a1' | 'a2' | 'a3' | 'a4' | 'letter' | 'autofit'; }; orientation: PaperOrientation | null; fitHorizontally: boolean; fitVertically: boolean; viewLegendData?: { html: string; styles: string; }; usage?: 'thumbnail' | 'export'; } export interface ReportUser { id: string; firstName: string; lastName: string; email: string; userName: string; } export type ReportFactSheetPermissibleAction = 'READ' | 'CREATE' | 'UPDATE' | 'DELETE' | 'ARCHIVE' | 'INLINE_EDIT'; export interface ReportFactSheetFieldPermissions { [fieldName: string]: ReportFactSheetPermissibleAction[]; } export interface ReportFactSheetRelationPermission { self: ReportFactSheetPermissibleAction[]; } export interface ReportFactSheetRelationPermissions { [relationName: string]: ReportFactSheetRelationPermission; } export interface ReportFactSheetPermission { self: ReportFactSheetPermissibleAction[]; fields: ReportFactSheetFieldPermissions; relations: ReportFactSheetRelationPermissions; } export interface ReportFactSheetPermissions { [factSheetName: string]: ReportFactSheetPermission; } export type Language = 'en' | 'de' | 'es' | 'fr' | 'pt'; export interface ReportSetupSettings { baseUrl: string; environment: Environment; viewModel: ViewModel; dataModel: EnrichedDataModel; tagModel: TagModel; factSheetPermissions: ReportFactSheetPermissions; translations: ReportSetupTranslations; impactConfiguration?: ImpactConfiguration; currency: ReportSetupCurrency; currentUser: ReportUser; language: Language; workspace: Workspace; page: PageContext; mtmWorkspaceSettings: MtmWorkspaceSettings; } export interface ReportSetupConfig { factSheetType?: string; [others: string]: any; } export interface ReportSetupTranslations { factSheetTypes: { [key: string]: string; }; relations: { [relationName: string]: RelationTranslation; }; fields: { [factSheetType: string]: FactSheetFieldsTranslation; }; /** * The reports custom translation for the current language. */ custom: { label: string; [customKeys: string]: any; }; } export interface FactSheetFieldsTranslation { [fieldName: string]: FieldTranslation; } export interface FieldTranslation { label: string | null; values: Record<string, FieldValueTranslation>; } export interface FieldValueTranslation { label: string | null; } export interface RelationTranslation { label: string | null; fields: Record<string, FieldTranslation>; } export interface ReportSetupCurrency { code: string; symbol: string; } export interface Workspace { id: string; name: string; /** @internal */ type: MtmWorkspaceType; /** @internal */ status: MtmWorkspaceStatus; /** @internal */ contract: { /** @internal */ type: MtmContractType; }; } /** @internal */ export type MtmWorkspaceStatus = 'ACTIVE' | 'BLOCKED'; /** @internal */ export type MtmWorkspaceType = 'LIVE' | 'DEMO' | 'SANDBOX'; /** @internal */ export type MtmContractType = 'REGULAR' | 'TRIAL'; export interface FiscalYears { default?: { /** * Month starting from 0 = Jan, 1 = Feb, ... */ month: number; /** * the day-of-the-month, starting from 1 */ date: number; }; } /** Workspace settings that are stored in MTM */ export interface MtmWorkspaceSettings { fiscalYears?: FiscalYears; } export interface BookmarkFilter { /** * The FactSheet type can be get and set with: * - FacetsService.getSelectedFactSheetTypeFromFilters(facetFilter) * - FacetsService.updateFactSheetTypeInFilters(facetFilter, newFactSheetType) */ fsType?: string; facetFilter: FacetFilter[]; fullTextSearchTerm?: string; factSheetIds?: string[]; sorting?: Sorting[]; } export interface ReportingBookmarkState<T = any> { filters: { [key: string]: BookmarkFilter; }; views: { [context: string]: { activeViewKey?: string; factSheetType?: string; viewOption?: ViewOption; }; }; customState?: T | null; customDropdownSelections?: ReportDropdownSelections; tableConfig?: TableConfig; tableSortings?: Sorting[]; /** * @deprecated */ timeline?: TimelineBookmarkSelection; } export interface ReportSetup { reportId: string; bookmarkName: string; config: ReportSetupConfig; settings: ReportSetupSettings; savedState?: ReportingBookmarkState; } export interface FacetFilter { facetKey: string; keys: string[]; operator?: FacetKeyOperator; dateFilter?: DateFilter; subscriptionFilter?: SubscriptionFilterInput; excludeTransitiveRelations?: boolean; subFilter?: { facetFilters: FacetFilter[]; fullTextSearch?: string; ids?: string[]; }; } export type DateFilterType = 'POINT' | 'TODAY' | 'END_OF_MONTH' | 'END_OF_YEAR' | 'RANGE' | 'RANGE_STARTS' | 'RANGE_ENDS' | 'TIMELINE'; export interface DateFilter { type: DateFilterType; minDate?: string; maxDate?: string; from?: string; to?: string; useTimelineDates?: boolean; } /** Valid GraphQL FacetType; constants defined in facets.const.ts */ export type BackendFacetType = 'SIMPLE' | 'TAG' | 'FACTSHEETTYPE' | 'FACTSHEETSUBTYPE' | 'RELATION' | 'LIFECYCLE' | 'SUBSCRIPTIONS' | 'EXTERNAL_ID' | 'HIERARCHY'; /** Pseudo-FacetTypes implemented only in front-end; constants defined in facets.const.ts */ export type FrontendFacetType = 'FACT_SHEET_ID' | 'FULLTEXTSEARCH' | 'SINGLE_SELECT' | 'UNKNOWN' | 'AGGREGATION'; export type FacetType = BackendFacetType | FrontendFacetType; export enum FacetKeyOperator { OR = "OR", AND = "AND", NOR = "NOR" } interface FacetListEntry { /** * Key that identifies this FacetListEntry. */ key: string; /** * Name of the FacetListEntry */ name: string; /** * Translated label of the FacetListEntry */ label?: string; /** * How many search results can be expected if this * facet list entry is selected. */ count: number; /** * Is this FacetListEntry selected. Default: false. */ selected?: boolean; } export interface FacetGroup { /** * Key of the facet. * For facets of type TAG the facetKey contains the tag's UUID. */ facetKey: string; /** * The logical operation that is set for this facet. */ operator: FacetKeyOperator; /** * List of operators the backend supports for this facet. */ possibleOperators?: string[]; /** * The type of the facet results. * Depending on the type of the results the facet is rendered differently. * 'UNKNOWN' is set when the information from the BE is missing, for example * when the Facet is generated on the fly (in the Bookmarks) */ facetType: FacetType; /** * Might contain additional information depending on the 'facetType'. * For facetType FACTSHEETSUBTYPE: contains the selected Fact Sheet type. * For facetType TAG: contains the facet key. */ facetSubType?: string; /** * List of available entries. */ results: FacetListEntry[]; /** * Subfilter applied to this facet. */ subFilter?: FacetSubfilter; /** * Optional date filter */ dateFilter?: DateFilter; /** * Optional subscription filter */ subscriptionFilter?: SubscriptionFilter; /** * Total number of available results (including the ones from results) */ total?: number; /** * Facet is open; default = true */ open?: boolean; isSelected?: boolean; /** * Facet is visible */ visible?: boolean; /** * Facet is read-only */ readOnly?: boolean; /** * Facet is read-only */ initialValue?: FacetGroupSettingValue; } export interface FacetGroupSettingValue extends FacetFilter { facetKey: string; keys: string[]; operator?: FacetKeyOperator; dateFilter?: DateFilter; subscriptionFilter?: SubscriptionFilter; facetType?: FacetType; } export interface SubscriptionFilter { type: SubscriptionType; role?: SubscriptionRole; } export interface SubscriptionRole { id: string; name: string; description?: string; comment?: string; subscriptionType: SubscriptionType; restrictToFactSheetTypes?: string[]; } export type SubscriptionType = 'RESPONSIBLE' | 'OBSERVER' | 'ACCOUNTABLE'; export interface FacetSubfilter { facetGroups?: FacetGroup[]; facetFilters?: FacetFilter[]; fullTextSearch?: string; ids?: string[]; } export interface SubscriptionFilterInput { type: SubscriptionType; roleId?: string; } export enum CompositeOperator { OR = "OR", AND = "AND" } export interface CompositeFactSheetFilter { group: CompositeGroupFilter; } export interface CompositeGroupFilter { operator: CompositeOperator; elements: SimpleCompositeFilter[]; } export interface SimpleCompositeFilter { filter: CompositeFilter; } export interface CompositeFilter { operator: CompositeOperator; elements: FacetFilter[]; } export type SortingMode = 'BY_FIELD' | 'BY_LIFECYCLE_LAST_PHASE'; export type SortingOrder = 'asc' | 'desc'; export interface Sorting { mode?: SortingMode; key: string; order: SortingOrder; } export interface TableConfig { columns: TableColumn[]; } export interface TableColumn { factSheetType: string; key: string; /** * Field type */ type: DataModelFieldType; virtualKey?: string; /** * Frontend attributes * @type {string} */ sort?: string; required?: boolean; editable?: boolean; sortable?: boolean; align?: TableColumnAlign; resizable?: boolean; movable?: boolean; width?: number; label?: string; expanded?: boolean; isRelationColumn?: boolean; isCustomColumn?: boolean; } export type DataModelFieldType = 'DOUBLE' | 'INTEGER' | 'LIFECYCLE' | 'LOCATION' | 'MULTIPLE_SELECT' | 'SINGLE_SELECT' | 'STRING' | 'EXTERNAL_ID' | 'PROJECT_STATUS' | 'AGGREGATED' | 'READ_ACCESS_CONTROL_LIST' | 'WRITE_ACCESS_CONTROL_LIST' | 'RELATION' | 'TAGS' | 'SUBSCRIPTIONS' | 'DATE_TIME' | 'COMPLETION' | 'QUALITYSEALSTATUS'; export type TableColumnAlign = 'LEFT' | 'RIGHT' | 'CENTER' | 'JUSTIFY'; export interface ReportDropdownSelections { [dropdownId: string]: string; } /** * Configures the reporting table for the report. * It allows to specify the initial attributes * that should be displayed in the table. * * Example: * factSheetType: 'Application', * attributes: ['release', 'alias'], * relatedFactSheetTypes: \{ * BusinessCapability: 'relApplicationToBusinessCapability', * UserGroup: 'relApplicationToUserGroup' * \} */ export interface ReportTableConfig { factSheetType: string; attributes: ReportTableConfigAttribute[]; columns?: TableColumn[]; /** * Maps Fact Sheet type to relation type in order to * add them as subfilter in table view. */ relatedFactSheetTypes?: { [facetsConfigKey: string]: string; }; } /** * Represents a Fact Sheet attribute to be displayed in a table. The attribute can be either the field name, as string, or a table column for more advanced fields. */ export type ReportTableConfigAttribute = string | ReportTableColumn; export interface ReportTableColumn { key: string; label?: string; type: DataModelFieldType; sortable?: boolean; align?: TableColumnAlign; /** A custom column is one that is provided by the report and does not correspond to an existing Fact Sheet attribute */ isCustomColumn?: boolean; virtualKey?: string; } /** * Represents one selectable entry. * * @deprecated Use `DropdownEntry` in the UI configuration instead. */ export interface CustomDropdownEntry { id: string; name: string; /** * This callback is invoked once the user selects the corresponding entry. */ callback?: (currentEntry: CustomDropdownEntry) => void; } /** * Represents a custom dropdown menu with several entries. * * @deprecated Use {@link UIDropdown} in the UI configuration instead. */ export interface CustomDropdown { id: string; name: string; entries: CustomDropdownEntry[]; position?: 'left' | 'right'; initialSelectionEntryId?: string; } /** * Describes the available configuration options for a report. */ export interface ReportConfiguration { /** * Multiple facets configurations ({@link ReportFacetsConfig}) can be provided * in order to allow the user to filter different aspects of your report. */ facets?: ReportFacetsConfig[]; menuActions?: { /** * Does the report provide configuration possibilities. * If true: There will be a configuration action shown to the user, * that triggers __configureCallback__. * * @default false. */ showConfigure?: boolean; /** * This callback is invoked whenever the user wants to see / change * the reports configuration. */ configureCallback?: () => void; /** * Define custom dropdowns that are shown to the user and allow him or her * to select different options that influcene how the report behaves or * presents data. * * @deprecated Use `elements` in the UI configuration instead. */ customDropdowns?: CustomDropdown[]; }; /** * * This callback is invoked whenever the user changes the view of the report. * It is also invoked, once the report view results are loaded during * initialization. * * In order to define which views should be available to the user, you can * specify a Fact Sheet type via {@link ReportConfiguration.reportViewFactSheetType}. */ reportViewCallback?: (view: ViewResult) => void; /** * If defined the views that are applicable for this Fact Sheet type will be * available for the user to be selected from a dropdown. * Whenever the view is fetched from the backend the view data will be * provided via {@link ReportConfiguration.reportViewCallback}. */ reportViewFactSheetType?: string; /** * Additional options that can be provided for the view calculation. */ reportViewOption?: ViewOption; /** * Defines whether the reporting framework should allow the user to switch * into a table view that shows the data of the report. * If not specified the default value is `true`, so the table view will be * allowed if not explicitly disabled. * * Hint: In order to configure the table (e.g. initially visible columns) * for the report use {@link ReportConfiguration.tableConfigCallback} */ allowTableView?: boolean; /** * This callback is invoked one time after the report has been initialised to * get an initial, static configuration for the table. If the configuration is dynamic or * computed asynchronously, {@link LxCustomReportLib.ready} needs to be used instead. */ tableConfigCallback?: () => ReportTableConfig; /** * @deprecated. Use UIButton to show the edit toggle. * * Specifiy whether the user shall be able to edit the report. * If the user toggles the editing mode the reporting framework * calls {@link ReportConfiguration.toggleEditingCallback} to inform * you about enabled or disabled edit mode. */ allowEditing?: boolean; /** * @deprecated. Use UIButton click callback to invoke an action for enable/disable. * * This callback is invoked whenever the user enables or disables editing. * The action to enable or disable editing is only visible when {@link ReportConfiguration.allowEditing} * is set to true. */ toggleEditingCallback?: (editingEnabled: boolean) => void; /** * The export options allow to influence the PDF or image export of a report. */ export?: ReportExportConfiguration; /** * `ui` defines the configuration of the UI elements to be displayed around the report. * * @beta */ ui?: UIConfiguration; } export interface ReportExportConfiguration { /** * Flag to disable export for the given report. * This option hides the export capabilities within the report container. * @default false */ disabled?: boolean; /** * CSS selector which specifies the DOM element whose contents should be * extracted for export to PDF or image. */ exportElementSelector?: string; /** * The type of content that is extracted from the DOM * to be exported. Default is HTML. * * Specify SVG if your report uses SVG elements for visualization. */ inputType?: 'HTML' | 'SVG'; /** * autoScale has been renamed to {@link fitHorizontally} and will be * removed in the near future. * * @default false * @deprecated */ autoScale?: boolean; /** * fitHorizontally scales the content for PDF exports to fit it to the * page width so that no content is cut off. * It should not be enabled if the content is already responsive HTML. * * @default true */ fitHorizontally?: boolean; /** * fitVertically scales the content for PDF exports to fit it to the * page height so that the content fits on a single page. * * @default true */ fitVertically?: boolean; /** * Paper format for PDF exports. * @default 'a4' */ format?: 'a0' | 'a1' | 'a2' | 'a3' | 'a4' | 'letter' | 'autofit'; /** * Paper orientation for PDF exports. * @default 'portrait' */ orientation?: 'portrait' | 'landscape'; /** * Usage of the export. * Determines if the export is triggered for thumbnail creation or from the user. * @default thumbnail */ usage?: 'thumbnail' | 'export'; /** * This callback is invoked just before the report framework extracts the HTML * from the report to export it as PDF or image. It allows to make adjustments * to the HTML for exporting. */ beforeExport?: (exportElement: HTMLElement, reportExportConfig: ReportExportConfiguration) => HTMLElement | Promise<HTMLElement>; } export interface UIMinimalConfiguration { /** * `timeline` defines the timeline UI element. */ timeline?: UITimeline | null; /** * `elements` defines the configuration of each UI element. * */ elements?: UIElements; /** * `showCompositeFilters` flag to show composite filters in the report ui * * @beta */ showCompositeFilters?: boolean; } export interface UIConfiguration extends UIMinimalConfiguration { /** * `update` provides a callback to react to changes from the UI elements. * * It's called when initializing the report's UI elements and whenever the user * interacts with them. * * `selection` is an object that reflects the state of the current selection * of the UI elements. * * `update` also allows modifying the ui configuration by returning the target configuration. Use `null` to * destroy any visible elements. When using an `undefined` value for a specific element, the element remains * untouched. * */ update: (selection: UISelection) => undefined | UIMinimalConfiguration | Promise<UIMinimalConfiguration | undefined>; } /** * `UIElements` defines the configuration needed to allow a report to show certain {@link UIElement} items in the Reports page. */ export interface UIElements { /** * `values` is the collection of values associated to the {@link UIElement} items. */ values: UIElementValues; /** * `root` defines the root structure of the {@link UIElements}. */ root: UIRoot; } /** * `UIRoot` allows to define the root items structure with an optional `style` for basic templating. */ export interface UIRoot { /** * `items` define the collection of {@link UIElement} items to be used. */ items: UIElement[]; /** * `style` allows a certain limited template styling for the `items`. */ style?: UIStyle; } /** * `UIElementValues` defines a key-value collection of values that each {@link UIElement} has assigned. * `UIElementValues` expects as a key the `id` property defined for a given {@link UIElement}. The type of value is * dependent on the type of {@link UIElement} being used. */ export type UIElementValues = Record<string, unknown>; /** * `UIElementType` is a identificator for each type of UI element that is used. */ export type UIElementType = 'container' | 'dropdown' | 'groupDropdown' | 'factSheetDropdown' | 'buttonGroup' | 'button' | 'impactSourcePicker' | 'layoutMode' | 'zoom' | 'hierarchyDepth'; export interface UIBaseElement { id: string; type: UIElementType; } /** * `UIElement` defines the different types of UI elements that are available to be defined in the Reports page. */ export type UIElement = UIContainer | UIDropdown | UIGroupDropdown | UIFactSheetDropdown | UIButtonGroup |