mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[canvas] disable canvas application when there are no workpads (#200203)
Closes https://github.com/elastic/kibana/issues/197370 ### Test instructions 1) open new kibana installation 2) verify canvas is not available in menu or application search bar 3) use saved object import to import canvas workpad. Reload browser 4) verify canvas is available in menu and application search bar --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
0aa63a7ecc
commit
eb68fb2713
14 changed files with 119 additions and 36 deletions
|
@ -5,6 +5,8 @@
|
|||
[partintro]
|
||||
--
|
||||
|
||||
*Note:* Canvas is only available for upgraded installations with existing workpads.
|
||||
|
||||
*Canvas* is a data visualization and presentation tool that allows you to pull live data from {es},
|
||||
then combine the data with colors, images, text, and your imagination to create dynamic, multi-page, pixel-perfect displays.
|
||||
If you are a little bit creative, a little bit technical, and a whole lot curious, then *Canvas* is for you.
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { FeatureCatalogueCategory } from '@kbn/home-plugin/public';
|
||||
|
||||
export const featureCatalogueEntry = {
|
||||
id: 'canvas',
|
||||
title: 'Canvas',
|
||||
subtitle: i18n.translate('xpack.canvas.featureCatalogue.canvasSubtitle', {
|
||||
defaultMessage: 'Design pixel-perfect presentations.',
|
||||
}),
|
||||
description: i18n.translate('xpack.canvas.appDescription', {
|
||||
defaultMessage: 'Showcase your data in a pixel-perfect way.',
|
||||
}),
|
||||
icon: 'canvasApp',
|
||||
path: '/app/canvas',
|
||||
showOnHomePage: false,
|
||||
category: 'data' as FeatureCatalogueCategory,
|
||||
solutionId: 'kibana',
|
||||
order: 300,
|
||||
};
|
|
@ -18,6 +18,7 @@ import {
|
|||
AppUpdater,
|
||||
DEFAULT_APP_CATEGORIES,
|
||||
PluginInitializerContext,
|
||||
AppStatus,
|
||||
} from '@kbn/core/public';
|
||||
import { HomePublicPluginSetup } from '@kbn/home-plugin/public';
|
||||
import { SpacesPluginStart } from '@kbn/spaces-plugin/public';
|
||||
|
@ -30,7 +31,6 @@ import { Start as InspectorStart } from '@kbn/inspector-plugin/public';
|
|||
import { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/public';
|
||||
import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
||||
import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public';
|
||||
import { featureCatalogueEntry } from './feature_catalogue_entry';
|
||||
import { CanvasAppLocatorDefinition } from '../common/locator';
|
||||
import { SESSIONSTORAGE_LASTPATH, CANVAS_APP } from '../common/lib/constants';
|
||||
import { getSessionStorage } from './lib/storage';
|
||||
|
@ -39,6 +39,7 @@ import { getPluginApi, CanvasApi } from './plugin_api';
|
|||
import { setupExpressions } from './setup_expressions';
|
||||
import { addCanvasElementTrigger } from './state/triggers/add_canvas_element_trigger';
|
||||
import { setKibanaServices, untilPluginStartServicesReady } from './services/kibana_services';
|
||||
import { getHasWorkpads } from './services/get_has_workpads';
|
||||
|
||||
export type { CoreStart, CoreSetup };
|
||||
|
||||
|
@ -161,9 +162,11 @@ export class CanvasPlugin
|
|||
},
|
||||
});
|
||||
|
||||
if (setupPlugins.home) {
|
||||
setupPlugins.home.featureCatalogue.register(featureCatalogueEntry);
|
||||
}
|
||||
getHasWorkpads(coreSetup.http).then((hasWorkpads) => {
|
||||
this.appUpdater.next(() => ({
|
||||
status: hasWorkpads ? AppStatus.accessible : AppStatus.inaccessible,
|
||||
}));
|
||||
});
|
||||
|
||||
if (setupPlugins.share) {
|
||||
setupPlugins.share.url.locators.create(new CanvasAppLocatorDefinition());
|
||||
|
|
20
x-pack/plugins/canvas/public/services/get_has_workpads.ts
Normal file
20
x-pack/plugins/canvas/public/services/get_has_workpads.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { HttpSetup } from '@kbn/core/public';
|
||||
import { API_ROUTE_WORKPAD } from '../../common/lib/constants';
|
||||
|
||||
export async function getHasWorkpads(http: HttpSetup): Promise<boolean> {
|
||||
try {
|
||||
const response = await http.get(`${API_ROUTE_WORKPAD}/hasWorkpads`, {
|
||||
version: '1',
|
||||
});
|
||||
return (response as { hasWorkpads: boolean })?.hasWorkpads ?? false;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
52
x-pack/plugins/canvas/server/routes/workpad/has_workpads.ts
Normal file
52
x-pack/plugins/canvas/server/routes/workpad/has_workpads.ts
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { SavedObjectAttributes } from '@kbn/core/server';
|
||||
import { RouteInitializerDeps } from '..';
|
||||
import { CANVAS_TYPE, API_ROUTE_WORKPAD } from '../../../common/lib/constants';
|
||||
|
||||
export function initializeHasWorkpadsRoute(deps: RouteInitializerDeps) {
|
||||
const { router } = deps;
|
||||
router.versioned
|
||||
.get({
|
||||
path: `${API_ROUTE_WORKPAD}/hasWorkpads`,
|
||||
access: 'internal',
|
||||
})
|
||||
.addVersion(
|
||||
{
|
||||
version: '1',
|
||||
validate: {
|
||||
request: {},
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const savedObjectsClient = (await context.core).savedObjects.client;
|
||||
|
||||
try {
|
||||
const workpads = await savedObjectsClient.find<SavedObjectAttributes>({
|
||||
type: CANVAS_TYPE,
|
||||
fields: ['id'],
|
||||
perPage: 1,
|
||||
// search across all spaces
|
||||
namespaces: ['*'],
|
||||
});
|
||||
|
||||
return response.ok({
|
||||
body: {
|
||||
hasWorkpads: workpads.total > 0,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
return response.ok({
|
||||
body: {
|
||||
hasWorkpads: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
|
@ -13,8 +13,10 @@ import { initializeImportWorkpadRoute } from './import';
|
|||
import { initializeUpdateWorkpadRoute, initializeUpdateWorkpadAssetsRoute } from './update';
|
||||
import { initializeDeleteWorkpadRoute } from './delete';
|
||||
import { initializeResolveWorkpadRoute } from './resolve';
|
||||
import { initializeHasWorkpadsRoute } from './has_workpads';
|
||||
|
||||
export function initWorkpadRoutes(deps: RouteInitializerDeps) {
|
||||
initializeHasWorkpadsRoute(deps);
|
||||
initializeFindWorkpadsRoute(deps);
|
||||
initializeResolveWorkpadRoute(deps);
|
||||
initializeGetWorkpadRoute(deps);
|
||||
|
|
|
@ -12501,7 +12501,6 @@
|
|||
"xpack.banners.settings.textContent.title": "Texte de la bannière",
|
||||
"xpack.canvas.addCanvasElementTrigger.description": "Une nouvelle action apparaît dans le menu du panneau d'ajout Canvas",
|
||||
"xpack.canvas.addCanvasElementTrigger.title": "Menu Ajouter un panneau",
|
||||
"xpack.canvas.appDescription": "Vos données méritent une présentation irréprochable.",
|
||||
"xpack.canvas.argAddPopover.addAriaLabel": "Ajouter un argument",
|
||||
"xpack.canvas.argFormAdvancedFailure.applyButtonLabel": "Appliquer",
|
||||
"xpack.canvas.argFormAdvancedFailure.resetButtonLabel": "Réinitialiser",
|
||||
|
@ -12690,7 +12689,6 @@
|
|||
"xpack.canvas.expressionTypes.argTypes.seriesStyle.styleLabel": "Style",
|
||||
"xpack.canvas.expressionTypes.argTypes.seriesStyleLabel": "Définir le style d'une série nommée sélectionnée",
|
||||
"xpack.canvas.expressionTypes.argTypes.seriesStyleTitle": "Style de la série",
|
||||
"xpack.canvas.featureCatalogue.canvasSubtitle": "Concevez des présentations irréprochables.",
|
||||
"xpack.canvas.features.reporting.pdf": "Générer des rapports PDF",
|
||||
"xpack.canvas.features.reporting.pdfFeatureName": "Reporting",
|
||||
"xpack.canvas.formatMsg.toaster.errorStatusMessage": "Erreur {errStatus} {errStatusText} : {errMessage}.",
|
||||
|
|
|
@ -12485,7 +12485,6 @@
|
|||
"xpack.banners.settings.textContent.title": "バナーテキスト",
|
||||
"xpack.canvas.addCanvasElementTrigger.description": "新しいアクションは、キャンバスのパネルの追加メニューに表示されます",
|
||||
"xpack.canvas.addCanvasElementTrigger.title": "パネルの追加メニュー",
|
||||
"xpack.canvas.appDescription": "データを完璧に美しく表現します。",
|
||||
"xpack.canvas.argAddPopover.addAriaLabel": "引数を追加",
|
||||
"xpack.canvas.argFormAdvancedFailure.applyButtonLabel": "適用",
|
||||
"xpack.canvas.argFormAdvancedFailure.resetButtonLabel": "リセット",
|
||||
|
@ -12674,7 +12673,6 @@
|
|||
"xpack.canvas.expressionTypes.argTypes.seriesStyle.styleLabel": "スタイル",
|
||||
"xpack.canvas.expressionTypes.argTypes.seriesStyleLabel": "選択された名前付きの数列のスタイルを設定",
|
||||
"xpack.canvas.expressionTypes.argTypes.seriesStyleTitle": "数列スタイル",
|
||||
"xpack.canvas.featureCatalogue.canvasSubtitle": "詳細まで正確な表示を設計します。",
|
||||
"xpack.canvas.features.reporting.pdf": "PDFレポートを生成",
|
||||
"xpack.canvas.features.reporting.pdfFeatureName": "レポート",
|
||||
"xpack.canvas.formatMsg.toaster.errorStatusMessage": "エラー {errStatus} {errStatusText}: {errMessage}",
|
||||
|
|
|
@ -12250,7 +12250,6 @@
|
|||
"xpack.banners.settings.textContent.title": "横幅广告文本",
|
||||
"xpack.canvas.addCanvasElementTrigger.description": "一项新操作将在 Canvas 添加面板菜单中显示出来",
|
||||
"xpack.canvas.addCanvasElementTrigger.title": "添加面板菜单",
|
||||
"xpack.canvas.appDescription": "以最佳像素展示您的数据。",
|
||||
"xpack.canvas.argAddPopover.addAriaLabel": "添加参数",
|
||||
"xpack.canvas.argFormAdvancedFailure.applyButtonLabel": "应用",
|
||||
"xpack.canvas.argFormAdvancedFailure.resetButtonLabel": "重置",
|
||||
|
@ -12435,7 +12434,6 @@
|
|||
"xpack.canvas.expressionTypes.argTypes.seriesStyle.styleLabel": "样式",
|
||||
"xpack.canvas.expressionTypes.argTypes.seriesStyleLabel": "设置选定已命名序列的样式",
|
||||
"xpack.canvas.expressionTypes.argTypes.seriesStyleTitle": "序列样式",
|
||||
"xpack.canvas.featureCatalogue.canvasSubtitle": "设计像素级完美的演示文稿。",
|
||||
"xpack.canvas.features.reporting.pdf": "生成 PDF 报告",
|
||||
"xpack.canvas.features.reporting.pdfFeatureName": "Reporting",
|
||||
"xpack.canvas.formatMsg.toaster.errorStatusMessage": "错误 {errStatus} {errStatusText}:{errMessage}",
|
||||
|
|
|
@ -29,6 +29,10 @@ export default function canvasExpressionTest({ getService, getPageObjects }: Ftr
|
|||
await kibanaServer.importExport.load(
|
||||
'test/functional/fixtures/kbn_archiver/kibana_sample_data_flights_index_pattern.json'
|
||||
);
|
||||
// canvas application is only available when installation contains canvas workpads
|
||||
await kibanaServer.importExport.load(
|
||||
'x-pack/test/functional/fixtures/kbn_archiver/canvas/default'
|
||||
);
|
||||
|
||||
await kibanaServer.uiSettings.update({
|
||||
defaultIndex: 'kibana_sample_data_flights',
|
||||
|
@ -46,6 +50,9 @@ export default function canvasExpressionTest({ getService, getPageObjects }: Ftr
|
|||
await kibanaServer.importExport.unload(
|
||||
'test/functional/fixtures/kbn_archiver/kibana_sample_data_flights_index_pattern.json'
|
||||
);
|
||||
await kibanaServer.importExport.unload(
|
||||
'x-pack/test/functional/fixtures/kbn_archiver/canvas/default'
|
||||
);
|
||||
});
|
||||
|
||||
describe('esdocs', function () {
|
||||
|
|
|
@ -18,6 +18,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
describe('maps in canvas', function () {
|
||||
before(async () => {
|
||||
await kibanaServer.savedObjects.cleanStandardList();
|
||||
// canvas application is only available when installation contains canvas workpads
|
||||
await kibanaServer.importExport.load(
|
||||
'x-pack/test/functional/fixtures/kbn_archiver/canvas/default'
|
||||
);
|
||||
// open canvas home
|
||||
await canvas.goToListingPage();
|
||||
// create new workpad
|
||||
|
@ -25,6 +29,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await canvas.setWorkpadName('maps tests');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await kibanaServer.savedObjects.cleanStandardList();
|
||||
});
|
||||
|
||||
describe('by-value', () => {
|
||||
it('creates new map embeddable', async () => {
|
||||
const originalEmbeddableCount = await canvas.getEmbeddableCount();
|
||||
|
|
|
@ -20,6 +20,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await kibanaServer.importExport.load(
|
||||
'test/functional/fixtures/kbn_archiver/dashboard/current/kibana'
|
||||
);
|
||||
// canvas application is only available when installation contains canvas workpads
|
||||
await kibanaServer.importExport.load(
|
||||
'x-pack/test/functional/fixtures/kbn_archiver/canvas/default'
|
||||
);
|
||||
// open canvas home
|
||||
await canvas.goToListingPage();
|
||||
// create new workpad
|
||||
|
|
|
@ -20,6 +20,10 @@ export default function enterSpaceFunctionalTests({
|
|||
describe('Enter Space', function () {
|
||||
this.tags('includeFirefox');
|
||||
before(async () => {
|
||||
// canvas application is only available when installation contains canvas workpads
|
||||
await kibanaServer.importExport.load(
|
||||
'x-pack/test/functional/fixtures/kbn_archiver/canvas/default'
|
||||
);
|
||||
await spacesService.create({
|
||||
id: 'another-space',
|
||||
name: 'Another Space',
|
||||
|
@ -45,6 +49,9 @@ export default function enterSpaceFunctionalTests({
|
|||
await PageObjects.security.forceLogout();
|
||||
});
|
||||
after(async () => {
|
||||
await kibanaServer.importExport.unload(
|
||||
'x-pack/test/functional/fixtures/kbn_archiver/canvas/default'
|
||||
);
|
||||
await spacesService.delete('another-space');
|
||||
await kibanaServer.savedObjects.cleanStandardList();
|
||||
});
|
||||
|
|
|
@ -14,6 +14,7 @@ export default function searchSolutionNavigation({
|
|||
const { common, solutionNavigation } = getPageObjects(['common', 'solutionNavigation']);
|
||||
const spaces = getService('spaces');
|
||||
const browser = getService('browser');
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
|
||||
describe('Search Solution Navigation', () => {
|
||||
let cleanUp: () => Promise<unknown>;
|
||||
|
@ -28,9 +29,18 @@ export default function searchSolutionNavigation({
|
|||
// Create a space with the search solution and navigate to its home page
|
||||
({ cleanUp, space: spaceCreated } = await spaces.create({ solution: 'es' }));
|
||||
await browser.navigateTo(spaces.getRootUrl(spaceCreated.id));
|
||||
|
||||
// canvas application is only available when installation contains canvas workpads
|
||||
await kibanaServer.importExport.load(
|
||||
'x-pack/test/functional/fixtures/kbn_archiver/canvas/default'
|
||||
);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await kibanaServer.importExport.unload(
|
||||
'x-pack/test/functional/fixtures/kbn_archiver/canvas/default'
|
||||
);
|
||||
|
||||
// Clean up space created
|
||||
await cleanUp();
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue