Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
1d26b6f
Setup server plugin
sebelga Jan 5, 2023
0077ce6
Setup core and registry services
sebelga Jan 5, 2023
e1832bb
Add Crud service to access content on storage layer
sebelga Jan 5, 2023
3c254a7
Add event bus and update crud service
sebelga Jan 5, 2023
a6631cf
Use UniqueFields generic to distinguish types
sebelga Jan 9, 2023
0d95aa1
Add RPC layer (public and server)
sebelga Jan 10, 2023
cd775d6
Refactor rpc contract
sebelga Jan 11, 2023
6968b9f
Add demo app in management section
sebelga Jan 11, 2023
ded1f58
Add content preview section to demo
sebelga Jan 11, 2023
ce22f6a
Validate rpc response
sebelga Jan 11, 2023
c3eac8b
Add create content section
sebelga Jan 11, 2023
56aea91
Move api contract to setup() method
sebelga Jan 11, 2023
f0bdb35
Add foo storage demo server side
sebelga Jan 11, 2023
d5150a3
Add create function to RPC
sebelga Jan 11, 2023
331424e
Add SearchIndex service
sebelga Jan 11, 2023
570bc2e
Update search logic
sebelga Jan 12, 2023
fae17a4
Fix TS
sebelga Jan 12, 2023
940d885
[CI] Auto-commit changed files from 'node scripts/ts_project_linter -…
kibanamachine Jan 12, 2023
71e0201
[CI] Auto-commit changed files from 'node scripts/build_plugin_list_d…
kibanamachine Jan 12, 2023
e9a251f
Add search example
sebelga Jan 12, 2023
618f323
Merge branch 'content-management/core-server-poc' of github.com:sebel…
sebelga Jan 12, 2023
6fd19aa
Add "updatedAt" column
sebelga Jan 12, 2023
24542f1
Have separate method for get() and getPreview()
sebelga Jan 12, 2023
25df250
Add content details section
sebelga Jan 12, 2023
8f1d4a9
Expose plugin public api
sebelga Jan 13, 2023
201a508
Serialize content before indexing
sebelga Jan 13, 2023
aacc610
Expose handler to retrieve config from registry
sebelga Jan 13, 2023
3526383
Send request context when creating content
sebelga Jan 13, 2023
7d7edf7
Add ref in tsconfig for demo
sebelga Jan 13, 2023
320bac9
Integrate content management into maps plugin
sebelga Jan 13, 2023
9c84bbb
[CI] Auto-commit changed files from 'node scripts/ts_project_linter -…
kibanamachine Jan 13, 2023
1936e04
Refactor implementation - remove io-ts
sebelga Jan 13, 2023
de6e32d
Update maps impl
sebelga Jan 13, 2023
b0e8f82
Merge branch 'content-management/core-server-poc' of github.com:sebel…
sebelga Jan 13, 2023
6f78cbc
Improve types
sebelga Jan 13, 2023
e3b46c7
Refactor search index serializer
sebelga Jan 13, 2023
ee15565
Require schemas to be provided when registering content
sebelga Jan 13, 2023
9fb4c48
Prepare for in / out rpc validation
sebelga Jan 13, 2023
bbfbe1d
Merge branch 'main' into content-management/core-server-poc
kibanamachine Jan 16, 2023
f81fb9e
Merge remote-tracking branch 'upstream/main' into content-management/…
sebelga Jan 30, 2023
33e39e2
Refactor common RPC
sebelga Feb 1, 2023
dfc59fd
Refactor RPC layer
sebelga Feb 1, 2023
41b9b7b
Refactor "maps" integration
sebelga Feb 1, 2023
985613c
Disable preview and search in demo app
sebelga Feb 1, 2023
4879857
Add "create" procecure
sebelga Feb 1, 2023
2e1d37f
Small refactor
sebelga Feb 1, 2023
1c9b76f
Update rpc validation
sebelga Feb 2, 2023
8c0d7a3
Update map schemas
sebelga Feb 2, 2023
ae3fd28
Export types from core
sebelga Feb 2, 2023
f4a8c0e
Refactor maps integration
sebelga Feb 2, 2023
a06ef45
Update public rpc client
sebelga Feb 2, 2023
eb643e9
Add context to storage layer crud methods
sebelga Feb 2, 2023
093876d
Refactor maps implementation
sebelga Feb 2, 2023
f4d8a9f
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Feb 2, 2023
8e259f6
Disable indexing content when created
sebelga Feb 2, 2023
2f8f216
Merge branch 'content-management/core-server-poc' of github.com:sebel…
sebelga Feb 2, 2023
b8d80ab
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Feb 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/developer/plugin-list.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ as uiSettings within the code.
|Console provides the user with tools for storing and executing requests against Elasticsearch.


