import { EventEmitter } from '@angular/core'; import { AdHocReportingAPI } from '@core/typings/api/ad-hoc-reporting.typing'; import { AdHocReportingUI } from '@core/typings/ui/ad-hoc-reporting.typing'; import { AudienceMember } from '@features/audience/audience.typing'; import { FormTypes } from '@features/configure-forms/form.typing'; import { RootObjectNames } from '@features/reporting/services/ad-hoc-reporting-definitions.service'; import { AdvancedFilterGroup, ColumnFilterRow, SkeletonDisplayConfig, SkeletonItemType, SwitchState, TableDataFactory } from '@yourcause/common'; import { GridsterItem } from 'angular-gridster2'; import { ChartDataset as IChartDataSet, ChartOptions, ChartType, Color } from 'chart.js'; export enum ManageWidgetTabs { DETAILS = 1, DATA = 2, FILTERS = 3, DRILLDOWN = 4 } export const DEFAULT_OBJECT = 'application'; export const DEFAULT_AGGREGATE_COLUMN = 'application.id'; export const DEFAULT_CHART_TYPE = 'bar'; export const DEFAULT_MAX_GROUPS = 20; export const DEFAULT_LEGEND_LOCATION = 'bottom'; export const DEFAULT_AGGREGATION_TYPE = AdHocReportingAPI.ChartAggregateType.Count; export const DEFAULT_ROWS_PER_PAGE = 10; export namespace Dashboards { export interface WidgetSourceConfig { name: string; // ex. sum of amount requested by program by country description: string; // ex. Used for seeing which programs are reaching each country type: WidgetType; // ex. 'bar' object: O; // ex. 'application' groupColumn: string; // 'programId' maxGroups: number; subGroupColumn: string; // 'nonprofit.country' aggregationType: A; // 'sum' aggregateColumn: string; // 'amountRequested' filters: ColumnFilterRow[]; legendLocation?: 'bottom'|'top'|'left'|'right'; sortColumn: string; sortAscending: boolean; xAxisLabel: string; yAxisLabel: string; drilldownColumns?: AdHocReportingUI.ColumnImplementation[]; rowsPerPage?: number; hasMaxRows?: boolean; maxRows?: number; summaryRecordId: number; } export type WidgetType = ChartType|'stat'|'table'; export interface ChartClickEvent { chart: GCDashboards.WidgetConfig; values: { display: string; value: any; }[]; groupDisplay: string; groupValue: string|number|boolean|symbol; subGroupDisplay: string; subGroupValue: string|number|boolean; } export interface DashboardWidget { grid: GridsterItem; chartData: GCDashboards.ChartDataSet[]; chartOptions?: ChartOptions; aggregationType?: AdHocReportingAPI.ChartAggregateType; labels: string[]; chartType: WidgetType; colors: Color[]; filters: ColumnFilterRow[]; onElementClick: EventEmitter; tableDataFactory?: TableDataFactory; drilldownColumns?: AdHocReportingUI.ColumnImplementation[]; object: RootObjectNames; formatAsCurrency: boolean; rowsPerPage: number; } } export namespace GCDashboards { export interface ChartDataResult { label: string; subLabel: string; subValue: any; xValue: any; yValue: number; count: number; } export enum DashboardTypes { CUSTOM = 1, MY_WORKSPACE = 2 } export interface DashboardTab { dashboardId: number; name: string; order: number; dashboardType: DashboardTypes; createdDate: string; createdBy: number; updatedBy: number; isDashboardOwner: boolean; numberOfUsersSharedWith: number; createdByFirstName: string; createdByLastName: string; isActive: boolean; isHidden: boolean; aliasRoute?: string|number; // we will use this for 'my-workspace' route instaed of the dashboardId isStandardDashboardPublished?: boolean; } export interface DashboardSharedUserInfo { userId: number; firstName: string; lastName: string; email: string; isDashboardOwner: boolean; } export interface SharedDashboardModalResult { removals: AudienceMember[]; changes: AudienceMember[]; } export interface ClientUserToSharePayload { sharedToUserId: number; isDashboardOwner: boolean; } export interface ShareDashboardUserPayload { dashboardId: number; usersToShareWith: ClientUserToSharePayload[]; } export interface RevokeDashboardUserPayload { dashboardId: number; userIdsToRevoke: number[]; } export interface DashboardDetail { name: string; order: number; widgets: WidgetConfigFromApi[]; } export interface DashboardDetailForUI { name: string; order: number; widgets: WidgetConfigFromApi[]; oldWidgets: WidgetConfigFromApi[]; lastRefreshDate?: string; } export type ChartResultData = AdHocReportingUI.ReportResponseRow & { formGroupingAttribute1: string; formGroupingAttribute2: string; referenceFieldGroupingAttribute1: string; referenceFieldGroupingAttribute2: string; }; export interface ChartResult { data: ChartResultData; aggregate: number; count: number; } export interface Widget extends Dashboards.DashboardWidget { id: number; name: string; description: string; } export interface CreateWidgetPayload { widget: AdHocReportingAPI.CreateChartPayload; dashboardId: number; } export interface UpdateWidgetPayload { id: number; formIds: number[]; userSavedReportColumns: AdHocReportingAPI.UserSavedReportColumn[]; name: string; description: string; reportModelType: AdHocReportingAPI.AdHocReportModelType; reportType: AdHocReportingAPI.AdHocReportType; chartType: AdHocReportingAPI.ChartType; chartConfig: string; chartMaxRows: number; chartIncludeOtherAggregate: boolean; primaryFormId?: number; } export type ChartConfig = Dashboards.WidgetSourceConfig; export interface WidgetConfig extends ChartConfig { id?: number; x?: number; y?: number; height?: number; width?: number; customForms?: number[]; primaryFormId?: number; advancedFilters?: AdvancedFilterGroup[]; useAnd?: SwitchState; } export interface SimpleWidgetConfig { id: number; name: string; description: string; reportModelType: AdHocReportingAPI.AdHocReportModelType; reportType: AdHocReportingAPI.AdHocReportType; chartType: AdHocReportingAPI.ChartType; chartConfig: string; type: Dashboards.WidgetType; object: RootObjectNames; } export type ChartDataSet = IChartDataSet&{ formats: (AdHocReportingUI.NumberFormats|'currency')[]; value: string|number|boolean; counts: number[]; }; export interface ChartDataReturn { labels: { display: string; value: any; color: string }[]; data: ChartDataSet[]; } export interface SimpleWidgetConfigFromApi { id: number; name: string; description: string; othersMayModify: boolean; othersMayView: boolean; reportModelType: AdHocReportingAPI.AdHocReportModelType; reportType: AdHocReportingAPI.AdHocReportType; chartType: AdHocReportingAPI.ChartType; chartConfig: string; } export interface WidgetConfigFromApi { id: number; userSavedReportColumns: AdHocReportingAPI.UserSavedReportColumn[]; name: string; description: string; othersMayModify: boolean; othersMayView: boolean; reportModelType: AdHocReportingAPI.AdHocReportModelType; reportType: AdHocReportingAPI.AdHocReportType; chartType: AdHocReportingAPI.ChartType; chartConfig: string; forms: WidgetForm[]; chartMaxRows: number; // this is actually maxGroups to us chartIncludeOtherAggregate: boolean; primaryFormId?: number; advancedFilterColumns: AdHocReportingAPI.AdvancedUserSavedFilterColumn[][]; useLogicalOperatorAnd: boolean; } export interface WidgetForm { id: number; name: string; description: string; currentRevisionId: number; formType: FormTypes; formDefinition: number; } interface DataPoint { value: number; label: string; } interface SplitDataPoint { values: DataPoint[]; label: string; } export interface SampleDataForWidget { id: number; data: SplitDataPoint[]; config: WidgetConfig; type: Dashboards.WidgetType; } export interface SimpleColumn { columnNameOverride: string; column: string; } export interface PreviewDataPayload { paginationOptions: AdHocReportingAPI.AdvancedPaginationOptionsModel; userSavedReportColumnList: AdHocReportingAPI.UserSavedReportColumn[]; formIds: number[]; chartMaxRows: number; chartIncludeOtherAggregate: boolean; referenceFieldIds: number[]; primaryFormId?: number; } export enum UnsavedChangesResponse { STAY = 1, SAVE_AND_LEAVE = 2 } export interface DashboardDataResults { results: GCDashboards.ChartResult[]; lastRefreshDate: string; otherAggregate: number; otherCount: number; } export const BarChartSkeleton: SkeletonDisplayConfig = { justifyContent: 'space-evenly', height: '100%', width: '100%', skeletonItemType: SkeletonItemType.CONTAINER, extraStyling: { display: 'flex', 'flex-direction': 'column' }, childElements: [{ skeletonItemType: SkeletonItemType.BASIC_BLOCK, height: '5%', width: '75%', extraStyling: { padding: '1%', 'align-self': 'center' } }, { skeletonItemType: SkeletonItemType.CONTAINER, justifyContent: 'start', height: '80%', width: '100%', childElements: [{ skeletonItemType: SkeletonItemType.BASIC_BLOCK, height: '100%', width: '2rem', extraStyling: { margin: '1rem' } }, { skeletonItemType: SkeletonItemType.BASIC_BLOCK, height: '50%', width: '2rem', extraStyling: { margin: '1rem' } }, { skeletonItemType: SkeletonItemType.BASIC_BLOCK, height: '25%', width: '2rem', extraStyling: { margin: '1rem' } }], extraStyling: { display: 'flex', 'align-items': 'end' } }, { skeletonItemType: SkeletonItemType.BASIC_BLOCK, height: '8%', width: '75%', extraStyling: { padding: '1%', 'align-self': 'center' } }] }; export const StatSkeleton: SkeletonDisplayConfig = { childElements: [{ skeletonItemType: SkeletonItemType.BASIC_BLOCK, height: '3rem', width: '100%', extraStyling: { 'margin-bottom': '1rem' } }, { skeletonItemType: SkeletonItemType.BASIC_BLOCK, height: '1.5rem', width: '75%', extraStyling: { 'margin-bottom': '1rem' } }], justifyContent: 'center', height: '100%', width: '100%', extraStyling: { display: 'flex', 'align-items': 'center', 'flex-direction': 'column' }, skeletonItemType: SkeletonItemType.CONTAINER }; export const DashboardTableSkeleton: SkeletonDisplayConfig = { justifyContent: 'center', height: '100%', width: '100%', extraStyling: { display: 'flex', 'align-items': 'center', 'flex-direction': 'column' }, skeletonItemType: SkeletonItemType.CONTAINER, childElements: [{ skeletonItemType: SkeletonItemType.BASIC_BLOCK, height: '1rem', width: '75%', extraStyling: { 'margin-bottom': '1rem' } }, { skeletonItemType: SkeletonItemType.CONTAINER, height: '15rem', width: '100%', justifyContent: 'start', extraStyling: { 'flex-direction': 'column' }, childElements: Array(5).fill({ skeletonItemType: SkeletonItemType.BASIC_BLOCK, width: '100%', height: '2rem', extraStyling: { 'margin-bottom': '.5rem' } }) }] }; }