Skip to content

Commit e8c09da

Browse files
Merge pull request #557 from Heigvd/dev
Some UX / UI improvements
2 parents ab97310 + e46c56a commit e8c09da

File tree

14 files changed

+88
-246
lines changed

14 files changed

+88
-246
lines changed

colab-api/src/main/java/ch/colabproject/colab/api/model/user/User.java

Lines changed: 22 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,18 @@
1616
import ch.colabproject.colab.api.ws.channel.tool.ChannelsBuilders.AboutUserChannelsBuilder;
1717
import ch.colabproject.colab.api.ws.channel.tool.ChannelsBuilders.ChannelsBuilder;
1818
import ch.colabproject.colab.generator.model.tools.DateSerDe;
19-
import java.time.OffsetDateTime;
20-
import java.util.ArrayList;
21-
import java.util.List;
19+
import org.apache.commons.lang3.StringUtils;
20+
2221
import javax.json.bind.annotation.JsonbTransient;
2322
import javax.json.bind.annotation.JsonbTypeDeserializer;
2423
import javax.json.bind.annotation.JsonbTypeSerializer;
25-
import javax.persistence.CascadeType;
26-
import javax.persistence.Embedded;
27-
import javax.persistence.Entity;
28-
import javax.persistence.EnumType;
29-
import javax.persistence.Enumerated;
30-
import javax.persistence.GeneratedValue;
31-
import javax.persistence.GenerationType;
32-
import javax.persistence.Id;
33-
import javax.persistence.Index;
34-
import javax.persistence.NamedQuery;
35-
import javax.persistence.OneToMany;
36-
import javax.persistence.SequenceGenerator;
37-
import javax.persistence.Table;
38-
import javax.persistence.Transient;
24+
import javax.persistence.*;
3925
import javax.validation.constraints.NotNull;
4026
import javax.validation.constraints.Pattern;
4127
import javax.validation.constraints.Size;
42-
import org.apache.commons.lang3.StringUtils;
28+
import java.time.OffsetDateTime;
29+
import java.util.ArrayList;
30+
import java.util.List;
4331