|{kib-repo}blob/{branch}/src/plugins/content_management[contentManagement]
|WARNING: Missing README.


|{kib-repo}blob/{branch}/src/plugins/controls/README.mdx[controls]
|The Controls plugin contains Embeddables which can be used to add user-friendly interactivity to apps.

Expand Down
11 changes: 11 additions & 0 deletions src/plugins/content_management/common/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* 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 const PLUGIN_ID = 'contentManagement';

export const API_ENDPOINT = '/api/content_management/rpc';
17 changes: 17 additions & 0 deletions src/plugins/content_management/common/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* 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 { PLUGIN_ID, API_ENDPOINT } from './constants';

export { schemas as rpcSchemas, procedureNames } from './rpc';

export { contentSchema } from './schemas';

export type { GetIn, CreateIn, ProcedureName, ProcedureSchemas } from './rpc';

export type { Ref, Content, InternalFields, CommonFields } from './schemas';
72 changes: 72 additions & 0 deletions src/plugins/content_management/common/rpc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* 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 { schema, Type } from '@kbn/config-schema';

export interface ProcedureSchemas {
in?: Type<any> | false;
out?: Type<any> | false;
}

export const procedureNames = ['get', 'create'] as const;

export type ProcedureName = typeof procedureNames[number];

// ---------------------------------
// API
// ---------------------------------

// ------- GET --------
const getSchemas: ProcedureSchemas = {
in: schema.object(
{
contentType: schema.string(),
id: schema.string(),
options: schema.maybe(schema.object({}, { unknowns: 'allow' })),
},
{ unknowns: 'forbid' }
),
// --> "out" will be specified by each storage layer
out: schema.maybe(schema.object({}, { unknowns: 'allow' })),
};

export interface GetIn<T extends string = string, Options extends object = any> {
id: string;
contentType: T;
options?: Options;
}

// -- Create content
const createSchemas: ProcedureSchemas = {
in: schema.object(
{
contentType: schema.string(),
data: schema.object({}, { unknowns: 'allow' }),
options: schema.maybe(schema.object({}, { unknowns: 'allow' })),
},
{ unknowns: 'forbid' }
),
// Here we could enforce that an "id" field is returned
out: schema.maybe(schema.object({}, { unknowns: 'allow' })),
};

export interface CreateIn<
T extends string = string,
Data extends object = Record<string, unknown>,
Options extends object = any
> {
contentType: T;
data: Data;
options?: Options;
}

export const schemas: {
[key in ProcedureName]: ProcedureSchemas;
} = {
get: getSchemas,
create: createSchemas,
};
69 changes: 69 additions & 0 deletions src/plugins/content_management/common/schemas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* 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 { schema, TypeOf } from '@kbn/config-schema';

/**
* Interface to represent a reference field (allows to populate() content)
*/
export const refSchema = schema.object(
{
$id: schema.string(),
},
{ unknowns: 'forbid' }
);

export type Ref = TypeOf<typeof refSchema>;

/**
* Fields that _all_ content must have (fields editable by the user)
*/
export const commonFieldsProps = {
title: schema.string(),
description: schema.maybe(schema.string()),
};

const commonFieldsSchema = schema.object({ ...commonFieldsProps }, { unknowns: 'forbid' });

export type CommonFields = TypeOf<typeof commonFieldsSchema>;

