Skip to content

Commit f31740b

Browse files
[7.x] [pre-req] New Component Layout proposal (#72385) (#72789)
* New Component Layout proposal * Add contribution guidelines; remove dead i18n * Re-adding i18n... ugh * Fix i18n files to reflect changes * Addressing feedback * Fix merge issue Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
1 parent e389968 commit f31740b

File tree

17 files changed

+1334
-474
lines changed

17 files changed

+1334
-474
lines changed
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Contributing to Canvas
2+
3+
Canvas is a plugin for Kibana, therefore its [contribution guidelines](../../../CONTRIBUTING.md) apply to Canvas development, as well. This document contains Canvas-specific guidelines that extend from the Kibana guidelines.
4+
5+
- [Active Migrations](#active_migrations)
6+
- [i18n](#i18n)
7+
- [Component Code Structure](#component_code_structure)
8+
- [Storybook](#storybook)
9+
10+
## Active Migrations
11+
12+
When editing code in Canvas, be aware of the following active migrations, (generally, taken when a file is touched):
13+
14+
- Convert file(s) to Typescript.
15+
- Convert React classes to Functional components, (where applicable).
16+
- Add Storybook stories for components, (and thus Storyshots).
17+
- Remove `recompose` in favor of React hooks.
18+
- Apply improved component structure.
19+
- Write tests.
20+
21+
## i18n
22+
23+
i18n syntax in Kibana can be a bit verbose in code:
24+
25+
```js
26+
i18n('pluginNamespace.messageId', {
27+
defaultMessage: 'Default message string literal, {key}',
28+
values: {
29+
key: 'value',
30+
},
31+
description: 'Message context or description',
32+
});
33+
```
34+
35+
To keep the code terse, Canvas uses i18n "dictionaries": abstracted, static singletons of accessor methods which return a given string:
36+
37+
```js
38+
39+
// i18n/components.ts
40+
export const ComponentStrings = {
41+
// ...
42+
AssetManager: {
43+
getCopyAssetMessage: (id: string) =>
44+
i18n.translate('xpack.canvas.assetModal.copyAssetMessage', {
45+
defaultMessage: `Copied '{id}' to clipboard`,
46+
values: {
47+
id,
48+
},
49+
}),
50+
// ...
51+
},
52+
// ...
53+
};
54+
55+
// asset_manager.tsx
56+
import { ComponentStrings } from '../../../i18n';
57+
const { AssetManager: strings } = ComponentStrings;
58+
59+
const text = (
60+
<EuiText>
61+
{strings.getSpaceUsedText(percentageUsed)}
62+
</EuiText>
63+
);
64+
65+
```
66+
67+
These singletons can then be changed at will, as well as audited for unused methods, (and therefore unused i18n strings).
68+
69+
## Component Code Structure
70+
71+
Canvas uses Redux. Component code is divided into React components and Redux containers. This way, components can be reused, their containers can be edited, and both can be tested independently.
72+
73+
Canvas is actively migrating to a structure which uses the `index.ts` file as a thin exporting index, rather than functional code:
74+
75+
```
76+
- components
77+
- foo <- directory representing the component
78+
- foo.ts <- redux container
79+
- foo.component.tsx <- react component
80+
- foo.scss
81+
- index.ts <- thin exporting index, (no redux)
82+
- bar <- directory representing the component
83+
- bar.ts
84+
- bar.component.tsx
85+
- bar.scss
86+
- bar_dep.ts <- redux sub container
87+
- bar_dep.component.tsx <- sub component
88+
- index.ts
89+
```
90+
91+
The exporting file would be:
92+
93+
```
94+
export { Foo } from './foo';
95+
export { Foo as FooComponent } from './foo.component';
96+
```
97+
98+
### Why?
99+
100+
Canvas has been using an "index-export" structure that has served it well, until recently. In this structure, the `index.ts` file serves as the primary export of the Redux component, (and holds that code). The component is then named-- `component.tsx`-- and consumed in the `index` file.
101+
102+
The problem we've run into is when you have sub-components which are also connected to Redux. To maintain this structure, each sub-component and its Redux container would then be stored in a subdirectory, (with only two files in it).
103+
104+
> NOTE: if a PR touches component code that is in the older structure, it should be migrated to the structure above.
105+
106+
## Storybook
107+
108+
Canvas uses [Storybook](https://storybook.js.org) to test and develop components. This has a number of benefits:
109+
110+
- Developing components without needing to start ES + Kibana.
111+
- Testing components interactively without starting ES + Kibana.
112+
- Automatic Storyshot integration with Jest
113+
114+
### Using Storybook
115+
116+
The Canvas Storybook instance can be started by running `node scripts/storybook` from the Canvas root directory. It has a number of options:
117+
118+
```
119+
node scripts/storybook
120+
121+
Storybook runner for Canvas.
122+
123+
Options:
124+
--clean Forces a clean of the Storybook DLL and exits.
125+
--dll Cleans and builds the Storybook dependency DLL and exits.
126+
--stats Produces a Webpack stats file.
127+
--site Produces a site deployment of this Storybook.
128+
--verbose, -v Log verbosely
129+
--debug Log debug messages (less than verbose)
130+
--quiet Only log errors
131+
--silent Don't log anything
132+
--help Show this message
133+
```
134+
135+
### What about `kbn-storybook`?
136+
137+
Canvas wants to move to the Kibana Storybook instance as soon as feasible. There are few tweaks Canvas makes to Storybook, so we're actively working with the maintainers to make that migration successful.
138+
139+
In the meantime, people can test our progress by running `node scripts/storybook_new` from the Canvas root.

x-pack/plugins/canvas/i18n/components.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -110,26 +110,24 @@ export const ComponentStrings = {
110110
i18n.translate('xpack.canvas.asset.thumbnailAltText', {
111111
defaultMessage: 'Asset thumbnail',
112112
}),
113-
},
114-
AssetManager: {
115-
getButtonLabel: () =>
116-
i18n.translate('xpack.canvas.assetManager.manageButtonLabel', {
117-
defaultMessage: 'Manage assets',
118-
}),
119113
getConfirmModalButtonLabel: () =>
120-
i18n.translate('xpack.canvas.assetManager.confirmModalButtonLabel', {
114+
i18n.translate('xpack.canvas.asset.confirmModalButtonLabel', {
121115
defaultMessage: 'Remove',
122116
}),
123117
getConfirmModalMessageText: () =>
124-
i18n.translate('xpack.canvas.assetManager.confirmModalDetail', {
118+
i18n.translate('xpack.canvas.asset.confirmModalDetail', {
125119
defaultMessage: 'Are you sure you want to remove this asset?',
126120
}),
127121
getConfirmModalTitle: () =>
128-
i18n.translate('xpack.canvas.assetManager.confirmModalTitle', {
122+
i18n.translate('xpack.canvas.asset.confirmModalTitle', {
129123
defaultMessage: 'Remove Asset',
130124
}),
131125
},
132-
AssetModal: {
126+
AssetManager: {
127+
getButtonLabel: () =>
128+
i18n.translate('xpack.canvas.assetManager.manageButtonLabel', {
129+
defaultMessage: 'Manage assets',
130+
}),
133131
getDescription: () =>
134132
i18n.translate('xpack.canvas.assetModal.modalDescription', {
135133
defaultMessage:
@@ -162,6 +160,13 @@ export const ComponentStrings = {
162160
percentageUsed,
163161
},
164162
}),
163+
getCopyAssetMessage: (id: string) =>
164+
i18n.translate('xpack.canvas.assetModal.copyAssetMessage', {
165+
defaultMessage: `Copied '{id}' to clipboard`,
166+
values: {
167+
id,
168+
},
169+
}),
165170
},
166171
AssetPicker: {
167172
getAssetAltText: () =>

x-pack/plugins/canvas/public/components/asset_manager/__examples__/__snapshots__/asset.stories.storyshot

Lines changed: 178 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)