diff --git a/webapp/channels/src/actions/websocket_actions.test.jsx b/webapp/channels/src/actions/websocket_actions.test.jsx index ef2e81c4ff..399a0e4fd5 100644 --- a/webapp/channels/src/actions/websocket_actions.test.jsx +++ b/webapp/channels/src/actions/websocket_actions.test.jsx @@ -1390,9 +1390,9 @@ describe('handleCustomAttributeCRUD', () => { let cpaFields = getCustomProfileAttributes(testStore.getState()); expect(cpaFields).toBeTruthy(); - expect(Object.keys(cpaFields).length).toEqual(1); - expect(cpaFields.field1.type).toEqual(field1.type); - expect(cpaFields.field1.name).toEqual(field1.name); + expect(cpaFields.length).toEqual(1); + expect(cpaFields.filter(({id}) => id === field1.id)[0].type).toEqual(field1.type); + expect(cpaFields.filter(({id}) => id === field1.id)[0].name).toEqual(field1.name); // create second field testStore.dispatch(handleCustomAttributesCreated({ @@ -1404,9 +1404,9 @@ describe('handleCustomAttributeCRUD', () => { cpaFields = getCustomProfileAttributes(testStore.getState()); expect(cpaFields).toBeTruthy(); - expect(Object.keys(cpaFields).length).toEqual(2); - expect(cpaFields.field2.type).toEqual(field2.type); - expect(cpaFields.field2.name).toEqual(field2.name); + expect(cpaFields.length).toEqual(2); + expect(cpaFields.filter(({id}) => id === field2.id)[0].type).toEqual(field2.type); + expect(cpaFields.filter(({id}) => id === field2.id)[0].name).toEqual(field2.name); // update field testStore.dispatch(handleCustomAttributesUpdated({ @@ -1418,9 +1418,9 @@ describe('handleCustomAttributeCRUD', () => { cpaFields = getCustomProfileAttributes(testStore.getState()); expect(cpaFields).toBeTruthy(); - expect(Object.keys(cpaFields).length).toEqual(2); - expect(cpaFields.field1.name).toEqual('Updated Name'); - expect(cpaFields.field2.name).toEqual(field2.name); + expect(cpaFields.length).toEqual(2); + expect(cpaFields.filter(({id}) => id === field1.id)[0].name).toEqual('Updated Name'); + expect(cpaFields.filter(({id}) => id === field2.id)[0].name).toEqual(field2.name); // delete field testStore.dispatch(handleCustomAttributesDeleted({ @@ -1432,7 +1432,7 @@ describe('handleCustomAttributeCRUD', () => { cpaFields = getCustomProfileAttributes(testStore.getState()); expect(cpaFields).toBeTruthy(); - expect(Object.keys(cpaFields).length).toEqual(1); - expect(cpaFields.field2).toBeTruthy(); + expect(cpaFields.length).toEqual(1); + expect(cpaFields.filter(({id}) => id === field2.id)[0]).toBeTruthy(); }); }); diff --git a/webapp/channels/src/components/profile_popover/profile_popover_custom_attributes.tsx b/webapp/channels/src/components/profile_popover/profile_popover_custom_attributes.tsx index 7d4d761459..c1273d4a4e 100644 --- a/webapp/channels/src/components/profile_popover/profile_popover_custom_attributes.tsx +++ b/webapp/channels/src/components/profile_popover/profile_popover_custom_attributes.tsx @@ -25,7 +25,7 @@ const ProfilePopoverCustomAttributes = ({ dispatch(getCustomProfileAttributeValues(userID)); } }); - const attributeSections = Object.values(customProfileAttributeFields).map((attribute) => { + const attributeSections = customProfileAttributeFields.map((attribute) => { if (userProfile.custom_profile_attributes) { const value = userProfile.custom_profile_attributes[attribute.id]; if (!value) { diff --git a/webapp/channels/src/components/user_settings/general/user_settings_general.test.tsx b/webapp/channels/src/components/user_settings/general/user_settings_general.test.tsx index 128ad36e2f..d48e03ee38 100644 --- a/webapp/channels/src/components/user_settings/general/user_settings_general.test.tsx +++ b/webapp/channels/src/components/user_settings/general/user_settings_general.test.tsx @@ -45,7 +45,7 @@ describe('components/user_settings/general/UserSettingsGeneral', () => { closeModal: jest.fn(), collapseModal: jest.fn(), isMobileView: false, - customProfileAttributeFields: {}, + customProfileAttributeFields: [], actions: { logError: jest.fn(), clearErrors: jest.fn(), @@ -199,7 +199,7 @@ describe('components/user_settings/general/UserSettingsGeneral', () => { const props = { ...requiredProps, enableCustomProfileAttributes: true, - customProfileAttributeFields: {field1: customProfileAttribute}, + customProfileAttributeFields: [customProfileAttribute], user: testUser, }; @@ -216,7 +216,7 @@ describe('components/user_settings/general/UserSettingsGeneral', () => { const props = { ...requiredProps, enableCustomProfileAttributes: true, - customProfileAttributeFields: {field1: customProfileAttribute}, + customProfileAttributeFields: [customProfileAttribute], user: testUser, }; @@ -233,7 +233,7 @@ describe('components/user_settings/general/UserSettingsGeneral', () => { const props = { ...requiredProps, enableCustomProfileAttributes: true, - customProfileAttributeFields: {field1: customProfileAttribute}, + customProfileAttributeFields: [customProfileAttribute], user: testUser, }; @@ -248,7 +248,7 @@ describe('components/user_settings/general/UserSettingsGeneral', () => { const props = { ...requiredProps, enableCustomProfileAttributes: true, - customProfileAttributeFields: {field1: customProfileAttribute}, + customProfileAttributeFields: [customProfileAttribute], actions: {...requiredProps.actions}, user: testUser, }; @@ -268,7 +268,7 @@ describe('components/user_settings/general/UserSettingsGeneral', () => { const props = { ...requiredProps, enableCustomProfileAttributes: true, - customProfileAttributeFields: {field1: customProfileAttribute}, + customProfileAttributeFields: [customProfileAttribute], user, activeSection: 'customAttribute_field1', }; @@ -283,7 +283,7 @@ describe('components/user_settings/general/UserSettingsGeneral', () => { ...requiredProps, enableCustomProfileAttributes: true, actions: {...requiredProps.actions, saveCustomProfileAttribute}, - customProfileAttributeFields: {field1: customProfileAttribute}, + customProfileAttributeFields: [customProfileAttribute], user: {...user}, activeSection: 'customAttribute_field1', }; diff --git a/webapp/channels/src/components/user_settings/general/user_settings_general.tsx b/webapp/channels/src/components/user_settings/general/user_settings_general.tsx index 4892bd43f0..f6d9cb3433 100644 --- a/webapp/channels/src/components/user_settings/general/user_settings_general.tsx +++ b/webapp/channels/src/components/user_settings/general/user_settings_general.tsx @@ -9,7 +9,6 @@ import type {IntlShape} from 'react-intl'; import type {UserPropertyField} from '@mattermost/types/properties'; import type {UserProfile} from '@mattermost/types/users'; -import type {IDMappedObjects} from '@mattermost/types/utilities'; import type {LogErrorOptions} from 'mattermost-redux/actions/errors'; import {LogErrorBarMode} from 'mattermost-redux/actions/errors'; @@ -110,7 +109,7 @@ export type Props = { collapseModal: () => void; isMobileView: boolean; maxFileSize: number; - customProfileAttributeFields: IDMappedObjects; + customProfileAttributeFields: UserPropertyField[]; actions: { logError: ({message, type}: {message: any; type: string}, options?: LogErrorOptions) => void; clearErrors: () => void; @@ -1325,7 +1324,7 @@ export class UserSettingsGeneralTab extends PureComponent { return <>; } - const attributeSections = Object.values(this.props.customProfileAttributeFields).map((attribute) => { + const attributeSections = this.props.customProfileAttributeFields.map((attribute) => { const sectionName = 'customAttribute_' + attribute.id; const active = this.props.activeSection === sectionName; let max = null; diff --git a/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/general.test.ts b/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/general.test.ts index a97745a052..5bb755518b 100644 --- a/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/general.test.ts +++ b/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/general.test.ts @@ -412,21 +412,21 @@ describe('Selectors.General', () => { }, } as unknown as GlobalState; - expect(Selectors.getCustomProfileAttributes(state)).toEqual({}); + expect(Selectors.getCustomProfileAttributes(state)).toEqual([]); }); test('should return the value of the attributes', () => { - const state = { + let state = { entities: { general: { - customProfileAttributes: [{id: '123', name: 'test attribute', dataType: 'text'}], + customProfileAttributes: {123: {id: '123', name: 'test attribute', dataType: 'text'}}, }, }, } as unknown as GlobalState; expect(Selectors.getCustomProfileAttributes(state)[0].id).toEqual('123'); - state.entities.general.customProfileAttributes = {}; - expect(Selectors.getCustomProfileAttributes(state)).toEqual({}); + state = {...state, entities: {...state.entities, general: {...state.entities.general, customProfileAttributes: {}}}}; + expect(Selectors.getCustomProfileAttributes(state)).toEqual([]); }); }); }); diff --git a/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/general.ts b/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/general.ts index fef303dce2..214e4200a8 100644 --- a/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/general.ts +++ b/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/general.ts @@ -4,7 +4,6 @@ import type {ClientConfig, FeatureFlags, ClientLicense} from '@mattermost/types/config'; import type {UserPropertyField} from '@mattermost/types/properties'; import type {GlobalState} from '@mattermost/types/store'; -import type {IDMappedObjects} from '@mattermost/types/utilities'; import {General} from 'mattermost-redux/constants'; import {createSelector} from 'mattermost-redux/selectors/create_selector'; @@ -153,6 +152,10 @@ export function testingEnabled(state: GlobalState): boolean { return state.entities.general.config.EnableTesting === 'true'; } -export function getCustomProfileAttributes(state: GlobalState): IDMappedObjects { - return state.entities.general.customProfileAttributes; -} +export const getCustomProfileAttributes: (state: GlobalState) => UserPropertyField[] = createSelector( + 'getCustomProfileAttributes', + (state) => state.entities.general.customProfileAttributes, + (fields) => { + return Object.values(fields).sort((a, b) => (a.attrs?.sort_order ?? 0) - (b.attrs?.sort_order ?? 0)); + }, +);