Skip to content

Commit

Permalink
[Manual Backport 2.x] [Workspace] Add user settings (#8057)
Browse files Browse the repository at this point in the history
* [Workspace] Add User level setting (#7953)

(cherry picked from commit 569b70d)
Signed-off-by: Hailong Cui <[email protected]>

* add experimental to user personal settings and support i18n

Signed-off-by: Hailong Cui <[email protected]>

---------

Signed-off-by: Hailong Cui <[email protected]>
  • Loading branch information
Hailong-am authored Sep 7, 2024
1 parent cc5f3cb commit eccf54f
Show file tree
Hide file tree
Showing 52 changed files with 2,671 additions and 283 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/7953.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
feat:
- [Experimental] Support user personal settings ([#7953](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7953))
2 changes: 2 additions & 0 deletions src/core/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ export {
NavGroupType,
NavGroupStatus,
WorkspaceAttributeWithPermission,
UiSettingScope,
PermissionModeId,
} from '../types';

export {
Expand Down
4 changes: 3 additions & 1 deletion src/core/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,8 @@ export {
StringValidation,
StringValidationRegex,
StringValidationRegexString,
CURRENT_USER_PLACEHOLDER,
UiSettingScope,
} from './ui_settings';

export {
Expand All @@ -369,7 +371,7 @@ export {
MetricsServiceStart,
} from './metrics';

export { AppCategory, WorkspaceAttribute } from '../types';
export { AppCategory, WorkspaceAttribute, PermissionModeId } from '../types';
export { DEFAULT_APP_CATEGORIES, WORKSPACE_TYPE, DEFAULT_NAV_GROUPS } from '../utils';

export {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ describe('uiSettings/createOrUpgradeSavedConfig', function () {
Object {
"newVersion": "4.0.1",
"prevVersion": "4.0.0",
"scope": undefined,
},
],
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,25 +35,33 @@ import { SavedObjectsErrorHelpers } from '../../saved_objects/';
import { Logger } from '../../logging';

import { getUpgradeableConfig } from './get_upgradeable_config';
import { UiSettingScope } from '../types';
import { buildDocIdWithScope } from '../utils';

interface Options {
savedObjectsClient: SavedObjectsClientContract;
version: string;
buildNum: number;
log: Logger;
handleWriteErrors: boolean;
scope?: UiSettingScope;
}

export async function createOrUpgradeSavedConfig(
options: Options
): Promise<Record<string, any> | undefined> {
const { savedObjectsClient, version, buildNum, log, handleWriteErrors } = options;
const { savedObjectsClient, version, buildNum, log, handleWriteErrors, scope } = options;

// try to find an older config we can upgrade
const upgradeableConfig = await getUpgradeableConfig({
savedObjectsClient,
version,
});
let upgradeableConfig;
if (scope === UiSettingScope.USER) {
upgradeableConfig = undefined;
} else {
upgradeableConfig = await getUpgradeableConfig({
savedObjectsClient,
version,
});
}

// default to the attributes of the upgradeableConfig if available
const attributes = defaults(
Expand All @@ -62,8 +70,9 @@ export async function createOrUpgradeSavedConfig(
);

try {
const docId = buildDocIdWithScope(version, scope);
// create the new SavedConfig
await savedObjectsClient.create('config', attributes, { id: version });
await savedObjectsClient.create('config', attributes, { id: docId });
} catch (error) {
if (handleWriteErrors) {
if (SavedObjectsErrorHelpers.isConflictError(error)) {
Expand All @@ -85,6 +94,7 @@ export async function createOrUpgradeSavedConfig(
log.debug(`Upgrade config from ${upgradeableConfig.id} to ${version}`, {
prevVersion: upgradeableConfig.id,
newVersion: version,
scope,
});
}
}
3 changes: 3 additions & 0 deletions src/core/server/ui_settings/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,7 @@ export {
StringValidation,
StringValidationRegex,
StringValidationRegexString,
UiSettingScope,
} from './types';

export { CURRENT_USER_PLACEHOLDER } from './utils';
10 changes: 9 additions & 1 deletion src/core/server/ui_settings/routes/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,17 @@ import { schema } from '@osd/config-schema';
import { IRouter } from '../../http';
import { SavedObjectsErrorHelpers } from '../../saved_objects';
import { CannotOverrideError } from '../ui_settings_errors';
import { UiSettingScope } from '../types';

const validate = {
params: schema.object({
key: schema.string(),
}),
query: schema.object({
scope: schema.maybe(
schema.oneOf([schema.literal(UiSettingScope.GLOBAL), schema.literal(UiSettingScope.USER)])
),
}),
};

export function registerDeleteRoute(router: IRouter) {
Expand All @@ -47,7 +53,9 @@ export function registerDeleteRoute(router: IRouter) {
try {
const uiSettingsClient = context.core.uiSettings.client;

await uiSettingsClient.remove(request.params.key);
const { scope } = request.query;

await uiSettingsClient.remove(request.params.key, scope);

return response.ok({
body: {
Expand Down
16 changes: 14 additions & 2 deletions src/core/server/ui_settings/routes/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,30 @@
* under the License.
*/

import { schema } from '@osd/config-schema';

import { IRouter } from '../../http';
import { SavedObjectsErrorHelpers } from '../../saved_objects';
import { UiSettingScope } from '../types';

const validate = {
query: schema.object({
scope: schema.maybe(
schema.oneOf([schema.literal(UiSettingScope.GLOBAL), schema.literal(UiSettingScope.USER)])
),
}),
};

export function registerGetRoute(router: IRouter) {
router.get(
{ path: '/api/opensearch-dashboards/settings', validate: false },
{ path: '/api/opensearch-dashboards/settings', validate },
async (context, request, response) => {
try {
const uiSettingsClient = context.core.uiSettings.client;
const { scope } = request.query;
return response.ok({
body: {
settings: await uiSettingsClient.getUserProvided(),
settings: await uiSettingsClient.getUserProvided(scope),
},
});
} catch (error) {
Expand Down
11 changes: 9 additions & 2 deletions src/core/server/ui_settings/routes/set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { schema, ValidationError } from '@osd/config-schema';
import { IRouter } from '../../http';
import { SavedObjectsErrorHelpers } from '../../saved_objects';
import { CannotOverrideError } from '../ui_settings_errors';
import { UiSettingScope } from '../types';

const validate = {
params: schema.object({
Expand All @@ -41,6 +42,11 @@ const validate = {
body: schema.object({
value: schema.any(),
}),
query: schema.object({
scope: schema.maybe(
schema.oneOf([schema.literal(UiSettingScope.GLOBAL), schema.literal(UiSettingScope.USER)])
),
}),
};

export function registerSetRoute(router: IRouter) {
Expand All @@ -52,12 +58,13 @@ export function registerSetRoute(router: IRouter) {

const { key } = request.params;
const { value } = request.body;
const { scope } = request.query;

await uiSettingsClient.set(key, value);
await uiSettingsClient.set(key, value, scope);

return response.ok({
body: {
settings: await uiSettingsClient.getUserProvided(),
settings: await uiSettingsClient.getUserProvided(scope),
},
});
} catch (error) {
Expand Down
11 changes: 9 additions & 2 deletions src/core/server/ui_settings/routes/set_many.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,17 @@ import { schema, ValidationError } from '@osd/config-schema';
import { IRouter } from '../../http';
import { SavedObjectsErrorHelpers } from '../../saved_objects';
import { CannotOverrideError } from '../ui_settings_errors';
import { UiSettingScope } from '../types';

const validate = {
body: schema.object({
changes: schema.object({}, { unknowns: 'allow' }),
}),
query: schema.object({
scope: schema.maybe(
schema.oneOf([schema.literal(UiSettingScope.GLOBAL), schema.literal(UiSettingScope.USER)])
),
}),
};

export function registerSetManyRoute(router: IRouter) {
Expand All @@ -48,12 +54,13 @@ export function registerSetManyRoute(router: IRouter) {
const uiSettingsClient = context.core.uiSettings.client;

const { changes } = request.body;
const { scope } = request.query;

await uiSettingsClient.setMany(changes);
await uiSettingsClient.setMany(changes, scope);

return response.ok({
body: {
settings: await uiSettingsClient.getUserProvided(),
settings: await uiSettingsClient.getUserProvided(scope),
},
});
} catch (error) {
Expand Down
24 changes: 16 additions & 8 deletions src/core/server/ui_settings/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@
*/

import { SavedObjectsClientContract } from '../saved_objects/types';
import { UiSettingsParams, UserProvidedValues, PublicUiSettingsParams } from '../../types';
import {
UiSettingsParams,
UserProvidedValues,
PublicUiSettingsParams,
UiSettingScope,
} from '../../types';
export {
UiSettingsParams,
PublicUiSettingsParams,
Expand All @@ -40,6 +45,7 @@ export {
ImageValidation,
UiSettingsType,
UserProvidedValues,
UiSettingScope,
} from '../../types';

/**
Expand All @@ -66,31 +72,33 @@ export interface IUiSettingsClient {
/**
* Retrieves uiSettings values set by the user with fallbacks to default values if not specified.
*/
get: <T = any>(key: string) => Promise<T>;
get: <T = any>(key: string, scope?: UiSettingScope) => Promise<T>;
/**
* Retrieves a set of all uiSettings values set by the user with fallbacks to default values if not specified.
*/
getAll: <T = any>() => Promise<Record<string, T>>;
getAll: <T = any>(scope?: UiSettingScope) => Promise<Record<string, T>>;
/**
* Retrieves a set of all uiSettings values set by the user.
*/
getUserProvided: <T = any>() => Promise<Record<string, UserProvidedValues<T>>>;
getUserProvided: <T = any>(
scope?: UiSettingScope
) => Promise<Record<string, UserProvidedValues<T>>>;
/**
* Writes multiple uiSettings values and marks them as set by the user.
*/
setMany: (changes: Record<string, any>) => Promise<void>;
setMany: (changes: Record<string, any>, scope?: UiSettingScope) => Promise<void>;
/**
* Writes uiSettings value and marks it as set by the user.
*/
set: (key: string, value: any) => Promise<void>;
set: (key: string, value: any, scope?: UiSettingScope) => Promise<void>;
/**
* Removes uiSettings value by key.
*/
remove: (key: string) => Promise<void>;
remove: (key: string, scope?: UiSettingScope) => Promise<void>;
/**
* Removes multiple uiSettings values by keys.
*/
removeMany: (keys: string[]) => Promise<void>;
removeMany: (keys: string[], scope?: UiSettingScope) => Promise<void>;
/**
* Shows whether the uiSettings value set by the user.
*/
Expand Down
Loading

0 comments on commit eccf54f

Please sign in to comment.