Skip to content

Commit

Permalink
add experimental to user personal settings and support i18n (#8080)
Browse files Browse the repository at this point in the history
Signed-off-by: Hailong Cui <[email protected]>
  • Loading branch information
Hailong-am authored Sep 9, 2024
1 parent cedba8e commit dfc7def
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 44 deletions.
2 changes: 1 addition & 1 deletion changelogs/fragments/7953.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
feat:
- [Workspace] Support user personal settings ([#7953](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7953))
- [Experimental] Support user personal settings ([#7953](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7953))
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { Logger } from '../../logging';

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

interface Options {
savedObjectsClient: SavedObjectsClientContract;
Expand Down Expand Up @@ -70,7 +70,7 @@ export async function createOrUpgradeSavedConfig(
);

try {
const docId = generateDocId(version, scope);
const docId = buildDocIdWithScope(version, scope);
// create the new SavedConfig
await savedObjectsClient.create('config', attributes, { id: docId });
} catch (error) {
Expand Down
8 changes: 3 additions & 5 deletions src/core/server/ui_settings/ui_settings_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import {
UiSettingScope,
} from './types';
import { CannotOverrideError } from './ui_settings_errors';
import { generateDocId } from './utils';
import { buildDocIdWithScope } from './utils';

export interface UiSettingsServiceOptions {
type: string;
Expand Down Expand Up @@ -167,8 +167,6 @@ export class UiSettingsClient implements IUiSettingsClient {
}

async setMany(changes: Record<string, any>, scope?: UiSettingScope) {
// log changes and scope
this.log.debug(`UiSettingsClient.setMany: ${JSON.stringify({ changes, scope })}`);
this.onWriteHook(changes, scope);

if (scope) {
Expand Down Expand Up @@ -310,7 +308,7 @@ export class UiSettingsClient implements IUiSettingsClient {
}) {
changes = this.translateChanges(changes, 'timeline', 'timelion');
try {
const docId = generateDocId(this.id, scope);
const docId = buildDocIdWithScope(this.id, scope);
await this.savedObjectsClient.update(this.type, docId, changes);
} catch (error) {
if (!SavedObjectsErrorHelpers.isNotFoundError(error) || !autoCreateOrUpgradeIfMissing) {
Expand Down Expand Up @@ -341,7 +339,7 @@ export class UiSettingsClient implements IUiSettingsClient {
scope,
}: ReadOptions = {}): Promise<Record<string, any>> {
try {
const docId = generateDocId(this.id, scope);
const docId = buildDocIdWithScope(this.id, scope);
const resp = await this.savedObjectsClient.get<Record<string, any>>(this.type, docId);
return this.translateChanges(resp.attributes, 'timelion', 'timeline');
} catch (error) {
Expand Down
2 changes: 1 addition & 1 deletion src/core/server/ui_settings/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { UiSettingScope } from './types';

export const CURRENT_USER_PLACEHOLDER = '<current_user>';

export const generateDocId = (id: string, scope?: UiSettingScope) => {
export const buildDocIdWithScope = (id: string, scope?: UiSettingScope) => {
if (scope === UiSettingScope.USER) {
return `${CURRENT_USER_PLACEHOLDER}_${id}`;
}
Expand Down
2 changes: 1 addition & 1 deletion src/core/types/ui_settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export interface DeprecationSettings {

/**
* UiSettings scope options.
* @public
* @experimental
*/
export enum UiSettingScope {
GLOBAL = 'global',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import {
CoreStart,
ACL,
SavedObjectsCreateOptions,
SavedObjectsFindOptions,
SavedObjectsFindResponse,
OpenSearchDashboardsRequest,
} from '../../../../core/server';
import { Logger, CURRENT_USER_PLACEHOLDER } from '../../../../core/server';
Expand Down Expand Up @@ -60,8 +58,6 @@ export class UserUISettingsClientWrapper {
): Promise<SavedObject<T>> => {
if (type === 'config') {
const docId = this.normalizeDocId(id, wrapperOptions.request, this.core);
this.logger.debug(`Getting config with original: ${id} normalizeDocId: ${docId}`);
// user level
return wrapperOptions.client.get(type, docId, options);
}

Expand All @@ -76,7 +72,6 @@ export class UserUISettingsClientWrapper {
): Promise<SavedObjectsUpdateResponse<T>> => {
if (type === 'config') {
const docId = this.normalizeDocId(id, wrapperOptions.request, this.core);
this.logger.debug(`Getting config with original: ${id} normalizeDocId: ${docId}`);
// update user level settings
return await wrapperOptions.client.update(type, docId, attributes, options);
}
Expand Down
117 changes: 88 additions & 29 deletions src/plugins/workspace/public/components/workspace_list/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ export const WorkspaceListInner = ({
const emptyStateMessage = useMemo(() => {
return (
<EuiEmptyPrompt
iconType="spacesApp"
iconType="wsSelector"
title={
<h3>
{i18n.translate('workspace.workspaceList.emptyState.title', {
Expand Down Expand Up @@ -222,7 +222,9 @@ export const WorkspaceListInner = ({

const handleCopyId = (id: string) => {
copyToClipboard(id);
notifications?.toasts.addSuccess('Workspace ID copied');
notifications?.toasts.addSuccess(
i18n.translate('workspace.copyWorkspaceId.message', { defaultMessage: 'Workspace ID copied' })
);
};

const handleSwitchWorkspace = useCallback(
Expand All @@ -239,11 +241,19 @@ export const WorkspaceListInner = ({
const set = await uiSettings?.set(DEFAULT_WORKSPACE, item.id);
if (set) {
setDefaultWorkspaceId(item.id);
notifications?.toasts.addSuccess(`Default workspace been set to ${item.name}`);
notifications?.toasts.addSuccess(
i18n.translate('workspace.setDefaultWorkspace.success.message', {
defaultMessage: 'Default workspace been set to {name}',
values: { name: item.name },
})
);
} else {
// toast
notifications?.toasts.addWarning(
`Failed to set workspace ${item.name} as default workspace.`
i18n.translate('workspace.setDefaultWorkspace.error.message', {
defaultMessage: 'Failed to set workspace {name} as default workspace.',
values: { name: item.name },
})
);
}
},
Expand Down Expand Up @@ -349,7 +359,7 @@ export const WorkspaceListInner = ({
const columnsWithoutActions = [
{
field: 'name',
name: 'Name',
name: i18n.translate('workspace.list.columns.name.title', { defaultMessage: 'Name' }),
width: '18%',
sortable: true,
render: (name: string, item: WorkspaceAttributeWithPermission) => (
Expand All @@ -361,7 +371,11 @@ export const WorkspaceListInner = ({
</EuiFlexItem>
{item.id === defaultWorkspaceId && (
<EuiFlexItem grow={false}>
<EuiBadge>Default workspace</EuiBadge>
<EuiBadge>
{i18n.translate('workspace.defaultWorkspace.title', {
defaultMessage: 'Default workspace',
})}
</EuiBadge>
</EuiFlexItem>
)}
</EuiFlexGroup>
Expand All @@ -372,13 +386,15 @@ export const WorkspaceListInner = ({

{
field: 'useCase',
name: 'Use case',
name: i18n.translate('workspace.list.columns.useCase.title', { defaultMessage: 'Use case' }),
width: '12%',
},

{
field: 'description',
name: 'Description',
name: i18n.translate('workspace.list.columns.description.title', {
defaultMessage: 'Description',
}),
width: '15%',
render: (description: string) => (
<EuiToolTip
Expand All @@ -395,7 +411,7 @@ export const WorkspaceListInner = ({
},
{
field: 'permissions',
name: 'Owners',
name: i18n.translate('workspace.list.columns.owners.title', { defaultMessage: 'Owners' }),
width: '15%',
render: (
permissions: WorkspaceAttributeWithPermission['permissions'],
Expand All @@ -407,12 +423,21 @@ export const WorkspaceListInner = ({
},
{
field: 'permissionMode',
name: 'Permissions',
name: i18n.translate('workspace.list.columns.permissions.title', {
defaultMessage: 'Permissions',
}),
width: '6%',
render: (permissionMode: WorkspaceAttributeWithPermission['permissionMode']) => {
return isDashboardAdmin ? (
<EuiToolTip position="right" content="You are dashboard admin">
<EuiText size="xs">Admin</EuiText>
<EuiToolTip
position="right"
content={i18n.translate('workspace.role.admin.description', {
defaultMessage: 'You are dashboard admin',
})}
>
<EuiText size="xs">
{i18n.translate('workspace.role.admin.name', { defaultMessage: 'Admin' })}
</EuiText>
</EuiToolTip>
) : (
startCase(permissionMode)
Expand All @@ -421,7 +446,9 @@ export const WorkspaceListInner = ({
},
{
field: 'lastUpdatedTime',
name: 'Last updated',
name: i18n.translate('workspace.list.columns.lastUpdated.title', {
defaultMessage: 'Last updated',
}),
width: '15%',
truncateText: false,
render: (lastUpdatedTime: string) => {
Expand All @@ -431,55 +458,85 @@ export const WorkspaceListInner = ({
{
field: 'dataSources',
width: '15%',
name: 'Data sources',
name: i18n.translate('workspace.list.columns.dataSources.title', {
defaultMessage: 'Data sources',
}),
render: (dataSources: string[], item: WorkspaceAttributeWithPermission) => {
return renderDataWithMoreBadge(dataSources, 2, item.id, DetailTab.DataSources);
},
},
];
const allActions = [
{
name: <EuiText key="copyId">Copy ID</EuiText>,
name: (
<EuiText key="copyId">
{i18n.translate('workspace.list.actions.copyId.name', { defaultMessage: 'Copy ID' })}
</EuiText>
),
icon: 'copy',
type: 'icon',
description: 'Copy workspace id',
description: i18n.translate('workspace.list.actions.copyId.description', {
defaultMessage: 'Copy workspace id',
}),
'data-test-subj': 'workspace-list-copy-id-icon',
onClick: ({ id }: WorkspaceAttribute) => handleCopyId(id),
},
{
name: <EuiText key="edit">Edit</EuiText>,
name: (
<EuiText key="edit">
{i18n.translate('workspace.list.actions.edit.name', { defaultMessage: 'Edit' })}
</EuiText>
),
icon: 'pencil',
type: 'icon',
description: 'Edit workspace',
description: i18n.translate('workspace.list.actions.edit.description', {
defaultMessage: 'Edit workspace',
}),
'data-test-subj': 'workspace-list-edit-icon',
onClick: ({ id }: WorkspaceAttribute) => handleSwitchWorkspace(id),
},
{
name: <EuiText key="setDefault">Set as my default</EuiText>,
name: (
<EuiText key="setDefault">
{i18n.translate('workspace.list.actions.setDefault.name', {
defaultMessage: 'Set as my default',
})}
</EuiText>
),
icon: 'flag',
type: 'icon',
description: 'Set as default workspace',
description: i18n.translate('workspace.list.actions.setDefault.description', {
defaultMessage: 'Set as my default workspace',
}),
'data-test-subj': 'workspace-list-set-default-icon',
onClick: (item: WorkspaceAttribute) => handleSetDefaultWorkspace(item),
},
{
name: <EuiText key="leave">Leave</EuiText>,
name: (
<EuiText key="leave">
{i18n.translate('workspace.list.actions.leave.name', { defaultMessage: 'Leave' })}
</EuiText>
),
icon: 'exit',
type: 'icon',
description: 'Leave workspace',
description: i18n.translate('workspace.list.actions.leave.description', {
defaultMessage: 'Leave workspace',
}),
'data-test-subj': 'workspace-list-leave-icon',
available: () => false,
},
{
name: (
<EuiText color="danger" key="delete">
Delete
{i18n.translate('workspace.list.actions.delete.name', { defaultMessage: 'Delete' })}
</EuiText>
),
icon: () => <EuiIcon type="trash" size="m" color="danger" />,
type: 'icon',
isPrimary: false,
description: 'Delete workspace',
description: i18n.translate('workspace.list.actions.delete.description', {
defaultMessage: 'Delete workspace',
}),
'data-test-subj': 'workspace-list-delete-icon',
available: () => isDashboardAdmin,
onClick: (item: WorkspaceAttribute) => {
Expand All @@ -497,12 +554,12 @@ export const WorkspaceListInner = ({
return column.field;
});
const availableColumns = columnsWithoutActions
.filter((column) => !excludedColumns.includes(column.field))
.filter((column) => {
return (
!includedColumnsFields ||
includedColumnsFields.length === 0 ||
includedColumnsFields.includes(column.field)
(!includedColumnsFields ||
includedColumnsFields.length === 0 ||
includedColumnsFields.includes(column.field)) &&
!excludedColumns.includes(column.field)
);
})
.map((column) => {
Expand All @@ -515,7 +572,9 @@ export const WorkspaceListInner = ({

const actionColumns = [
{
name: 'Actions',
name: i18n.translate('workspace.list.columns.actions.title', {
defaultMessage: 'Actions',
}),
field: '',
actions: availableActions,
},
Expand Down

0 comments on commit dfc7def

Please sign in to comment.