From c930996a60de1ec40addb5f43f0f98d54fb86deb Mon Sep 17 00:00:00 2001 From: Viktor Vorona Date: Thu, 28 Dec 2023 11:33:01 +0100 Subject: [PATCH] SONAR-21382 Migrate Groups page to MIUI --- .../components/AlmSynchronisationWarning.tsx | 25 ++-- .../js/app/components/GlobalContainer.tsx | 1 + .../src/main/js/apps/groups/GroupsApp.tsx | 59 +++++----- .../js/apps/groups/__tests__/GroupsApp-it.tsx | 20 ++-- .../groups/components/DeleteGroupForm.tsx | 43 +++---- .../groups/components/EditMembersModal.tsx | 28 ++--- .../js/apps/groups/components/GroupForm.tsx | 107 ++++++++---------- .../main/js/apps/groups/components/Header.tsx | 48 ++++---- .../main/js/apps/groups/components/List.tsx | 40 +++---- .../js/apps/groups/components/ListItem.tsx | 99 +++++++++------- .../js/apps/groups/components/Members.tsx | 28 ++--- .../groups/components/ViewMembersModal.tsx | 94 +++++++-------- .../src/main/js/apps/groups/groups.css | 39 ------- .../js/components/controls/ManagedFilter.tsx | 59 ++++++---- .../resources/org/sonar/l10n/core.properties | 1 + 15 files changed, 319 insertions(+), 372 deletions(-) delete mode 100644 server/sonar-web/src/main/js/apps/groups/groups.css diff --git a/server/sonar-web/src/main/js/app/components/AlmSynchronisationWarning.tsx b/server/sonar-web/src/main/js/app/components/AlmSynchronisationWarning.tsx index 83e933e4858..411b4ae79f8 100644 --- a/server/sonar-web/src/main/js/app/components/AlmSynchronisationWarning.tsx +++ b/server/sonar-web/src/main/js/app/components/AlmSynchronisationWarning.tsx @@ -17,12 +17,11 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import styled from '@emotion/styled'; import { formatDistance } from 'date-fns'; +import { CheckIcon, FlagMessage, FlagWarningIcon, Link, themeColor } from 'design-system'; import * as React from 'react'; import { FormattedMessage } from 'react-intl'; -import Link from '../../components/common/Link'; -import CheckIcon from '../../components/icons/CheckIcon'; -import WarningIcon from '../../components/icons/WarningIcon'; import { Alert } from '../../components/ui/Alert'; import { translate, translateWithParameters } from '../../helpers/l10n'; import { AlmSyncStatus } from '../../types/provisioning'; @@ -50,13 +49,13 @@ function LastSyncAlert({ info, short }: Readonly) { if (short) { return status === TaskStatuses.Success ? (
- + {warningMessage ? ( - + ) : ( - + )} - + {warningMessage ? ( ) { values={{ date: formattedDate, details: ( - + {translate('settings.authentication.github.synchronization_details_link')} ), @@ -82,19 +81,19 @@ function LastSyncAlert({ info, short }: Readonly) {
) : ( - + + {translate('settings.authentication.github.synchronization_details_link')} ), }} /> - + ); } @@ -165,3 +164,7 @@ export default function AlmSynchronisationWarning({ ); } + +const IconWrapper = styled.span` + color: ${themeColor('iconSuccess')}; +`; diff --git a/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx b/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx index d8d409bd004..4ea23f1fec2 100644 --- a/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx @@ -77,6 +77,7 @@ const TEMP_PAGELIST_WITH_NEW_BACKGROUND_WHITE = [ '/admin/permission_templates', '/project/background_tasks', '/admin/background_tasks', + '/admin/groups', ]; export default function GlobalContainer() { diff --git a/server/sonar-web/src/main/js/apps/groups/GroupsApp.tsx b/server/sonar-web/src/main/js/apps/groups/GroupsApp.tsx index 24cbae5c7c6..16bf3fcaac7 100644 --- a/server/sonar-web/src/main/js/apps/groups/GroupsApp.tsx +++ b/server/sonar-web/src/main/js/apps/groups/GroupsApp.tsx @@ -17,6 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { InputSearch, LargeCenteredLayout, PageContentFontWrapper } from 'design-system'; import * as React from 'react'; import { useState } from 'react'; import { Helmet } from 'react-helmet-async'; @@ -24,7 +25,6 @@ import GitHubSynchronisationWarning from '../../app/components/GitHubSynchronisa import GitLabSynchronisationWarning from '../../app/components/GitLabSynchronisationWarning'; import ListFooter from '../../components/controls/ListFooter'; import { ManagedFilter } from '../../components/controls/ManagedFilter'; -import SearchBox from '../../components/controls/SearchBox'; import Suggestions from '../../components/embed-docs-modal/Suggestions'; import { translate } from '../../helpers/l10n'; import { useGroupsQueries } from '../../queries/groups'; @@ -32,7 +32,6 @@ import { useIdentityProviderQuery } from '../../queries/identity-provider/common import { Provider } from '../../types/types'; import Header from './components/Header'; import List from './components/List'; -import './groups.css'; export default function GroupsApp() { const [search, setSearch] = useState(''); @@ -47,42 +46,44 @@ export default function GroupsApp() { const groups = data?.pages.flatMap((page) => page.groups) ?? []; return ( - <> - - -
-
- {manageProvider?.provider === Provider.Github && } - {manageProvider?.provider === Provider.Gitlab && } + + + + +
+
+ {manageProvider?.provider === Provider.Github && } + {manageProvider?.provider === Provider.Gitlab && } -
- - setSearch(q)} - placeholder={translate('search.search_by_name')} - value={search} - /> -
+
+ + setSearch(q)} + placeholder={translate('search.search_by_name')} + value={search} + /> +
- + - -
- +
+ + ); } diff --git a/server/sonar-web/src/main/js/apps/groups/__tests__/GroupsApp-it.tsx b/server/sonar-web/src/main/js/apps/groups/__tests__/GroupsApp-it.tsx index b1d64c35f15..1c9a5ac1611 100644 --- a/server/sonar-web/src/main/js/apps/groups/__tests__/GroupsApp-it.tsx +++ b/server/sonar-web/src/main/js/apps/groups/__tests__/GroupsApp-it.tsx @@ -47,18 +47,19 @@ const ui = { allFilter: byRole('radio', { name: 'all' }), selectedFilter: byRole('radio', { name: 'selected' }), unselectedFilter: byRole('radio', { name: 'unselected' }), - localAndManagedFilter: byRole('button', { name: 'all' }), - managedFilter: byRole('button', { name: 'managed' }), - localFilter: byRole('button', { name: 'local' }), + localAndManagedFilter: byRole('radio', { name: 'all' }), + managedFilter: byRole('radio', { name: 'managed' }), + localFilter: byRole('radio', { name: 'local' }), searchInput: byRole('searchbox', { name: 'search.search_by_name' }), - updateButton: byRole('button', { name: 'update_details' }), + updateButton: byRole('menuitem', { name: 'update_details' }), updateDialog: byRole('dialog', { name: 'groups.update_group' }), updateDialogButton: byRole('button', { name: 'update_verb' }), - deleteButton: byRole('button', { name: 'delete' }), + deleteButton: byRole('menuitem', { name: 'delete' }), + deleteIconButton: byRole('button', { name: /delete_x/ }), deleteDialog: byRole('dialog', { name: 'groups.delete_group' }), deleteDialogButton: byRole('button', { name: 'delete' }), showMore: byRole('button', { name: 'show_more' }), - nameInput: byRole('textbox', { name: 'name field_required' }), + nameInput: byRole('textbox', { name: 'name required' }), descriptionInput: byRole('textbox', { name: 'description' }), createGroupDialogButton: byRole('button', { name: 'create' }), editGroupDialogButton: byRole('button', { name: 'groups.create_group' }), @@ -287,11 +288,10 @@ describe('in manage mode', () => { expect(await ui.localGroupRowWithLocalBadge.find()).toBeInTheDocument(); await user.click(await ui.localFilter.find()); - await user.click(await ui.localEditButton.find()); - - expect(ui.updateButton.query()).not.toBeInTheDocument(); + expect(ui.localEditButton.query()).not.toBeInTheDocument(); + expect(await ui.localGroupRowWithLocalBadge.by(ui.deleteIconButton).find()).toBeInTheDocument(); - await user.click(await ui.deleteButton.find()); + await user.click(ui.localGroupRowWithLocalBadge.by(ui.deleteIconButton).get()); expect(await ui.deleteDialog.find()).toBeInTheDocument(); diff --git a/server/sonar-web/src/main/js/apps/groups/components/DeleteGroupForm.tsx b/server/sonar-web/src/main/js/apps/groups/components/DeleteGroupForm.tsx index a4b4ad084a2..a9b29459e8a 100644 --- a/server/sonar-web/src/main/js/apps/groups/components/DeleteGroupForm.tsx +++ b/server/sonar-web/src/main/js/apps/groups/components/DeleteGroupForm.tsx @@ -17,10 +17,8 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { DangerButtonPrimary, Modal } from 'design-system'; import * as React from 'react'; -import SimpleModal from '../../../components/controls/SimpleModal'; -import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons'; -import Spinner from '../../../components/ui/Spinner'; import { translate, translateWithParameters } from '../../../helpers/l10n'; import { useDeleteGroupMutation } from '../../../queries/groups'; import { Group } from '../../../types/types'; @@ -30,10 +28,10 @@ interface Props { onClose: () => void; } -export default function DeleteGroupForm(props: Props) { +export default function DeleteGroupForm(props: Readonly) { const { group } = props; - const { mutate: deleteGroup } = useDeleteGroupMutation(); + const { mutate: deleteGroup, isLoading } = useDeleteGroupMutation(); const onSubmit = () => { deleteGroup(group.id, { @@ -41,30 +39,17 @@ export default function DeleteGroupForm(props: Props) { }); }; - const header = translate('groups.delete_group'); return ( - - {({ onCloseClick, onFormSubmit, submitting }) => ( -
-
-

{header}

-
- -
- {translateWithParameters('groups.delete_group.confirmation', group.name)} -
- -
- - - {translate('delete')} - - - {translate('cancel')} - -
-
- )} -
+ + {translate('delete')} + + } + secondaryButtonLabel={translate('cancel')} + /> ); } diff --git a/server/sonar-web/src/main/js/apps/groups/components/EditMembersModal.tsx b/server/sonar-web/src/main/js/apps/groups/components/EditMembersModal.tsx index c1818628841..5abe6bf8160 100644 --- a/server/sonar-web/src/main/js/apps/groups/components/EditMembersModal.tsx +++ b/server/sonar-web/src/main/js/apps/groups/components/EditMembersModal.tsx @@ -17,14 +17,13 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { Modal, TextMuted } from 'design-system'; import { find } from 'lodash'; import * as React from 'react'; -import Modal from '../../../components/controls/Modal'; import SelectList, { SelectListFilter, SelectListSearchParams, } from '../../../components/controls/SelectList'; -import { ResetButtonLink } from '../../../components/controls/buttons'; import { translate } from '../../../helpers/l10n'; import { useAddGroupMembershipMutation, @@ -90,10 +89,10 @@ export default function EditMembersModal(props: Readonly) { } return ( -
+
{user.name}
- {user.login} +
); }; @@ -111,15 +110,8 @@ export default function EditMembersModal(props: Readonly) { return ( -
-

{modalHeader}

-
- -
+ headerTitle={modalHeader} + body={ user.id)} elementsTotalCount={data?.pages[0].page.total} @@ -134,11 +126,9 @@ export default function EditMembersModal(props: Readonly) { withPaging loading={isLoading} /> -
- -
- {translate('done')} -
-
+ } + secondaryButtonLabel={translate('done')} + onClose={props.onClose} + /> ); } diff --git a/server/sonar-web/src/main/js/apps/groups/components/GroupForm.tsx b/server/sonar-web/src/main/js/apps/groups/components/GroupForm.tsx index 97faf125d87..3852cebe389 100644 --- a/server/sonar-web/src/main/js/apps/groups/components/GroupForm.tsx +++ b/server/sonar-web/src/main/js/apps/groups/components/GroupForm.tsx @@ -17,13 +17,10 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { ButtonPrimary, FormField, InputField, InputTextArea, Modal } from 'design-system'; import * as React from 'react'; import { useState } from 'react'; -import SimpleModal from '../../../components/controls/SimpleModal'; -import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons'; -import MandatoryFieldMarker from '../../../components/ui/MandatoryFieldMarker'; import MandatoryFieldsExplanation from '../../../components/ui/MandatoryFieldsExplanation'; -import Spinner from '../../../components/ui/Spinner'; import { translate } from '../../../helpers/l10n'; import { useCreateGroupMutation, useUpdateGroupMutation } from '../../../queries/groups'; import { Group } from '../../../types/types'; @@ -46,8 +43,8 @@ export default function GroupForm(props: Props) { const [name, setName] = useState(create ? '' : group.name); const [description, setDescription] = useState(create ? '' : group.description ?? ''); - const { mutate: createGroup } = useCreateGroupMutation(); - const { mutate: updateGroup } = useUpdateGroupMutation(); + const { mutate: createGroup, isLoading: isCreating } = useCreateGroupMutation(); + const { mutate: updateGroup, isLoading: isUpdating } = useUpdateGroupMutation(); const handleCreateGroup = () => { createGroup({ name, description }, { onSuccess: props.onClose }); @@ -70,61 +67,49 @@ export default function GroupForm(props: Props) { }; return ( - + + + ) => { + setName(event.currentTarget.value); + }} + required + size="full" + type="text" + value={name} + /> + + + ) => { + setDescription(event.currentTarget.value); + }} + size="full" + value={description} + /> + + + } onClose={props.onClose} - onSubmit={create ? handleCreateGroup : handleUpdateGroup} - size="small" - > - {({ onCloseClick, onFormSubmit, submitting }) => ( -
-
-

{create ? translate('groups.create_group') : translate('groups.update_group')}

-
- -
- -
- - ) => { - setName(event.currentTarget.value); - }} - required - size={50} - type="text" - value={name} - /> -
-
- -