4432
/**
4533
* Represents a registered user. A user may authenticate by several means (accounts).
@@ -381,28 +369,24 @@ public void setAccounts(List<Account> accounts) {
381369
*/
382370
@JsonbTransient
383371
public String getDisplayName() {
384-
if (StringUtils.isNotBlank(this.commonname)) {
385-
return this.commonname;
372+
StringBuilder sb = new StringBuilder();
386373

387-
} else {
388-
StringBuilder sb = new StringBuilder();
389-
390-
if (StringUtils.isNotBlank(this.firstname)) {
391-
sb.append(this.firstname);
392-
}
393-
if (StringUtils.isNotBlank(this.firstname) && StringUtils.isNotBlank(this.lastname)) {
394-
sb.append(" ");
395-
}
396-
if (StringUtils.isNotBlank(this.lastname)) {
397-
sb.append(this.lastname);
398-
}
399-
400-
String toString = sb.toString();
401-
if (StringUtils.isNotBlank(toString)) {
402-
return toString;
403-
}
374+
if (StringUtils.isNotBlank(this.firstname)) {
375+
sb.append(this.firstname);
376+
}
377+
if (StringUtils.isNotBlank(this.firstname) && StringUtils.isNotBlank(this.lastname)) {
378+
sb.append(" ");
379+
}
380+
if (StringUtils.isNotBlank(this.lastname)) {
381+
sb.append(this.lastname);
404382
}
405-
return this.username;
383+
384+
String toString = sb.toString();
385+
if (StringUtils.isNotBlank(toString)) {
386+
return toString;
387+
}
388+
389+
return "Someone";
406390
}
407391

408392
// ---------------------------------------------------------------------------------------------

colab-webapp/src/main/node/app/src/components/common/element/Link.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ function defaultClassName({ isActive }: { isActive: boolean }): string {
2828

2929
export const MainMenuLink = ({ to, children, end, className }: LinkProps): JSX.Element => {
3030
const location = useLocation();
31-
const isActive = location.pathname.endsWith(to.slice(1));
31+
const isActive = end
32+
? location.pathname.endsWith(to.slice(1))
33+
: location.pathname.includes(to.slice(1));
3234

3335
return (
3436
<NavLink

colab-webapp/src/main/node/app/src/components/common/layout/ShowOnClick.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import { css, cx } from '@emotion/css';
99
import * as React from 'react';
10+
import Flex from '../../common/layout/Flex';
1011

1112
const relative = css({
1213
position: 'relative',
@@ -39,15 +40,15 @@ export default function ShowOnClick({
3940

4041
if (state === 'COLLAPSED') {
4142
return (
42-
<div
43+
<Flex
4344
className={className}
4445
onClick={e => {
4546
e.stopPropagation();
4647
setState('EXPANDED');
4748
}}
4849
>
4950
{collapsedChildren}
50-
</div>
51+
</Flex>
5152
);
5253
} else {
5354
return (

colab-webapp/src/main/node/app/src/components/team/CardAssignmentsTable.tsx

Lines changed: 12 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,18 @@ import { Assignment, InvolvementLevel, TeamMember } from 'colab-rest-client';
1010
import * as React from 'react';
1111
import * as API from '../../API/api';
1212
import useTranslations from '../../i18n/I18nContext';
13-
import { useAppDispatch, useAppSelector } from '../../store/hooks';
14-
import { useAssignmentForCardAndMember } from '../../store/selectors/assignmentSelector';
13+
import { useAppDispatch } from '../../store/hooks';
1514
import {
16-
useTeamMembersHavingAssignment,
17-
useTeamMembersWithoutAssignment,
18-
} from '../../store/selectors/teamMemberSelector';
15+
useAssignmentForCardAndMember,
16+
useAssignmentsForCard,
17+
} from '../../store/selectors/assignmentSelector';
18+
import { useTeamMembers } from '../../store/selectors/teamMemberSelector';
1919
import { useLoadUsersForCurrentProject } from '../../store/selectors/userSelector';
2020
import { AvailabilityStatus } from '../../store/store';
21-
import { space_lg, space_sm, space_xl, space_xs, th_sm } from '../../styling/style';
21+
import { th_sm } from '../../styling/style';
2222
import AvailabilityStatusIndicator from '../common/element/AvailabilityStatusIndicator';
23-
import Button from '../common/element/Button';
2423
import IconButton from '../common/element/IconButton';
25-
import SelectInput from '../common/element/SelectInput';
26-
import Flex from '../common/layout/Flex';
27-
import UserName, { getUserName } from './UserName';
24+
import UserName from './UserName';
2825

2926
// -------------------------------------------------------------------------------------------------
3027
// Assignments options
@@ -61,7 +58,6 @@ function TeamAssignmentHeaderColumns(): JSX.Element {
6158
<PrettyPrint involvementLevel={involvementLevel} />
6259
</th>
6360
))}
64-
<th>{/* for delete action */}</th>
6561
</tr>
6662
</thead>
6763
);
@@ -78,17 +74,8 @@ interface TeamAssignmentRowProps {
7874
}
7975

8076
function TeamAssignmentRow({ cardId, member, readOnly }: TeamAssignmentRowProps): JSX.Element {
81-
const dispatch = useAppDispatch();
82-
const i18n = useTranslations();
83-
8477
const { status, assignment } = useAssignmentForCardAndMember(cardId, member.id);
8578

86-
const onDeleteRow = React.useCallback(() => {
87-
if (member.id != null && cardId != null) {
88-
dispatch(API.deleteAssignments({ memberId: member.id, cardId }));
89-
}
90-
}, [cardId, member.id, dispatch]);
91-
9279
return (
9380
<tr>
9481
<td>
@@ -106,16 +93,6 @@ function TeamAssignmentRow({ cardId, member, readOnly }: TeamAssignmentRowProps)
10693
/>
10794
</td>
10895
))}
109-
<td>
110-
{!readOnly && (
111-
<IconButton
112-
icon="delete"
113-
title={i18n.team.assignment.actions.clickToRemoveAssignment}
114-
onClick={onDeleteRow}
115-
className={'hoverButton ' + css({ visibility: 'hidden', padding: space_xs })}
116-
/>
117-
)}
118-
</td>
11996
</tr>
12097
);
12198
}
@@ -183,70 +160,6 @@ function IconCheckBox({
183160
);
184161
}
185162

186-
// -------------------------------------------------------------------------------------------------
187-
// Add button
188-
// -------------------------------------------------------------------------------------------------
189-
190-
interface TeamMemberAssignmentCreatorProps {
191-
cardId: number;
192-
}
193-
194-
function TeamMemberAssignmentCreator({ cardId }: TeamMemberAssignmentCreatorProps): JSX.Element {
195-
const dispatch = useAppDispatch();
196-
const i18n = useTranslations();
197-
198-
const { members: membersWithoutAssignment } = useTeamMembersWithoutAssignment(cardId);
199-
200-
const membersToSelect = useAppSelector(state => {
201-
return membersWithoutAssignment.map(m => ({
202-
label: getUserName(state, i18n, m),
203-
value: m.id || 0,
204-
}));
205-
});
206-
207-
const [isAdding, setIsAdding] = React.useState<boolean>(false);
208-
209-
const [newMembers, setNewMembers] = React.useState<number[]>([]);
210-
211-
return (
212-
<Flex gap={space_sm} align="center">
213-
{isAdding && (
214-
<>
215-
<SelectInput
216-
value={undefined} // see if ok
217-
isClearable={true}
218-
isMulti={true}
219-
options={membersToSelect}
220-
onChange={(selected: number[] | null) => {
221-
setNewMembers(selected || []);
222-
}}
223-
/>
224-
</>
225-
)}
226-
<Button
227-
icon="add"
228-
kind={isAdding ? 'outline' : 'solid'}
229-
onClick={() => {
230-
if (isAdding) {
231-
newMembers.forEach(mId => {
232-
dispatch(
233-
API.createAssignment({
234-
cardId,
235-
memberId: mId,
236-
}),
237-
);
238-
});
239-
}
240-
setNewMembers([]);
241-
setIsAdding(e => !e);
242-
}}
243-
>
244-
{i18n.common.add}
245-
</Button>
246-
</Flex>
247-
);
248-
}
249-
250163
// -------------------------------------------------------------------------------------------------
251164
// Panel
252165
// -------------------------------------------------------------------------------------------------
@@ -260,9 +173,10 @@ export default function CardAssignmentsPanel({
260173
cardId,
261174
readOnly,
262175
}: CardAssignmentsPanelProps): JSX.Element {
263-
const { status: statusMembers, members: membersWithAssignment } =
264-
useTeamMembersHavingAssignment(cardId);
265-
// Note : Assignments are loaded when fetching the members having Assignments
176+
const { status: statusMembers, members } = useTeamMembers();
177+
178+
// just to load assignments once for the card
179+
useAssignmentsForCard(cardId);
266180

267181
// usefull for team members' display name, load all users at once
268182
const statusUsers = useLoadUsersForCurrentProject();
@@ -279,9 +193,6 @@ export default function CardAssignmentsPanel({
279193
<>
280194
<table
281195
className={css({
282-
marginBottom: space_xl,
283-
paddingBottom: space_lg,
284-
borderBottom: '1px solid var(--divider-main)',
285196
'tbody tr:hover': {
286197
backgroundColor: 'var(--gray-100)',
287198
},
@@ -294,7 +205,7 @@ export default function CardAssignmentsPanel({
294205
{/* titles row */}
295206
<TeamAssignmentHeaderColumns />
296207
<tbody>
297-
{membersWithAssignment.map(member => {
208+
{members.map(member => {
298209
return (
299210
<TeamAssignmentRow
300211
key={member.id}
@@ -306,12 +217,6 @@ export default function CardAssignmentsPanel({
306217
})}
307218
</tbody>
308219
</table>
309-
310-
{!readOnly && (
311-
<Flex>
312-
<TeamMemberAssignmentCreator cardId={cardId} />
313-
</Flex>
314-
)}
315220
</>
316221
);
317222
}

colab-webapp/src/main/node/app/src/components/team/MemberCreator.tsx

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { emailFormat } from '../../helper';
1212
import useTranslations from '../../i18n/I18nContext';
1313
import { useAppDispatch } from '../../store/hooks';
1414
import { useCurrentProjectId } from '../../store/selectors/projectSelector';
15-
import { addNotification } from '../../store/slice/notificationSlice';
1615
import { m_md, space_lg, space_md, space_xs, warningTextStyle } from '../../styling/style';
1716
import Button from '../common/element/Button';
1817
import { BlockInput } from '../common/element/Input';
@@ -56,10 +55,16 @@ export default function ParticipantCreator({ mode }: ParticipantCreatorProps): J
5655

5756
return (
5857
<OpenModalOnClick
59-
title={mode === 'INVITE' ? i18n.common.invite : i18n.common.share}
58+
title={
59+
mode === 'INVITE'
60+
? i18n.modules.project.labels.invitationToProject
61+
: i18n.modules.project.labels.modelSharing
62+
}
6063
collapsedChildren={
6164
<Button kind="outline" icon="add" size="sm">
62-
{mode === 'INVITE' ? i18n.common.invite : i18n.common.share}
65+
{mode === 'INVITE'
66+
? i18n.modules.project.labels.invite
67+
: i18n.modules.project.labels.share}
6368
</Button>
6469
}
6570
modalBodyClassName={css({ padding: space_lg, alignItems: 'stretch' })}
@@ -80,7 +85,7 @@ export default function ParticipantCreator({ mode }: ParticipantCreatorProps): J
8085
close();
8186
}}
8287
>
83-
{i18n.common.close}
88+
{i18n.common.cancel}
8489
</Button>
8590
<Button
8691
onClick={() => {
@@ -110,13 +115,7 @@ export default function ParticipantCreator({ mode }: ParticipantCreatorProps): J
110115
);
111116
}
112117
}
113-
dispatch(
114-
addNotification({
115-
status: 'OPEN',
116-
type: 'INFO',
117-
message: `${i18n.team.mailsInvited}`,
118-
}),
119-
);
118+
120119
setInputValue('');
121120
setLoading(false);
122121
close();

0 commit comments

Comments
 (0)