Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Backport 2.x][Feature] Adds the Drag and Drop editor to Visualize #2078

Merged
merged 1 commit into from
Aug 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/pr_check_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
name: Run functional tests
strategy:
matrix:
group: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ]
group: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 ]
steps:
- run: echo Running functional tests for ciGroup${{ matrix.group }}

Expand Down
1 change: 1 addition & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ def functionalDynamicParallelSteps(image){
"ciGroup10",
"ciGroup11",
"ciGroup12",
"ciGroup13",
]
for (int i = 0; i < ciGroups.size(); i++) {
def currentCiGroup = ciGroups[i];
Expand Down
17 changes: 16 additions & 1 deletion TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ To run specific functional tests, you can run by CI group:

To debug functional tests:
Say that you would want to debug a test in CI group 1, you can run the following command in your environment:
`node --debug-brk --inspect scripts/functional_tests.js --config test/functional/config.js --include ciGroup1 --debug`
`node --inspect-brk --inspect scripts/functional_tests.js --config test/functional/config.js --include ciGroup1 --debug`

This will print off an address, to which you could open your chrome browser on your instance and navigate to `chrome://inspect/#devices` and inspect the functional test runner `scripts/functional_tests.js`.

Expand Down Expand Up @@ -89,9 +89,24 @@ Automated testing is provided with Jenkins for Continuous Integration. Jenkins e
Selenium tests are run in headless mode on CI. Locally the same tests will be executed in a real browser. You can activate headless mode by setting the environment variable:
`export TEST_BROWSER_HEADLESS=1`

Since local Selenium tests are run in a real browser, the dev environment should have a desktop environment and Google Chrome or Chromium installed to run the tests.

By default the version of OpenSearch Dashboards will pull the snapshot of the same version of OpenSearch if available while running a few integration tests and for running functional tests. However, if the version of OpenSearch Dashboards is not available, you can build OpenSearch locally and point the functional test runner to the executable with:
`export TEST_OPENSEARCH_FROM=[local directory of OpenSearch executable]`

Selinium tests require a chromedriver and a corresponding version of chrome to run properly. Depending on the version of chromedriver used, you may need to use a version of Google Chrome that is not the latest version. You can do this by running:

```sh
# Enter the version of chrome that you want to install
CHROME_VERSION=100.0.4896.127-1

# Download Chrome to a temp directory
curl -sSL "https://dl.google.com/linux/linux_signing_key.pub" | sudo apt-key add - && wget -O /tmp/chrome.deb "https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_${CHROME_VERSION}_amd64.deb"

# Install/Downgrade Chrome
sudo apt-get install -y --allow-downgrades /tmp/chrome.deb
```

# Misc
Although Jest is the standard for this project, there are a few Mocha tests that still exist. You can run these tests by running:
`yarn test:mocha`
Expand Down
4 changes: 4 additions & 0 deletions config/opensearch_dashboards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,7 @@
# Set the value of this setting to false to suppress search usage telemetry
# for reducing the load of OpenSearch cluster.
# data.search.usageTelemetry.enabled: false

# Set the value of this setting to true to start exploring wizard
# functionality in Visualization.
# wizard.enabled: false
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@
"@osd/std": "1.0.0",
"@osd/ui-framework": "1.0.0",
"@osd/ui-shared-deps": "1.0.0",
"@reduxjs/toolkit": "^1.6.1",
"@types/yauzl": "^2.9.1",
"JSONStream": "1.3.5",
"abortcontroller-polyfill": "^1.4.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ opensearch_dashboards_vars=(
telemetry.optIn
telemetry.optInStatusUrl
telemetry.sendUsageFrom
wizard.enabled
)

longopts=''
Expand Down
8 changes: 8 additions & 0 deletions src/plugins/navigation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,11 @@
The navigation plugins exports the `TopNavMenu` component.
It also provides a stateful version of it on the `start` contract.

## navigation.ui.TopNavMenu

The `naivgation.ui` module exposes the `TopNavMenu` component that features The search bar, time filter and menu options to be used across the app in multiple locations. It primarity consists of 2 components:

- Menu options: Options to show on the menu bar alongside the breadcrumbs
- Search bar: The [`data.ui.SearchBar`](../data/public/ui/search_bar/) component responsible for the query bar, time filter and field filters.

Most of the logic for the component resides in the `SearchBar` component. This simply adds a way to add menu options on top of the search bar.
42 changes: 42 additions & 0 deletions src/plugins/saved_objects_management/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Saved objects management

Provides a UI (via the `management` plugin) to find and manage all saved objects in one place (you can see the primary page by navigating to `/app/management/opensearch-dashboards/objects`). Not to be confused with the `savedObjects` plugin, which provides all the core capabilities of saved objects.

