diff --git a/changelogs/fragments/8592.yml b/changelogs/fragments/8592.yml
new file mode 100644
index 000000000000..fd4fae271865
--- /dev/null
+++ b/changelogs/fragments/8592.yml
@@ -0,0 +1,2 @@
+fix:
+- Workspace selector style alignment ([#8592](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/8592))
\ No newline at end of file
diff --git a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.test.tsx b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.test.tsx
index 71a7632d6f08..f70d5efb23a0 100644
--- a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.test.tsx
+++ b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.test.tsx
@@ -83,7 +83,7 @@ describe('', () => {
const selectButton = screen.getByTestId('workspace-select-button');
fireEvent.click(selectButton);
- expect(screen.getByText(`viewed ${moment(1234567890).fromNow()}`)).toBeInTheDocument();
+ expect(screen.getByText(`Viewed ${moment(1234567890).fromNow()}`)).toBeInTheDocument();
});
it('should be able to display empty state when the workspace list is empty', () => {
diff --git a/src/plugins/workspace/public/components/workspace_picker_content/workspace_picker_content.tsx b/src/plugins/workspace/public/components/workspace_picker_content/workspace_picker_content.tsx
index 2bbb2c613173..cf8ce3324233 100644
--- a/src/plugins/workspace/public/components/workspace_picker_content/workspace_picker_content.tsx
+++ b/src/plugins/workspace/public/components/workspace_picker_content/workspace_picker_content.tsx
@@ -27,18 +27,6 @@ import { WorkspaceUseCase } from '../../types';
import { validateWorkspaceColor } from '../../../common/utils';
import { getFirstUseCaseOfFeatureConfigs, getUseCaseUrl } from '../../utils';
-function sortBy(getkey: (item: T) => number | undefined) {
- return (a: T, b: T): number => {
- const aValue = getkey(a);
- const bValue = getkey(b);
-
- if (aValue === undefined) return 1;
- if (bValue === undefined) return -1;
-
- return bValue - aValue;
- };
-}
-
const searchFieldPlaceholder = i18n.translate('workspace.menu.search.placeholder', {
defaultMessage: 'Search workspace name',
});
@@ -48,7 +36,7 @@ const getValidWorkspaceColor = (color?: string) =>
interface UpdatedWorkspaceObject extends WorkspaceObject {
accessTimeStamp?: number;
- accessTime?: string;
+ accessTimeDescription?: string;
}
interface Props {
coreStart: CoreStart;
@@ -57,6 +45,21 @@ interface Props {
isInTwoLines?: boolean;
}
+const sortByRecentVisitedAndAlphabetical = (
+ ws1: UpdatedWorkspaceObject,
+ ws2: UpdatedWorkspaceObject
+) => {
+ // First, sort by accessTimeStamp in descending order (if both have timestamps)
+ if (ws1?.accessTimeStamp && ws2?.accessTimeStamp) {
+ return ws2.accessTimeStamp - ws1.accessTimeStamp;
+ }
+ // If one has a timestamp and the other does not, prioritize the one with the timestamp
+ if (ws1.accessTimeStamp) return -1;
+ if (ws2.accessTimeStamp) return 1;
+ // If neither has a timestamp, sort alphabetically by name
+ return ws1.name.localeCompare(ws2.name);
+};
+
export const WorkspacePickerContent = ({
coreStart,
registeredUseCases$,
@@ -72,18 +75,23 @@ export const WorkspacePickerContent = ({
const recentWorkspaces = recentWorkspaceManager.getRecentWorkspaces();
const updatedList = workspaceList.map((workspace) => {
const recentWorkspace = recentWorkspaces.find((recent) => recent.id === workspace.id);
-
- if (recentWorkspace) {
- return {
- ...workspace,
- accessTimeStamp: recentWorkspace.timestamp,
- accessTime: `viewed ${moment(recentWorkspace.timestamp).fromNow()}`,
- };
- }
- return workspace as UpdatedWorkspaceObject;
+ return {
+ ...workspace,
+ accessTimeStamp: recentWorkspace?.timestamp,
+ accessTimeDescription: recentWorkspace
+ ? i18n.translate('workspace.picker.accessTime.description', {
+ defaultMessage: 'Viewed {timeLabel}',
+ values: {
+ timeLabel: moment(recentWorkspace.timestamp).fromNow(),
+ },
+ })
+ : i18n.translate('workspace.picker.accessTime.not.visited', {
+ defaultMessage: 'Not visited recently',
+ }),
+ };
});
- return updatedList.sort(sortBy((workspace) => workspace.accessTimeStamp));
+ return updatedList.sort(sortByRecentVisitedAndAlphabetical);
}, [workspaceList]);
const queryFromList = ({ list, query }: { list: UpdatedWorkspaceObject[]; query: string }) => {
@@ -186,7 +194,7 @@ export const WorkspacePickerContent = ({
- {workspace.accessTime}
+ {workspace.accessTimeDescription}
@@ -211,7 +219,7 @@ export const WorkspacePickerContent = ({
- {workspace.accessTime}
+ {workspace.accessTimeDescription}
diff --git a/src/plugins/workspace/public/components/workspace_selector/workspace_selector.scss b/src/plugins/workspace/public/components/workspace_selector/workspace_selector.scss
index 685d823b30c6..9ac8ef1fa86e 100644
--- a/src/plugins/workspace/public/components/workspace_selector/workspace_selector.scss
+++ b/src/plugins/workspace/public/components/workspace_selector/workspace_selector.scss
@@ -7,3 +7,32 @@
transition: none !important;
transform: none !important;
}
+
+/* Trying to show the border label:
+ * The following style is referenced from data souce selector
+ * see file src/plugins/data_source_management/public/components/popover_button/popover_button.scss
+*/
+.workspaceSelectorPopoverButtonContainer {
+ position: relative;
+ background-color: $euiSideNavBackgroundColor;
+ border: 1px solid $euiColorMediumShade;
+ border-radius: 4px;
+
+ &::before {
+ content: attr(data-label);
+ position: absolute;
+ top: -0.2rem;
+ left: $euiSizeS;
+ font-size: 0.4rem;
+ line-height: 0.4rem;
+ padding: 0 $euiSizeXS;
+
+ /* update
+ * Delete the line-gradient and set the background color to euiSideNavBackgroundColor directly
+ */
+ background-color: $euiSideNavBackgroundColor;
+ color: $euiTextColor;
+ z-index: 0;
+ text-transform: uppercase;
+ }
+}
diff --git a/src/plugins/workspace/public/components/workspace_selector/workspace_selector.test.tsx b/src/plugins/workspace/public/components/workspace_selector/workspace_selector.test.tsx
index 5b8b05a6506a..6f0b4136698d 100644
--- a/src/plugins/workspace/public/components/workspace_selector/workspace_selector.test.tsx
+++ b/src/plugins/workspace/public/components/workspace_selector/workspace_selector.test.tsx
@@ -10,13 +10,8 @@ import { WorkspaceSelector } from './workspace_selector';
import { coreMock } from '../../../../../core/public/mocks';
import { CoreStart, DEFAULT_NAV_GROUPS, WorkspaceObject } from '../../../../../core/public';
import { BehaviorSubject } from 'rxjs';
-import { IntlProvider } from 'react-intl';
import { recentWorkspaceManager } from '../../recent_workspace_manager';
-jest.mock('@osd/i18n', () => ({
- i18n: {
- translate: (id: string, { defaultMessage }: { defaultMessage: string }) => defaultMessage,
- },
-}));
+import { I18nProvider } from '@osd/i18n/react';
describe('', () => {
let coreStartMock: CoreStart;
const navigateToApp = jest.fn();
@@ -52,9 +47,9 @@ describe('', () => {
const WorkspaceSelectorCreatorComponent = () => {
return (
-
+
-
+
);
};
@@ -68,6 +63,7 @@ describe('', () => {
expect(screen.getByTestId('workspace-selector-current-title')).toBeInTheDocument();
expect(screen.getByTestId('workspace-selector-current-name')).toBeInTheDocument();
});
+
it('should display a list of workspaces in the dropdown', () => {
jest
.spyOn(recentWorkspaceManager, 'getRecentWorkspaces')
@@ -82,11 +78,11 @@ describe('', () => {
const selectButton = screen.getByTestId('workspace-selector-button');
fireEvent.click(selectButton);
- expect(screen.getByTestId('workspace-menu-item-workspace-1')).toBeInTheDocument();
- expect(screen.getByTestId('workspace-menu-item-workspace-2')).toBeInTheDocument();
+ expect(screen.getByText('workspace 1')).toBeInTheDocument();
+ expect(screen.getByText('workspace 2')).toBeInTheDocument();
});
- it('should display viewed xx ago for recent workspaces', () => {
+ it('should display viewed xx ago for recent workspaces, and Not visited recently for never-visited workspace', () => {
jest
.spyOn(recentWorkspaceManager, 'getRecentWorkspaces')
.mockReturnValue([{ id: 'workspace-1', timestamp: 1234567890 }]);
@@ -95,13 +91,12 @@ describe('', () => {
{ id: 'workspace-1', name: 'workspace 1', features: [] },
{ id: 'workspace-2', name: 'workspace 2', features: [] },
]);
-
render();
-
const selectButton = screen.getByTestId('workspace-selector-button');
fireEvent.click(selectButton);
- expect(screen.getByText(`viewed ${moment(1234567890).fromNow()}`)).toBeInTheDocument();
+ expect(screen.getByText(`Viewed ${moment(1234567890).fromNow()}`)).toBeInTheDocument();
+ expect(screen.getByText('Not visited recently')).toBeInTheDocument();
});
it('should be able to display empty state when the workspace list is empty', () => {
@@ -127,8 +122,8 @@ describe('', () => {
const searchInput = screen.getByRole('searchbox');
fireEvent.change(searchInput, { target: { value: 'works' } });
- expect(screen.getByTestId('workspace-menu-item-workspace-1')).toBeInTheDocument();
- expect(screen.queryByText('workspace-menu-item-workspace-1')).not.toBeInTheDocument();
+ expect(screen.getByText('workspace 1')).toBeInTheDocument();
+ expect(screen.queryByText('test 2')).not.toBeInTheDocument();
});
it('should be able to display empty state when seach is not found', () => {
diff --git a/src/plugins/workspace/public/components/workspace_selector/workspace_selector.tsx b/src/plugins/workspace/public/components/workspace_selector/workspace_selector.tsx
index f0c0243703f5..5374f3f2aea6 100644
--- a/src/plugins/workspace/public/components/workspace_selector/workspace_selector.tsx
+++ b/src/plugins/workspace/public/components/workspace_selector/workspace_selector.tsx
@@ -64,36 +64,21 @@ export const WorkspaceSelector = ({ coreStart, registeredUseCases$ }: Props) =>
const closePopover = () => {
setPopover(false);
};
+
const button = currentWorkspace ? (
-
-
+
-
- {i18n.translate('workspace.left.nav.selector.label', {
- defaultMessage: 'WORKSPACE',
- })}
-
-
-
-
+
-
+
color={getValidWorkspaceColor(currentWorkspace.color)}
/>
-
-
-
+
+
+
{currentWorkspace.name}
-
+
-
+
) : (
Select a Workspace
);