Tilte Style plugin in v9.0.2

As generated plugin which is for styling title of visualisation suppose table or any other visual having title so have to customise setting like title font size,its colour its background colour alignment etc just like MS office styling bars But its is showing left side navigation bar and not integrated through inside dashboards like title is not changing and this plugin is not connected to any dashboards or visual title styles.How can achieve this

Hi @Mayuri_Jaiswal,

It sounds like you are having issues with a Kibana plugin that you've built. Can you share the plugin code please, along with any error showing in the DevTools console?

Let us know!

I am having source code of kibana “v9.0.2” and generate plugin and edited file as follow-

My requirement is to integarte plugin with dashboard that it will change the styles of title we give to visualisation

kibana/plugins/titleStyleEditor/kibana.json

{

"id": "titleStyleEditor",

"version": "9.0.2",

"kibanaVersion": "9.0.2",

"requiredPlugins": ["uiActions"],

"optionalPlugins": ,

"server": false,

"ui": true

}

kibana/plugins/titleStyleEditor/package.json

{

"name": "titleStyleEditor",

"version": "0.0.0",

"private": true,

"scripts": {

"bootstrap": "yarn kbn bootstrap && yarn install",

"build": "yarn plugin-helpers build",

"dev": "yarn plugin-helpers dev",

"plugin-helpers": "node ../../scripts/plugin_helpers",

"kbn": "node ../../scripts/kbn"

}

}

kibana/plugins/titleStyleEditor/tsconfig.json

{

"extends": "../../tsconfig.json",

"compilerOptions": {

"outDir": "./target/types"

},

"include": [

"index.ts",

"common/**/*.ts",

"public/**/*.ts",

"public/**/*.tsx",

"server/**/*.ts",

"../../typings/**/*"

],

"exclude":

}

"kibana/plugins/titleStyleEditor/common/index.ts"

export const PLUGIN_ID = 'titleStyleEditor';

export const PLUGIN_NAME = 'titleStyleEditor';

"kibana/plugins/titleStyleEditor/public/components/app.tsx"

import React, { useState } from 'react';

import { i18n } from '@kbn/i18n';

import { FormattedMessage, I18nProvider } from '@kbn/i18n-react';

import { BrowserRouter as Router } from '@kbn/shared-ux-router';

import { EuiButton, EuiHorizontalRule, EuiPageTemplate, EuiTitle, EuiText } from '@elastic/eui';

import type { CoreStart } from '@kbn/core/public';