From the primary UI page, this plugin allows you to:
1. Search/view/delete saved objects and their relationships
2. Import/export saved objects
3. Inspect/edit raw saved object values without validation

For 3., this plugin can also be used to provide a route/page for editing, such as `/app/management/opensearch-dashboards/objects/savedVisualizations/{visualizationId}`, although plugins are also free to provide or host alternate routes for this purpose (see index patterns, for instance, which provide their own integration and UI via the `management` plugin directly).

## Making a new saved object type manageable

1. Create a new `SavedObjectsType` or add the `management` property to an existing one. (See [`SavedObjectsTypeManagementDefinition`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/e1380f14deb98cc7cce55c3b82c2d501826a78c3/src/core/server/saved_objects/types.ts#L247-L285) for explanation of its properties)
2. Register saved object type via `core.savedObjects.registerType(...)` as part of plugin server setup method
3. Implement a way to save the object (e.g. via `savedObjectsClient.create(...)` or a `savedObjectLoader`)
4. After these steps, you should be able to save objects and view/search for them in Saved Objects management (`/app/management/opensearch-dashboards/objects`)

## Enabling edit links from saved objects management

1. Make sure `management.getInAppUrl` method of the `SavedObjectsType` is defined with a `path` (which will specify the link target) and the `uiCapabilitiesPath`
2. For `uiCapabilitiesPath` to work without additional hardcoding, it should be in the format `{plugin}.show`, so that [the default logic of `src/plugins/saved_objects_management/public/lib/in_app_url.ts`](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/a9984f63a38e964007ab94fae99237a14d8f9ee2/src/plugins/saved_objects_management/public/lib/in_app_url.ts#L48-L50) will correctly match. Otherwise, you'll need to [add a case for your `uiCapabilities` path](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/a9984f63a38e964007ab94fae99237a14d8f9ee2/src/plugins/saved_objects_management/public/lib/in_app_url.ts#L45-L47) to that function
3. Create default plugin capabilities provider
4. Register plugin capabilities via `core.capabilities.registerProvider(...);` as part of plugin server setup method

## Using saved objects management to inspect/edit new plugin objects

You'll notice that when clicking on the "Inspect" button from the saved objects management table, you'll usually be routed to something like `/app/management/opensearch-dashboards/objects/savedVisualizations/` (where the route itself is determined by the `management.getEditUrl` method of the `SavedObjectsType`). But to register a similar route for a new saved object type, you'll need to create a new `savedObjectLoader` and register it with the management plugin.

### Creating `savedObjectLoader`

1. In your plugin's public directory, create a class for your saved object that extends `SavedObjectClass`. The mapping should match the `mappings` defined in your `SavedObjectsType`.
2. Create a `savedObjectLoader` creation function that returns a `new SavedObjectLoader(YourSavedObjectClass, savedObjectsClient)`
3. Return that `savedObjectLoader` as part of your public plugin `start` method

### Registering

Ideally, we'd allow plugins to self-register their `savedObjectLoader` and (declare a dependency on this plugin). However, as currently implemented, any plugins that want this plugin to handle their inspect routes need to be added as optional dependencies and registered here.

1. Add your plugin to the `optionalPlugins` array in `./opensearch_dashboards.json`
2. Update the `StartDependencies` interface of this plugin to include the public plugin start type
3. Update `registerServices` to register a new type of `SavedObjectLoader`, where `id` will be the route, `title` will likely match your saved object type, and `service` is your `SavedObjectLoader` that is defined in your plugin start.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"server": true,
"ui": true,
"requiredPlugins": ["management", "data"],
"optionalPlugins": ["dashboard", "visualizations", "discover", "home"],
"optionalPlugins": ["dashboard", "visualizations", "discover", "home", "wizard"],
"extraPublicDirs": ["public/lib"],
"requiredBundles": ["opensearchDashboardsReact", "home"]
}
3 changes: 3 additions & 0 deletions src/plugins/saved_objects_management/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

import { i18n } from '@osd/i18n';
import { CoreSetup, CoreStart, Plugin } from 'src/core/public';

import { WizardStart } from '../../wizard/public';
import { ManagementSetup } from '../../management/public';
import { DataPublicPluginStart } from '../../data/public';
import { DashboardStart } from '../../dashboard/public';
Expand Down Expand Up @@ -69,6 +71,7 @@ export interface StartDependencies {
dashboard?: DashboardStart;
visualizations?: VisualizationsStart;
discover?: DiscoverStart;
wizard?: WizardStart;
}

export class SavedObjectsManagementPlugin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const registerServices = async (
registry: ISavedObjectsManagementServiceRegistry,
getStartServices: StartServicesAccessor<StartDependencies, SavedObjectsManagementPluginStart>
) => {
const [, { dashboard, visualizations, discover }] = await getStartServices();
const [, { dashboard, visualizations, discover, wizard }] = await getStartServices();

if (dashboard) {
registry.register({
Expand All @@ -61,4 +61,12 @@ export const registerServices = async (
service: discover.savedSearchLoader,
});
}

if (wizard) {
registry.register({
id: 'savedWizard',
title: 'wizard',
service: wizard.savedWizardLoader,
});
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export interface DefaultEditorCommonProps {
formIsTouched: boolean;
groupName: AggGroupName;
metricAggs: IAggConfig[];
state: EditorVisState;
state: Partial<EditorVisState>;
setAggParamValue: <T extends keyof AggParams>(
aggId: AggId,
paramName: T,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ interface ParamInstanceBase {
agg: IAggConfig;
editorConfig: EditorConfig;
metricAggs: IAggConfig[];
state: EditorVisState;
state: Partial<EditorVisState>;
schemas: Schema[];
hideCustomLabel?: boolean;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const createEditorStateReducer = ({
!state.data.aggs!.aggs.find((agg) => agg.schema === schema.name) && schema.defaults
? (schema as any).defaults.slice(0, schema.max)
: { schema: schema.name };

const aggConfig = state.data.aggs!.createAggConfig(defaultConfig, {
addToAggConfigs: false,
});
Expand Down
1 change: 1 addition & 0 deletions src/plugins/vis_default_editor/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
export { DefaultEditorController } from './default_editor_controller';
export { useValidation } from './components/controls/utils';
export { RangesParamEditor, RangeValues } from './components/controls/ranges';
export { DefaultEditorAggParams } from './components/agg_params';
export * from './editor_size';
export * from './vis_options_props';
export * from './utils';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ function MetricVisOptions({
);

const setColorMode: EuiButtonGroupProps['onChange'] = useCallback(
(id) => setMetricValue('metricColorMode', id as ColorModes),
(id: string) => setMetricValue('metricColorMode', id as ColorModes),
[setMetricValue]
);

Expand Down
3 changes: 3 additions & 0 deletions src/plugins/vis_type_metric/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ import { MetricVisPlugin as Plugin } from './plugin';
export function plugin(initializerContext: PluginInitializerContext) {
return new Plugin(initializerContext);
}

/* Public Types */
export { MetricVisExpressionFunctionDefinition } from './metric_vis_fn';
2 changes: 1 addition & 1 deletion src/plugins/vis_type_metric/public/metric_vis_fn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ interface Arguments {
colorRange: Range[];
font: Style;
metric: any[]; // these aren't typed yet
bucket: any; // these aren't typed yet
bucket?: any; // these aren't typed yet
}

export interface MetricVisRenderValue {
Expand Down
12 changes: 7 additions & 5 deletions src/plugins/visualizations/public/legacy/build_pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,8 @@ export const buildVislibDimensions = async (vis: any, params: BuildPipelineParam
splitColumn: schemas.split_column,
};
if (schemas.segment) {
const xAgg = vis.data.aggs.getResponseAggs()[dimensions.x.accessor];
const a = vis.data.aggs.getResponseAggs();
const xAgg = a[dimensions.x.accessor];
if (xAgg.type.name === 'date_histogram') {
dimensions.x.params.date = true;
const { opensearchUnit, opensearchValue } = xAgg.buckets.getInterval();
Expand Down Expand Up @@ -423,10 +424,10 @@ export const buildPipeline = async (vis: Vis, params: BuildPipelineParams) => {
// request handler
if (vis.type.requestHandler === 'courier') {
pipeline += `opensearchaggs
${prepareString('index', indexPattern!.id)}
metricsAtAllLevels=${vis.isHierarchical()}
partialRows=${vis.params.showPartialRows || false}
${prepareJson('aggConfigs', vis.data.aggs!.aggs)} | `;
${prepareString('index', indexPattern!.id)}
metricsAtAllLevels=${vis.isHierarchical()}
partialRows=${vis.params.showPartialRows || false}
${prepareJson('aggConfigs', vis.data.aggs!.aggs)} | `;
}

const schemas = getSchemas(vis, params);
Expand Down Expand Up @@ -456,5 +457,6 @@ export const buildPipeline = async (vis: Vis, params: BuildPipelineParams) => {
}
}
}

return pipeline;
};
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
* under the License.
*/

import { SavedObjectAttributes } from 'opensearch-dashboards/public';
import { TriggerContextMapping } from '../../../ui_actions/public';

export interface VisualizationListItem {
Expand All @@ -51,7 +52,7 @@ export interface VisualizationsAppExtension {
toListItem: (savedObject: {
id: string;
type: string;
attributes: object;
attributes: SavedObjectAttributes;
}) => VisualizationListItem;
}

Expand Down
Loading