Skip to content

Commit

Permalink
[Reporting] Add link to Kibana app from Reporting management UI + Des…
Browse files Browse the repository at this point in the history
…ign update (#111412) (#118524)

* moved components to nested components dir

* added health status indicator

* download button -> download link

* updated poblic Job API, remove some of the "rendering" behaviour

* restructure list table contents and clean up use of i18n

* set table column widths

* slight update to table column widths

* actually use action width 🤦

* added view in app link component and included space id in public side Job

* server side changes so that we can get the job payload containing the locator

* initial round of public-side changes to make the link to Kibana app work

* added tooltip to view action

* remove unused import and do not show chrome

* removed use of fp-ts

* added type column and updated mobile look

* remove unused imports

* take a different approach to job query factory -> added new function called "getReport" and leave "get" as is

* update i18n

* code simplifications, also ensure that "PROCESSING" status is being handled by health indicator

* do not hide chrome

* refactor jest test:
 - make test more specific and remove snapshot
 - added use of isMounted() to not run set state when component
   is not mounted

* surface deprecation warning in a special way

* updated one functional test

* updated other functional test

* Several updates to bring table more in line with design
 * Removed "created by" column
 * Added app icons instead of names
 * Added content type indication (PDF, CSV or PNG)
 * Updated the "info" button to have no colors
 * Updated the status to have a timestamp and show "yellow" if
   we detect any issues and guide users to view the report info.

* a lot of changes to bring this more in line with defazio designs

* fix lint

* -wip- [skip-ci]

* some very basic house keeping [skip-ci]

* get to a point where the linking behaviour is working as expected

* further house-keeping, remove unecessary components

* clean up imports

* move hasIssues check into status indicator

* refactored report status indicator

* hide open kibana app button when not available

* remove unused import

* fix jest tests

* created a new redirect plugin to avoid page flicker

* remove unused report info button

* removed unused translations

* fix jest tests after changing the redirect app path

* added reportingRedirect to applicationUsageSchema

* added column width for type

* update test for extracting first row title

* update functional test snapshot

* updated plugins schema

* removed the interstitial page so that we do not conflict with future work planned for the share service

* remove unused i18n

* small, but center-ish type icons

* elastic@ email address

* add i18n, update import with forward slash and added missing ":" to TODO

* move non-type export to own import line and "type" to only-type imports

* remove unecessary export

* refactor payload endpoint to locatorParams endpoint and document query function

* finish refactoring client side to work with new locatorParams endpoint

* remove unused import

* use info endpoint because it contains payload!

* added functional test to ensure that we can navigate back to report

* added jest test for checking that link navigated to is spaces aware

* fix type issue and remove unused import

Co-authored-by: Kibana Machine <[email protected]>

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
jloleysens and kibanamachine authored Nov 15, 2021
1 parent 34021ce commit 140db56
Show file tree
Hide file tree
Showing 43 changed files with 1,114 additions and 11,754 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ export const applicationUsageSchema = {
'observability-overview': commonSchema,
osquery: commonSchema,
security_account: commonSchema,
reportingRedirect: commonSchema,
security_access_agreement: commonSchema,
security_capture_url: commonSchema, // It's a forward app so we'll likely never report it
security_logged_out: commonSchema,
Expand Down
131 changes: 131 additions & 0 deletions src/plugins/telemetry/schema/oss_plugins.json
Original file line number Diff line number Diff line change
Expand Up @@ -4232,6 +4232,137 @@
}
}
},
"reportingRedirect": {
"properties": {
"appId": {
"type": "keyword",
"_meta": {
"description": "The application being tracked"
}
},
"viewId": {
"type": "keyword",
"_meta": {
"description": "Always `main`"
}
},
"clicks_total": {
"type": "long",
"_meta": {
"description": "General number of clicks in the application since we started counting them"
}
},
"clicks_7_days": {
"type": "long",
"_meta": {
"description": "General number of clicks in the application over the last 7 days"
}
},
"clicks_30_days": {
"type": "long",
"_meta": {
"description": "General number of clicks in the application over the last 30 days"
}
},
"clicks_90_days": {
"type": "long",
"_meta": {
"description": "General number of clicks in the application over the last 90 days"
}
},
"minutes_on_screen_total": {
"type": "float",
"_meta": {
"description": "Minutes the application is active and on-screen since we started counting them."
}
},
"minutes_on_screen_7_days": {
"type": "float",
"_meta": {
"description": "Minutes the application is active and on-screen over the last 7 days"
}
},
"minutes_on_screen_30_days": {
"type": "float",
"_meta": {
"description": "Minutes the application is active and on-screen over the last 30 days"
}
},
"minutes_on_screen_90_days": {
"type": "float",
"_meta": {
"description": "Minutes the application is active and on-screen over the last 90 days"
}
},
"views": {
"type": "array",
"items": {
"properties": {
"appId": {
"type": "keyword",
"_meta": {
"description": "The application being tracked"
}
},
"viewId": {
"type": "keyword",
"_meta": {
"description": "The application view being tracked"
}
},
"clicks_total": {
"type": "long",
"_meta": {
"description": "General number of clicks in the application sub view since we started counting them"
}
},
"clicks_7_days": {
"type": "long",
"_meta": {
"description": "General number of clicks in the active application sub view over the last 7 days"
}
},
"clicks_30_days": {
"type": "long",
"_meta": {
"description": "General number of clicks in the active application sub view over the last 30 days"
}
},
"clicks_90_days": {
"type": "long",
"_meta": {
"description": "General number of clicks in the active application sub view over the last 90 days"
}
},
"minutes_on_screen_total": {
"type": "float",
"_meta": {
"description": "Minutes the application sub view is active and on-screen since we started counting them."
}
},
"minutes_on_screen_7_days": {
"type": "float",
"_meta": {
"description": "Minutes the application is active and on-screen active application sub view over the last 7 days"
}
},
"minutes_on_screen_30_days": {
"type": "float",
"_meta": {
"description": "Minutes the application is active and on-screen active application sub view over the last 30 days"
}
},
"minutes_on_screen_90_days": {
"type": "float",
"_meta": {
"description": "Minutes the application is active and on-screen active application sub view over the last 90 days"
}
}
}
}
}
}
},
"security_access_agreement": {
"properties": {
"appId": {
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/reporting/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export const REPORTING_REDIRECT_LOCATOR_STORE_KEY = '__REPORTING_REDIRECT_LOCATO
* be injected to the page
*/
export const getRedirectAppPath = () => {
return '/app/management/insightsAndAlerting/reporting/r';
return '/app/reportingRedirect';
};

// Statuses
Expand Down
25 changes: 25 additions & 0 deletions x-pack/plugins/reporting/common/job_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,32 @@
* 2.0.
*/

import {
CSV_JOB_TYPE,
PDF_JOB_TYPE,
PNG_JOB_TYPE,
PDF_JOB_TYPE_V2,
PNG_JOB_TYPE_V2,
CSV_JOB_TYPE_DEPRECATED,
} from './constants';

// TODO: Remove this code once everyone is using the new PDF format, then we can also remove the legacy
// export type entirely
export const isJobV2Params = ({ sharingData }: { sharingData: Record<string, unknown> }): boolean =>
sharingData.locatorParams != null;

export const prettyPrintJobType = (type: string) => {
switch (type) {
case PDF_JOB_TYPE:
case PDF_JOB_TYPE_V2:
return 'PDF';
case CSV_JOB_TYPE:
case CSV_JOB_TYPE_DEPRECATED:
return 'CSV';
case PNG_JOB_TYPE:
case PNG_JOB_TYPE_V2:
return 'PNG';
default:
return type;
}
};
11 changes: 11 additions & 0 deletions x-pack/plugins/reporting/common/types/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import type { Ensure, SerializableRecord } from '@kbn/utility-types';
import type { LayoutParams } from './layout';
import { LocatorParams } from './url';

export type JobId = string;

Expand All @@ -21,9 +22,19 @@ export type BaseParams = Ensure<
SerializableRecord
>;

export type BaseParamsV2 = BaseParams & {
locatorParams: LocatorParams[];
};

// base params decorated with encrypted headers that come into runJob functions
export interface BasePayload extends BaseParams {
headers: string;
spaceId?: string;
isDeprecated?: boolean;
}

export interface BasePayloadV2 extends BaseParamsV2 {
headers: string;
spaceId?: string;
isDeprecated?: boolean;
}
4 changes: 2 additions & 2 deletions x-pack/plugins/reporting/common/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
*/

import type { Size, LayoutParams } from './layout';
import type { JobId, BaseParams, BasePayload } from './base';
import type { JobId, BaseParams, BaseParamsV2, BasePayload, BasePayloadV2 } from './base';

export type { JobId, BaseParams, BasePayload };
export type { JobId, BaseParams, BaseParamsV2, BasePayload, BasePayloadV2 };
export type { Size, LayoutParams };
export type {
DownloadReportFn,
Expand Down
4 changes: 1 addition & 3 deletions x-pack/plugins/reporting/common/types/url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ export type DownloadReportFn = (jobId: JobId) => DownloadLink;
type ManagementLink = string;
export type ManagementLinkFn = () => ManagementLink;

export interface LocatorParams<
P extends SerializableRecord = SerializableRecord & { forceNow?: string }
> {
export interface LocatorParams<P extends SerializableRecord = SerializableRecord> {
id: string;
version: string;
params: P;
Expand Down
8 changes: 0 additions & 8 deletions x-pack/plugins/reporting/public/constants.ts

This file was deleted.

48 changes: 41 additions & 7 deletions x-pack/plugins/reporting/public/lib/job.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import moment from 'moment';
import React from 'react';
import { JOB_STATUSES } from '../../common/constants';
import {
BaseParamsV2,
JobId,
ReportApiJSON,
ReportOutput,
Expand All @@ -34,6 +35,7 @@ export class Job {
public objectType: ReportPayload['objectType'];
public title: ReportPayload['title'];
public isDeprecated: ReportPayload['isDeprecated'];
public spaceId: ReportPayload['spaceId'];
public browserTimezone?: ReportPayload['browserTimezone'];
public layout: ReportPayload['layout'];

Expand All @@ -57,6 +59,8 @@ export class Job {
public max_size_reached?: TaskRunResult['max_size_reached'];
public warnings?: TaskRunResult['warnings'];

public locatorParams?: BaseParamsV2['locatorParams'];

constructor(report: ReportApiJSON) {
this.id = report.id;
this.index = report.index;
Expand All @@ -82,9 +86,11 @@ export class Job {
this.content_type = report.output?.content_type;

this.isDeprecated = report.payload.isDeprecated || false;
this.spaceId = report.payload.spaceId;
this.csv_contains_formulas = report.output?.csv_contains_formulas;
this.max_size_reached = report.output?.max_size_reached;
this.warnings = report.output?.warnings;
this.locatorParams = (report.payload as BaseParamsV2).locatorParams;
}

getStatusMessage() {
Expand Down Expand Up @@ -167,6 +173,25 @@ export class Job {
);
}

/**
* Returns a user friendly version of the report job creation date
*/
getCreatedAtDate(): string {
return this.formatDate(this.created_at);
}

/**
* Returns a user friendly version of the user that created the report job
*/
getCreatedBy(): string {
return (
this.created_by ||
i18n.translate('xpack.reporting.jobCreatedBy.unknownUserPlaceholderText', {
defaultMessage: 'Unknown',
})
);
}

getCreatedAtLabel() {
if (this.created_by) {
return (
Expand All @@ -191,15 +216,20 @@ export class Job {
}
}

getDeprecatedMessage(): undefined | string {
if (this.isDeprecated) {
return i18n.translate('xpack.reporting.jobWarning.exportTypeDeprecated', {
defaultMessage:
'This is a deprecated export type. Automation of this report will need to be re-created for compatibility with future versions of Kibana.',
});
}
}

getWarnings() {
const warnings: string[] = [];
if (this.isDeprecated) {
warnings.push(
i18n.translate('xpack.reporting.jobWarning.exportTypeDeprecated', {
defaultMessage:
'This is a deprecated export type. Automation of this report will need to be re-created for compatibility with future versions of Kibana.',
})
);
const deprecatedMessage = this.getDeprecatedMessage();
if (deprecatedMessage) {
warnings.push(deprecatedMessage);
}

if (this.csv_contains_formulas) {
Expand Down Expand Up @@ -234,6 +264,10 @@ export class Job {
}
}

getPrettyStatusTimestamp() {
return this.formatDate(this.getStatusTimestamp());
}

private formatDate(timestamp: string) {
try {
return moment(timestamp).format('YYYY-MM-DD @ hh:mm A');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import { stringify } from 'query-string';
import rison from 'rison-node';
import type { HttpFetchQuery } from 'src/core/public';
import { HttpSetup, IUiSettingsClient } from 'src/core/public';
import { buildKibanaPath } from '../../../common/build_kibana_path';
import {
API_BASE_GENERATE,
API_BASE_URL,
API_GENERATE_IMMEDIATE,
API_LIST_URL,
API_MIGRATE_ILM_POLICY_URL,
getRedirectAppPath,
REPORTING_MANAGEMENT_HOME,
} from '../../../common/constants';
import {
Expand Down Expand Up @@ -73,6 +75,19 @@ export class ReportingAPIClient implements IReportingAPI {
private kibanaVersion: string
) {}

public getKibanaAppHref(job: Job): string {
const searchParams = stringify({ jobId: job.id });

const path = buildKibanaPath({
basePath: this.http.basePath.serverBasePath,
spaceId: job.spaceId,
appPath: getRedirectAppPath(),
});

const href = `${path}?${searchParams}`;
return href;
}

public getReportURL(jobId: string) {
const apiBaseUrl = this.http.basePath.prepend(API_LIST_URL);
const downloadLink = `${apiBaseUrl}/download/${jobId}`;
Expand Down
Loading

0 comments on commit 140db56

Please sign in to comment.