Skip to content

Commit

Permalink
dashboard views
Browse files Browse the repository at this point in the history
  • Loading branch information
Dosant committed Aug 21, 2024
1 parent 8b7de03 commit 2238ac4
Show file tree
Hide file tree
Showing 61 changed files with 1,172 additions and 175 deletions.
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ packages/kbn-config-mocks @elastic/kibana-core
packages/kbn-config-schema @elastic/kibana-core
src/plugins/console @elastic/kibana-management
packages/content-management/content_editor @elastic/appex-sharedux
packages/content-management/content_insights/content_insights_public @elastic/appex-sharedux
packages/content-management/content_insights/content_insights_server @elastic/appex-sharedux
examples/content_management_examples @elastic/appex-sharedux
packages/content-management/favorites/favorites_public @elastic/appex-sharedux
packages/content-management/favorites/favorites_server @elastic/appex-sharedux
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@
"@kbn/config-schema": "link:packages/kbn-config-schema",
"@kbn/console-plugin": "link:src/plugins/console",
"@kbn/content-management-content-editor": "link:packages/content-management/content_editor",
"@kbn/content-management-content-insights-public": "link:packages/content-management/content_insights/content_insights_public",
"@kbn/content-management-content-insights-server": "link:packages/content-management/content_insights/content_insights_server",
"@kbn/content-management-examples-plugin": "link:examples/content_management_examples",
"@kbn/content-management-favorites-public": "link:packages/content-management/favorites/favorites_public",
"@kbn/content-management-favorites-server": "link:packages/content-management/favorites/favorites_server",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import type { Item } from '../types';
import { MetadataForm } from './metadata_form';
import { useMetadataForm } from './use_metadata_form';
import type { CustomValidators } from './use_metadata_form';
import { ActivityView } from './activity_view';

