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

feat: introducing workspace level ui settings and hide non-global ui settings from advance settings page #8500

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 5 additions & 0 deletions src/core/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ import {
CoreEnvironmentUsageData,
CoreServicesUsageData,
} from './core_usage_data';
import { WorkspaceSetup, WorkspaceStart } from './workspace';

export { CoreUsageData, CoreConfigUsageData, CoreEnvironmentUsageData, CoreServicesUsageData };

Expand Down Expand Up @@ -480,6 +481,8 @@ export interface CoreSetup<TPluginsStart extends object = object, TStart = unkno
auditTrail: AuditTrailSetup;
/** {@link DynamicConfigServiceSetup} */
dynamicConfigService: DynamicConfigServiceSetup;
/** {@link WorkspaceSetup} */
workspace: WorkspaceSetup;
}

/**
Expand Down Expand Up @@ -521,6 +524,8 @@ export interface CoreStart {
crossCompatibility: CrossCompatibilityServiceStart;
/** {@link DynamicConfigServiceStart} */
dynamicConfig: DynamicConfigServiceStart;
/** {@link WorkspaceStart} */
workspace: WorkspaceStart;
}

export {
Expand Down
3 changes: 3 additions & 0 deletions src/core/server/internal_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import { InternalLoggingServiceSetup } from './logging';
import { CoreUsageDataStart } from './core_usage_data';
import { InternalSecurityServiceSetup } from './security/types';
import { CrossCompatibilityServiceStart } from './cross_compatibility';
import { InternalWorkspaceServiceSetup, InternalWorkspaceServiceStart } from './workspace';

/** @internal */
export interface InternalCoreSetup {
Expand All @@ -72,6 +73,7 @@ export interface InternalCoreSetup {
metrics: InternalMetricsServiceSetup;
security: InternalSecurityServiceSetup;
dynamicConfig: InternalDynamicConfigServiceSetup;
workspace: InternalWorkspaceServiceSetup;
}

/**
Expand All @@ -88,6 +90,7 @@ export interface InternalCoreStart {
coreUsageData: CoreUsageDataStart;
crossCompatibility: CrossCompatibilityServiceStart;
dynamicConfig: InternalDynamicConfigServiceStart;
workspace: InternalWorkspaceServiceStart;
}

/**
Expand Down
2 changes: 2 additions & 0 deletions src/core/server/legacy/legacy_service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import { auditTrailServiceMock } from '../audit_trail/audit_trail_service.mock';
import { loggingServiceMock } from '../logging/logging_service.mock';
import { metricsServiceMock } from '../metrics/metrics_service.mock';
import { securityServiceMock } from '../security/security_service.mock';
import { workspaceServiceMock } from '../workspace/mocks';

const MockOsdServer: jest.Mock<OsdServer> = OsdServer as any;

Expand Down Expand Up @@ -114,6 +115,7 @@ beforeEach(() => {
metrics: metricsServiceMock.createInternalSetupContract(),
security: securityServiceMock.createSetupContract(),
dynamicConfig: dynamicConfigServiceMock.createInternalSetupContract(),
workspace: workspaceServiceMock.createInternalSetupContract(),
},
plugins: { 'plugin-id': 'plugin-value' },
uiPlugins: {
Expand Down
2 changes: 2 additions & 0 deletions src/core/server/legacy/legacy_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ export class LegacyService implements CoreService {
getAsyncLocalStore: startDeps.core.dynamicConfig.getAsyncLocalStore,
createStoreFromRequest: startDeps.core.dynamicConfig.createStoreFromRequest,
},
workspace: startDeps.core.workspace,
};

const router = setupDeps.core.http.createRouter('', this.legacyId);
Expand Down Expand Up @@ -308,6 +309,7 @@ export class LegacyService implements CoreService {
auditTrail: setupDeps.core.auditTrail,
getStartServices: () => Promise.resolve([coreStart, startDeps.plugins, {}]),
security: setupDeps.core.security,
workspace: setupDeps.core.workspace,
};

// eslint-disable-next-line @typescript-eslint/no-var-requires
Expand Down
5 changes: 5 additions & 0 deletions src/core/server/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import { coreUsageDataServiceMock } from './core_usage_data/core_usage_data_serv
import { securityServiceMock } from './security/security_service.mock';
import { crossCompatibilityServiceMock } from './cross_compatibility/cross_compatibility.mock';
import { dynamicConfigServiceMock } from './config/dynamic_config_service.mock';
import { workspaceServiceMock } from './workspace/mocks';

export { configServiceMock } from './config/mocks';
export { dynamicConfigServiceMock } from './config/mocks';
Expand Down Expand Up @@ -170,6 +171,7 @@ function createCoreSetupMock({
.mockResolvedValue([createCoreStartMock(), pluginStartDeps, pluginStartContract]),
security: securityServiceMock.createSetupContract(),
dynamicConfigService: dynamicConfigServiceMock.createSetupContract(),
workspace: workspaceServiceMock.createSetupContract(),
};

return mock;
Expand All @@ -187,6 +189,7 @@ function createCoreStartMock() {
coreUsageData: coreUsageDataServiceMock.createStartContract(),
crossCompatibility: crossCompatibilityServiceMock.createStartContract(),
dynamicConfig: dynamicConfigServiceMock.createStartContract(),
workspace: workspaceServiceMock.createStartContract(),
};

return mock;
Expand All @@ -209,6 +212,7 @@ function createInternalCoreSetupMock() {
metrics: metricsServiceMock.createInternalSetupContract(),
security: securityServiceMock.createSetupContract(),
dynamicConfig: dynamicConfigServiceMock.createInternalSetupContract(),
workspace: workspaceServiceMock.createInternalSetupContract(),
};
return setupDeps;
}
Expand All @@ -225,6 +229,7 @@ function createInternalCoreStartMock() {
coreUsageData: coreUsageDataServiceMock.createStartContract(),
crossCompatibility: crossCompatibilityServiceMock.createStartContract(),
dynamicConfig: dynamicConfigServiceMock.createInternalStartContract(),
workspace: workspaceServiceMock.createInternalStartContract(),
};
return startDeps;
}
Expand Down
2 changes: 2 additions & 0 deletions src/core/server/plugins/plugin_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ export function createPluginSetupContext<TPlugin, TPluginDependencies>(
registerAsyncLocalStoreRequestHeader: deps.dynamicConfig.registerAsyncLocalStoreRequestHeader,
getStartService: deps.dynamicConfig.getStartService,
},
workspace: deps.workspace,
};
}

Expand Down Expand Up @@ -282,5 +283,6 @@ export function createPluginStartContext<TPlugin, TPluginDependencies>(
getClient: deps.dynamicConfig.getClient,
createStoreFromRequest: deps.dynamicConfig.createStoreFromRequest,
},
workspace: deps.workspace,
};
}
7 changes: 7 additions & 0 deletions src/core/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ import { InternalCoreSetup, InternalCoreStart, ServiceConfigDescriptor } from '.
import { CoreUsageDataService } from './core_usage_data';
import { CoreRouteHandlerContext } from './core_route_handler_context';
import { DynamicConfigService } from './config/dynamic_config_service';
import { WorkspaceService } from './workspace/workspace_service';

const coreId = Symbol('core');
const rootConfigPath = '';
Expand All @@ -88,6 +89,7 @@ export class Server {
private readonly plugins: PluginsService;
private readonly savedObjects: SavedObjectsService;
private readonly uiSettings: UiSettingsService;
private readonly workspace: WorkspaceService;
private readonly environment: EnvironmentService;
private readonly metrics: MetricsService;
private readonly httpResources: HttpResourcesService;
Expand Down Expand Up @@ -130,6 +132,7 @@ export class Server {
this.opensearch = new OpenSearchService(core);
this.savedObjects = new SavedObjectsService(core);
this.uiSettings = new UiSettingsService(core);
this.workspace = new WorkspaceService(core);
this.capabilities = new CapabilitiesService(core);
this.environment = new EnvironmentService(core);
this.metrics = new MetricsService(core);
Expand Down Expand Up @@ -199,6 +202,7 @@ export class Server {
http: httpSetup,
savedObjects: savedObjectsSetup,
});
const workspaceSetup = await this.workspace.setup();

const metricsSetup = await this.metrics.setup({ http: httpSetup });

Expand Down Expand Up @@ -247,6 +251,7 @@ export class Server {
metrics: metricsSetup,
security: securitySetup,
dynamicConfig: dynamicConfigServiceSetup,
workspace: workspaceSetup,
};

const pluginsSetup = await this.plugins.setup(coreSetup);
Expand Down Expand Up @@ -285,6 +290,7 @@ export class Server {
soStartSpan?.end();
const capabilitiesStart = this.capabilities.start();
const uiSettingsStart = await this.uiSettings.start();
const workspaceStart = await this.workspace.start();
const metricsStart = await this.metrics.start();
const httpStart = this.http.getStartContract();
const coreUsageDataStart = this.coreUsageData.start({
Expand All @@ -308,6 +314,7 @@ export class Server {
coreUsageData: coreUsageDataStart,
crossCompatibility: crossCompatibilityServiceStart,
dynamicConfig: dynamicConfigServiceStart,
workspace: workspaceStart,
};

const pluginsStart = await this.plugins.start(this.coreStart);
Expand Down
19 changes: 19 additions & 0 deletions src/core/server/workspace/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { PublicMethodsOf } from '@osd/utility-types';

import {
InternalWorkspaceServiceSetup,
InternalWorkspaceServiceStart,
WorkspaceService,
} from './workspace_service';

export { InternalWorkspaceServiceSetup, InternalWorkspaceServiceStart } from './workspace_service';

export type WorkspaceSetup = InternalWorkspaceServiceSetup;
export type WorkspaceStart = InternalWorkspaceServiceStart;

export type IWorkspaceService = PublicMethodsOf<WorkspaceService>;
43 changes: 43 additions & 0 deletions src/core/server/workspace/mocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { IWorkspaceService } from '.';
import { InternalWorkspaceServiceSetup, InternalWorkspaceServiceStart } from './workspace_service';

const createWorkspaceServiceMock = () => {
const mocked: jest.Mocked<IWorkspaceService> = {

Check warning on line 10 in src/core/server/workspace/mocks.ts

View check run for this annotation

Codecov / codecov/patch

src/core/server/workspace/mocks.ts#L10

Added line #L10 was not covered by tests
setup: jest.fn().mockReturnValue(createInternalSetupContractMock()),
start: jest.fn().mockReturnValue({}),
stop: jest.fn(),
};

return mocked;

Check warning on line 16 in src/core/server/workspace/mocks.ts

View check run for this annotation

Codecov / codecov/patch

src/core/server/workspace/mocks.ts#L16

Added line #L16 was not covered by tests
};

const createInternalSetupContractMock = () => {
const mocked: jest.Mocked<InternalWorkspaceServiceSetup> = {
isWorkspaceEnabled: jest.fn(),
};

return mocked;
};
const createSetupContractMock = createInternalSetupContractMock;

const createInternalStartContractMock = () => {
const mocked: jest.Mocked<InternalWorkspaceServiceStart> = {
isWorkspaceEnabled: jest.fn(),
};

return mocked;
};
const createStartContractMock = createInternalStartContractMock;

export const workspaceServiceMock = {
create: createWorkspaceServiceMock,
createInternalSetupContract: createInternalSetupContractMock,
createInternalStartContract: createInternalStartContractMock,
createSetupContract: createSetupContractMock,
createStartContract: createStartContractMock,
};
53 changes: 53 additions & 0 deletions src/core/server/workspace/workspace_service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { Observable } from 'rxjs';
import { first } from 'rxjs/operators';

import { CoreService } from '../../types';
import { CoreContext } from '../core_context';
import { Logger } from '../logging';

export interface InternalWorkspaceServiceSetup {
isWorkspaceEnabled: () => boolean;
}

export interface InternalWorkspaceServiceStart {
isWorkspaceEnabled: () => boolean;
}

/** @internal */
export class WorkspaceService
implements CoreService<InternalWorkspaceServiceSetup, InternalWorkspaceServiceStart> {
private readonly log: Logger;
private readonly config$: Observable<{ enabled: boolean }>;

constructor(private readonly coreContext: CoreContext) {
this.log = this.coreContext.logger.get('workspace-service');
this.config$ = this.coreContext.configService.atPath<{ enabled: boolean }>('workspace');
}

public async setup(): Promise<InternalWorkspaceServiceSetup> {
this.log.debug('Setting up workspace service');

const workspaceConfig = await this.config$.pipe(first()).toPromise();

return {
isWorkspaceEnabled: () => workspaceConfig.enabled,

Check warning on line 38 in src/core/server/workspace/workspace_service.ts

View check run for this annotation

Codecov / codecov/patch

src/core/server/workspace/workspace_service.ts#L38

Added line #L38 was not covered by tests
};
}

public async start(): Promise<InternalWorkspaceServiceStart> {
this.log.debug('Starting workspace service');

const workspaceConfig = await this.config$.pipe(first()).toPromise();

return {
isWorkspaceEnabled: () => workspaceConfig.enabled,

Check warning on line 48 in src/core/server/workspace/workspace_service.ts

View check run for this annotation

Codecov / codecov/patch

src/core/server/workspace/workspace_service.ts#L48

Added line #L48 was not covered by tests
};
}

public async stop() {}
}
1 change: 1 addition & 0 deletions src/core/types/ui_settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export interface DeprecationSettings {
export enum UiSettingScope {
GLOBAL = 'global',
USER = 'user',
WORKSPACE = 'workspace',
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,23 @@
const all = config.getAll();
const userSettingsEnabled = config.get('theme:enableUserControl');
return Object.entries(all)
.filter(([, setting]) => setting.scope !== UiSettingScope.USER)
.filter(([, setting]) => {
const scope = setting.scope;
// if scope is not defined, then it's a global ui setting
if (!scope) {
return true;
}

if (typeof scope === 'string') {
return scope === UiSettingScope.GLOBAL;

Check warning on line 184 in src/plugins/advanced_settings/public/management_app/advanced_settings.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/advanced_settings/public/management_app/advanced_settings.tsx#L184

Added line #L184 was not covered by tests
}

if (Array.isArray(scope)) {
return scope.includes(UiSettingScope.GLOBAL);

Check warning on line 188 in src/plugins/advanced_settings/public/management_app/advanced_settings.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/advanced_settings/public/management_app/advanced_settings.tsx#L188

Added line #L188 was not covered by tests
}

return false;

Check warning on line 191 in src/plugins/advanced_settings/public/management_app/advanced_settings.tsx

View check run for this annotation

Codecov / codecov/patch

src/plugins/advanced_settings/public/management_app/advanced_settings.tsx#L191

Added line #L191 was not covered by tests
})
.map((setting) => {
return toEditableConfig({
def: setting[1],
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/data/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
this.autocompleteService.setup(core);
this.dqlTelemetryService.setup(core, { usageCollection });

core.uiSettings.register(getUiSettings());
core.uiSettings.register(getUiSettings(core.workspace.isWorkspaceEnabled()));

Check warning on line 109 in src/plugins/data/server/plugin.ts

View check run for this annotation

Codecov / codecov/patch

src/plugins/data/server/plugin.ts#L109

Added line #L109 was not covered by tests

const searchSetup = await this.searchService.setup(core, {
registerFunction: expressions.registerFunction,
Expand Down
9 changes: 6 additions & 3 deletions src/plugins/data/server/ui_settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@

import { i18n } from '@osd/i18n';
import { schema } from '@osd/config-schema';
import { UiSettingsParams } from 'opensearch-dashboards/server';
// @ts-ignore untyped module
import numeralLanguages from '@elastic/numeral/languages';
import { DEFAULT_QUERY_LANGUAGE, UI_SETTINGS } from '../common';
import { UiSettingsParams, UiSettingScope } from '../../../core/server';

const luceneQueryLanguageLabel = i18n.translate('data.advancedSettings.searchQueryLanguageLucene', {
defaultMessage: 'Lucene',
Expand Down Expand Up @@ -79,7 +79,9 @@ const numeralLanguageIds = [
}),
];

export function getUiSettings(): Record<string, UiSettingsParams<unknown>> {
export function getUiSettings(
workspaceEnabled: boolean
): Record<string, UiSettingsParams<unknown>> {
return {
[UI_SETTINGS.META_FIELDS]: {
name: i18n.translate('data.advancedSettings.metaFieldsTitle', {
Expand Down Expand Up @@ -200,6 +202,7 @@ export function getUiSettings(): Record<string, UiSettingsParams<unknown>> {
defaultMessage: 'The index to access if no index is set',
}),
schema: schema.nullable(schema.string()),
scope: workspaceEnabled ? UiSettingScope.WORKSPACE : UiSettingScope.GLOBAL,
},
[UI_SETTINGS.COURIER_IGNORE_FILTER_IF_FIELD_NOT_IN_INDEX]: {
name: i18n.translate('data.advancedSettings.courier.ignoreFilterTitle', {
Expand Down Expand Up @@ -757,7 +760,7 @@ export function getUiSettings(): Record<string, UiSettingsParams<unknown>> {
}),
value: ['none'],
description: i18n.translate('data.advancedSettings.searchQueryLanguageBlocklistText', {
defaultMessage: `Additional languages that are blocked from being used in the query editor.
defaultMessage: `Additional languages that are blocked from being used in the query editor.
<strong>Note</strong>: DQL and Lucene will not be blocked even if set.`,
}),
schema: schema.arrayOf(schema.string()),
Expand Down
Loading