/**
* Fields that all content must have (fields *not* editable by the user)
*/
const internalFieldsProps = {
id: schema.string(),
type: schema.string(),
meta: schema.object(
{
updatedAt: schema.string(),
createdAt: schema.string(),
updatedBy: refSchema,
createdBy: refSchema,
},
{ unknowns: 'forbid' }
),
};

export const internalFieldsSchema = schema.object(
{ ...internalFieldsProps },
{ unknowns: 'forbid' }
);

export type InternalFields = TypeOf<typeof internalFieldsSchema>;

/**
* Base type for all content (in the search index)
*/
export const contentSchema = schema.object(
{
...internalFieldsProps,
...commonFieldsProps,
},
{ unknowns: 'forbid' }
);

export type Content = TypeOf<typeof contentSchema>;
14 changes: 14 additions & 0 deletions src/plugins/content_management/kibana.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"id": "contentManagement",
"version": "kibana",
"server": true,
"ui": true,
"requiredPlugins": ["management", "esUiShared"],
"requiredBundles": [],
"optionalPlugins": [],
"owner": {
"name": "@elastic/kibana-global-experience",
"githubTeam": "@elastic/kibana-global-experience"
},
"description": "Content management app"
}
41 changes: 41 additions & 0 deletions src/plugins/content_management/public/demo-app/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* 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 React from 'react';
import type { FC } from 'react';
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';

import { EuiSpacer } from '@elastic/eui';
import { CreateContentSection, ContentDetailsSection } from './components';

export const App: FC = () => {
return (
<KibanaPageTemplate panelled>
<KibanaPageTemplate.Header
pageTitle="Content management POC"
description=""
rightSideItems={[<button>Todo</button>]}
/>
<KibanaPageTemplate.Section>
{/* Search */}
{/* <SearchContentSection />
<EuiSpacer size="xl" /> */}

{/* Content details */}
<ContentDetailsSection />
<EuiSpacer size="xl" />

{/* Content preview */}
{/* <ContentPreviewSection />
<EuiSpacer size="xl" /> */}

{/* Create memory content */}
<CreateContentSection />
</KibanaPageTemplate.Section>
</KibanaPageTemplate>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* 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 React, { FC, useState } from 'react';
import useDebounce from 'react-use/lib/useDebounce';
import {
EuiFieldText,
EuiFlexGroup,
EuiFlexItem,
EuiFormRow,
EuiSpacer,
EuiTitle,
} from '@elastic/eui';
import { EuiCodeEditor } from '@kbn/es-ui-shared-plugin/public';

import { useApp } from '../context';

export const ContentDetailsSection: FC = () => {
const { rpc } = useApp();

const [contentType, setContentType] = useState('foo');
const [contentId, setContentId] = useState('');
const [content, setContent] = useState<Record<string, unknown>>({});

const isIdEmpty = contentId.trim() === '';

useDebounce(
() => {
const load = async () => {
const res = await rpc.get({ contentType, id: contentId });
setContent(res as Record<string, unknown>);
};

if (!isIdEmpty) {
load();
}
},
500,
[rpc, contentType, contentId, isIdEmpty]
);

return (
<>
<EuiTitle>
<h2>Content details</h2>
</EuiTitle>
<EuiSpacer />
<EuiFlexGroup>
<EuiFlexItem>
<EuiFormRow label="Type" helpText="The content type" fullWidth>
<EuiFieldText
value={contentType}
onChange={(e) => {
setContentType(e.currentTarget.value);
}}
fullWidth
/>
</EuiFormRow>

<EuiFormRow label="Id" helpText="The content id" fullWidth>
<EuiFieldText
value={contentId}
onChange={(e) => {
setContentId(e.currentTarget.value);
}}
fullWidth
/>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiCodeEditor
value={JSON.stringify(content, null, 4)}
width="100%"
height="500px"
mode="json"
readOnly
wrapEnabled
showPrintMargin={false}
theme="textmate"
editorProps={{ $blockScrolling: true }}
setOptions={{
tabSize: 2,
useSoftTabs: true,
}}
/>
</EuiFlexItem>
</EuiFlexGroup>
</>
);
};
Loading