import type { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public';

import { PLUGIN_ID, PLUGIN_NAME } from '../../common';

interface TitleStyleEditorAppDeps {

basename: string;

notifications: CoreStart['notifications'];

http: CoreStart['http'];

navigation: NavigationPublicPluginStart;

}

export const TitleStyleEditorApp = ({

basename,

notifications,

http,

navigation,

}: TitleStyleEditorAppDeps) => {

// Use React hooks to manage state.

const [timestamp, setTimestamp] = useState<string | undefined>();

const onClickHandler = () => {

// Use the core http service to make a response to the server API.

http.get('/api/title_style_editor/example').then((res) => {

setTimestamp(res.time);

// Use the core notifications service to display a success message.

notifications.toasts.addSuccess(

i18n.translate('titleStyleEditor.dataUpdated', {

defaultMessage: 'Data updated',

    })

  );

});

};

// Render the application DOM.

// Note that `navigation.ui.TopNavMenu` is a stateful component exported on the `navigation` plugin's start contract.

return (

<Router basename={basename}>

  <I18nProvider>

    <>

      <navigation.ui.TopNavMenu

        appName={PLUGIN_ID}

        showSearchBar={true}

        useDefaultBehaviors={true}

      />

      <EuiPageTemplate restrictWidth="1000px">

        <EuiPageTemplate.Header>

          <EuiTitle size="l">

            <h1>

              <FormattedMessage

                id="titleStyleEditor.helloWorldText"

                defaultMessage="{name}"

                values={{ name: PLUGIN_NAME }}

              />

            </h1>

          </EuiTitle>

        </EuiPageTemplate.Header>

        <EuiPageTemplate.Section>

          <EuiTitle>

            <h2>

              <FormattedMessage

                id="titleStyleEditor.congratulationsTitle"

                defaultMessage="Congratulations, you have successfully created a new Kibana Plugin!"

              />

            </h2>

          </EuiTitle>

          <EuiText>

            <p>

              <FormattedMessage

                id="titleStyleEditor.content"

                defaultMessage="Look through the generated code and check out the plugin development documentation."

              />

            </p>

            <EuiHorizontalRule />

            <p>

              <FormattedMessage

                id="titleStyleEditor.timestampText"

                defaultMessage="Last timestamp: {time}"

                values={{ time: timestamp ? timestamp : 'Unknown' }}

              />

            </p>

            <EuiButton type="primary" size="s" onClick={onClickHandler}>

              <FormattedMessage

                id="titleStyleEditor.buttonText"

                defaultMessage="Get data"

                ignoreTag

              />

            </EuiButton>

          </EuiText>

        </EuiPageTemplate.Section>

      </EuiPageTemplate>

    </>

  </I18nProvider>

</Router>

);

};

"kibana/plugins/titleStyleEditor/public/components/TitleStyleMenuButton.tsx"

// /public/components/TitleStyleMenuButton.tsx

import React from 'react';

import { CoreStart } from '@kbn/core/public';

import { toMountPoint } from '@kbn/kibana-react-plugin/public';

import { ActionExecutionContext } from '@kbn/ui-actions-plugin/public';

import { EuiButtonEmpty } from '@elastic/eui';

import { TitleStyleFlyout } from '../title_style_flyout';

interface Props {

core: CoreStart;

context: ActionExecutionContext<{ embeddable?: any }>;

}

export const TitleStyleMenuButton: React.FC = ({ core, context }) => {

const handleClick = () => {

const embeddable = context.embeddable;

if (embeddable) {

core.overlays.openFlyout(

toMountPoint(, { theme: core.theme })

  );

}

};

return (

<EuiButtonEmpty onClick={handleClick} iconType="pencil">

  Edit Title Style

</EuiButtonEmpty>

);

};

"kibana/plugins/titleStyleEditor/public/application.tsx"

import React from 'react';

export const App: React.FC = () =>

Title Style Editor
;

"kibana/plugins/titleStyleEditor/public/apply_title_styles.ts"

import { TitleStyleSettings } from './types';

export function applyTitleStyles(panel: any, settings: TitleStyleSettings) {

panel.updateInput({

title: settings.text,

titleFontSize: settings.fontSize,

titleBold: settings.bold,

titleItalic: settings.italic,

titleAlign: settings.align,

});

}

"kibana/plugins/titleStyleEditor/public/index.scss"

empty

"kibana/plugins/titleStyleEditor/public/index.ts"

import { TitleStyleEditorPlugin } from './plugin';

export function plugin() {

return new TitleStyleEditorPlugin();

}

"kibana/plugins/titleStyleEditor/public/plugin.ts"

import { i18n } from '@kbn/i18n';

import type { CoreSetup, CoreStart, Plugin, AppMountParameters } from '@kbn/core/public';

import type {

TitleStyleEditorPluginSetup,

TitleStyleEditorPluginStart,

AppPluginStartDependencies,

} from './types';

import { PLUGIN_ID, PLUGIN_NAME } from '../common';

import { titleStyleAction } from './title_style_action';

export class TitleStyleEditorPlugin

implements Plugin<TitleStyleEditorPluginSetup, TitleStyleEditorPluginStart>

{

public setup(core: CoreSetup<{ uiActions: unknown }>): TitleStyleEditorPluginSetup {

core.application.register({

id: PLUGIN_ID,

title: PLUGIN_NAME,

async mount(params: AppMountParameters) {

const { renderApp } = await import('./application');

const [coreStart, depsStart] = await core.getStartServices();

return renderApp(coreStart, depsStart as AppPluginStartDependencies, params);

  },

});



const \[\_, deps\] = core.getStartServices();

(deps as AppPluginStartDependencies).uiActions?.registerAction(titleStyleAction);



return {

getGreeting() {

return i18n.translate('titleStyleEditor.greetingText', {

defaultMessage: 'Hello from {name}!',

values: { name: PLUGIN_NAME },

    });

  },

};

}

public start(core: CoreStart): TitleStyleEditorPluginStart {

return {};

}

public stop() {}

}

"kibana/plugins/titleStyleEditor/public/title_style_action.tsx"

import { createAction } from '@kbn/ui-actions-plugin/public';

import { ActionExecutionContext } from '@kbn/ui-actions-plugin/public';

import { CoreStart } from '@kbn/core/public';

import React from 'react';

import { toMountPoint } from '@kbn/kibana-react-plugin/public';

import { TitleStyleFlyout } from './title_style_flyout';

export const titleStyleAction = createAction<{ embeddable?: any }>({

id: 'titleStyleAction',

type: 'titleStyle',

getDisplayName: () => 'Edit Title Style',

execute: async ({ embeddable }: ActionExecutionContext<{ embeddable?: any }>, core: CoreStart) => {

if (embeddable) {

core.overlays.openFlyout(

toMountPoint(, { theme$: core.theme.theme$ })

  );

}

},

});

"kibana/plugins/titleStyleEditor/public/title_style_flyout.tsx"

import React, { useState } from 'react';

import {

EuiFlyout,

EuiFlyoutHeader,

EuiFlyoutBody,

EuiTitle,

EuiFormRow,

EuiFieldText,

EuiSelect,

EuiSwitch,

EuiButton,

} from '@elastic/eui';

interface Props {

embeddable: any; // you can replace "any" with a stricter Embeddable type later

onClose?: () => void;

}

export const TitleStyleFlyout: React.FC = ({ embeddable, onClose }) => {

// Example state – you can store actual embeddable attributes here

const [title, setTitle] = useState(embeddable?.getInput()?.title || '');

const [fontSize, setFontSize] = useState('m');

const [isBold, setIsBold] = useState(false);

const [isItalic, setIsItalic] = useState(false);

const fontSizeOptions = [

{ value: 's', text: 'Small' },

{ value: 'm', text: 'Medium' },

{ value: 'l', text: 'Large' },

{ value: 'xl', text: 'Extra Large' },

];

const handleSave = () => {

if (embeddable?.updateInput) {

embeddable.updateInput({

title,

// In future: persist font size, bold/italic to your own state store

  });

}

if (onClose) onClose();

};

return (

<EuiFlyout onClose={onClose} size="s" ownFocus>

  <EuiFlyoutHeader hasBorder>

    <EuiTitle size="m">

      <h2>Edit Title Style</h2>

    </EuiTitle>

  </EuiFlyoutHeader>



  <EuiFlyoutBody>

    <EuiFormRow label="Panel title">

      <EuiFieldText value={title} onChange={(e) => setTitle(e.target.value)} />

    </EuiFormRow>



    <EuiFormRow label="Font size">

      <EuiSelect

        options={fontSizeOptions}

        value={fontSize}

        onChange={(e) => setFontSize(e.target.value)}

      />

    </EuiFormRow>



    <EuiFormRow>

      <EuiSwitch

        label="Bold"

        checked={isBold}

        onChange={(e) => setIsBold(e.target.checked)}

      />

    </EuiFormRow>



    <EuiFormRow>

      <EuiSwitch

        label="Italic"

        checked={isItalic}

        onChange={(e) => setIsItalic(e.target.checked)}

      />

    </EuiFormRow>



    <EuiButton fill onClick={handleSave}>

      Save

    </EuiButton>

  </EuiFlyoutBody>

</EuiFlyout>

);

};

// helper for action.tsx

export const openFlyout = (embeddable?: any) => {

// here you’d open via overlays if you want, but since you already

// use TitleStyleMenuButton, you can just import TitleStyleFlyout directly

};

"kibana/plugins/titleStyleEditor/public/types.ts"

export interface TitleStyleEditorPluginSetup {

getGreeting: () => string;

}

export interface TitleStyleEditorPluginStart {}

export interface AppPluginStartDependencies {

uiActions: unknown; // You can tighten this later

}

/home/tec14/Documents/kibana/plugins/titleStyleEditor/

export interface TitleStyleEditorPluginSetup {

getGreeting: () => string;

}

export interface TitleStyleEditorPluginStart {}

export interface AppPluginStartDependencies {

uiActions: unknown; // You can tighten this later

}

"kibana/plugins/titleStyleEditor/server/routes"

import type { IRouter } from '@kbn/core/server';

export function defineRoutes(router: IRouter) {

router.get(

{

path: '/api/title_style_editor/example',

validate: false,

},

async (context, request, response) => {

return response.ok({

body: {

time: new Date().toISOString(),

    },

  });

}

);

}

"kibana/plugins/titleStyleEditor/server/index.ts"

import type { PluginInitializerContext } from '@kbn/core/server';

// This exports static code and TypeScript types,

// as well as, Kibana Platform `plugin()` initializer.

export async function plugin(initializerContext: PluginInitializerContext) {

const { TitleStyleEditorPlugin } = await import('./plugin');

return new TitleStyleEditorPlugin(initializerContext);

}

export type { TitleStyleEditorPluginSetup, TitleStyleEditorPluginStart } from './types';

"kibana/plugins/titleStyleEditor/server/plugin.ts"

import type {

PluginInitializerContext,

CoreSetup,

CoreStart,

Plugin,

Logger,

} from '@kbn/core/server';

import type { TitleStyleEditorPluginSetup, TitleStyleEditorPluginStart } from './types';

import { defineRoutes } from './routes';

export class TitleStyleEditorPlugin

implements Plugin<TitleStyleEditorPluginSetup, TitleStyleEditorPluginStart>

{

private readonly logger: Logger;

constructor(initializerContext: PluginInitializerContext) {

this.logger = initializerContext.logger.get();

}

public setup(core: CoreSetup) {

this.logger.debug('titleStyleEditor: Setup');

const router = core.http.createRouter();

// Register server side APIs

defineRoutes(router);

return {};

}

public start(core: CoreStart) {

this.logger.debug('titleStyleEditor: Started');

return {};

}

public stop() {}

}

"kibana/plugins/titleStyleEditor/server/types.ts"

// eslint-disable-next-line @typescript-eslint/no-empty-interface

export interface TitleStyleEditorPluginSetup {}

// eslint-disable-next-line @typescript-eslint/no-empty-interface

export interface TitleStyleEditorPluginStart {}

Hi @carly.richmond
Can you please help.