const getI18nTexts = ({ entityName }: { entityName: string }) => ({
saveButtonLabel: i18n.translate('contentManagement.contentEditor.saveButtonLabel', {
Expand Down Expand Up @@ -56,7 +55,7 @@ export interface Props {
}) => Promise<void>;
customValidators?: CustomValidators;
onCancel: () => void;
showActivityView?: boolean;
appendRows?: React.ReactNode;
}

const capitalize = (str: string) => `${str.charAt(0).toLocaleUpperCase()}${str.substring(1)}`;
Expand All @@ -70,7 +69,7 @@ export const ContentEditorFlyoutContent: FC<Props> = ({
onSave,
onCancel,
customValidators,
showActivityView,
appendRows,
}) => {
const { euiTheme } = useEuiTheme();
const [isSubmitting, setIsSubmitting] = useState(false);
Expand Down Expand Up @@ -151,7 +150,7 @@ export const ContentEditorFlyoutContent: FC<Props> = ({
TagList={TagList}
TagSelector={TagSelector}
>
{showActivityView && <ActivityView item={item} />}
{appendRows}
</MetadataForm>
</EuiFlyoutBody>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type CommonProps = Pick<
| 'onCancel'
| 'entityName'
| 'customValidators'
| 'showActivityView'
| 'appendRows'
>;

export type Props = CommonProps;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,30 @@
* Side Public License, v 1.
*/

import React, { useState, useCallback, useEffect } from 'react';
import { EuiFlyoutHeader, EuiFlyoutBody, EuiFlyoutFooter } from '@elastic/eui';
import React from 'react';
import { EuiFlyoutBody, EuiFlyoutFooter, EuiFlyoutHeader } from '@elastic/eui';
import type { Props } from './editor_flyout_content_container';

export const ContentEditorLoader: React.FC<Props> = (props) => {
const [Editor, setEditor] = useState<React.ComponentType<Props> | null>(null);

const loadEditor = useCallback(async () => {
const { ContentEditorFlyoutContentContainer } = await import(
'./editor_flyout_content_container'
);
setEditor(() => ContentEditorFlyoutContentContainer);
}, []);
const ContentEditorFlyoutContentContainer = React.lazy(() =>
import('./editor_flyout_content_container').then(
({ ContentEditorFlyoutContentContainer: _ContentEditorFlyoutContentContainer }) => ({
default: _ContentEditorFlyoutContentContainer,
})
)
);

useEffect(() => {
// On mount: load the editor asynchronously
loadEditor();
}, [loadEditor]);

return Editor ? (
<Editor {...props} />
) : (
<>
<EuiFlyoutHeader />
<EuiFlyoutBody />
<EuiFlyoutFooter />
</>
export const ContentEditorLoader: React.FC<Props> = (props) => {
return (
<React.Suspense
fallback={
<>
<EuiFlyoutHeader />
<EuiFlyoutBody />
<EuiFlyoutFooter />
</>
}
>
<ContentEditorFlyoutContentContainer {...props} />
</React.Suspense>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -262,22 +262,5 @@ describe('<ContentEditorFlyoutContent />', () => {
tags: ['id-3', 'id-4'], // New selection
});
});

test('should render activity view', async () => {
await act(async () => {
testBed = await setup({ showActivityView: true });
});
const { find, component } = testBed!;

expect(find('activityView').exists()).toBe(true);
expect(find('activityView.createdByCard').exists()).toBe(true);
expect(find('activityView.updatedByCard').exists()).toBe(false);

testBed.setProps({
item: { ...savedObjectItem, updatedAt: '2021-01-01T00:00:00Z' },
});
component.update();
expect(find('activityView.updatedByCard').exists()).toBe(true);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export type OpenContentEditorParams = Pick<
| 'readonlyReason'
| 'entityName'
| 'customValidators'
| 'showActivityView'
| 'appendRows'
>;

export function useOpenContentEditor() {
Expand Down
1 change: 0 additions & 1 deletion packages/content-management/content_editor/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
"@kbn/test-jest-helpers",
"@kbn/react-kibana-mount",
"@kbn/content-management-user-profiles",
"@kbn/user-profile-components"
],
"exclude": [
"target/**/*"
Expand Down
64 changes: 64 additions & 0 deletions packages/content-management/content_insights/README.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
id: sharedUX/ContentInsights
slug: /shared-ux/content-insights
title: Content Insights
description: A set of Content Management services and component to provide insights on the content of Kibana.
tags: ['shared-ux', 'component']
date: 2024-08-06
---

## Description

The Content Insights is a set of Content Management services and components to provide insights on the content of Kibana.
Currently, it allows to track the usage of your content and display the stats of it.

- The service can count the following events:
- `viewed`
- It provides the api for registering the routes to increase the count and to get the stats.
- It provides the client to increase the count and to get the stats.
- It provides a flyout and a component to display the stats as a total count and a weekly chart.
- Internally it uses the usage collection plugin to store and search the data.

## API

// server side

```ts
import { registerContentInsights } from '@kbn/content-management-content-insights-server';

if (plugins.usageCollection) {
// Registers routes for tracking and fetching dashboard views
registerContentInsights(
{
usageCollection: plugins.usageCollection,
http: core.http,
getStartServices: () =>
core.getStartServices().then(([_, start]) => ({
usageCollection: start.usageCollection!,
})),
},
{
domainId: 'dashboard',
// makes sure that only users with read/all access to dashboard app can access the routes
routeTags: ['access:dashboardUsageStats'],
}
);
}
```

// client side

```ts
import { ContentInsightsClient } from '@kbn/content-management-content-insights-public';

const contentInsightsClient = new ContentInsightsClient(
{ http: params.coreStart.http },
{ domainId: 'dashboard' }
);

contentInsightsClient.track(dashboardId, 'viewed');

// wrap component in `ContentInsightsProvider` and use the hook to open an insights flyout
const openInsightsFlyout = useOpenInsightsFlyout();
openInsightsFlyout({ item });
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# @kbn/content-management-content-insights-public

Refer to [README](../README.mdx)
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

export {
ContentInsightsProvider,
type ContentInsightsServices,
useServices as useContentInsightsServices,
} from './src/services';

export {
type ContentInsightsClientPublic,
ContentInsightsClient,
type ContentInsightsEventTypes,
} from './src/client';

export { ActivityView, ViewsStats, type ActivityViewProps } from './src/components';
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

module.exports = {
preset: '@kbn/test',
rootDir: '../../../..',
roots: ['<rootDir>/packages/content-management/content_insights/content_insights_public'],
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"type": "shared-browser",
"id": "@kbn/content-management-content-insights-public",
"owner": "@elastic/appex-sharedux"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "@kbn/content-management-content-insights-public",
"private": true,
"version": "1.0.0",
"license": "SSPL-1.0 OR Elastic License 2.0"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import type { HttpStart } from '@kbn/core-http-browser';
import type {
ContentInsightsStats,
ContentInsightsStatsResponse,
} from '@kbn/content-management-content-insights-server';

export type ContentInsightsEventTypes = 'viewed';

/**
* Public interface of the Content Management Insights service.
*/
export interface ContentInsightsClientPublic {
track(id: string, eventType: ContentInsightsEventTypes): void;
getStats(id: string, eventType: ContentInsightsEventTypes): Promise<ContentInsightsStats>;
}

/**
* Client for the Content Management Insights service.
*/
export class ContentInsightsClient implements ContentInsightsClientPublic {
constructor(
private readonly deps: { http: HttpStart },
private readonly config: { domainId: string }
) {}

track(id: string, eventType: ContentInsightsEventTypes) {
this.deps.http
.post(`/internal/content_management/insights/${this.config.domainId}/${id}/${eventType}`)
.catch((e) => {
// eslint-disable-next-line no-console
console.warn(`Could not track ${eventType} event for ${id}`, e);
});
}

async getStats(id: string, eventType: ContentInsightsEventTypes) {
return this.deps.http
.get<ContentInsightsStatsResponse>(
`/internal/content_management/insights/${this.config.domainId}/${id}/${eventType}/stats`
)
.then((response) => response.result);
}
}
Loading

0 comments on commit 2238ac4

Please sign in to comment.