Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
29dcb74
feat(bugspageslice): added exclude 'not a bug' feature added back
sanchayan721 Apr 11, 2023
e3747a5
feat(custom status field): added back the exclude 'not a bug' toggle
sanchayan721 Apr 11, 2023
c8b3a92
feat(drawer): added exclude 'not a bug' feature in drawer
sanchayan721 Apr 11, 2023
2647784
feat(usetabledata): added feature exclude 'not a bug'
sanchayan721 Apr 11, 2023
cf58601
feat(bugs types): added bugItem type
sanchayan721 Apr 11, 2023
94b5752
refactor(bugs item): bugitems refactored with BugItem type
sanchayan721 Apr 11, 2023
0dd7646
feat(translation): added translation for not a bug and not a bug excl…
sanchayan721 Apr 11, 2023
585f09b
feat(get exclude not a bug info): custom function to get data related…
sanchayan721 Apr 11, 2023
d46f3e9
refactor(usetabledata): component refactored by implementing getExclu…
sanchayan721 Apr 11, 2023
6b9e289
style(translation): modified translation punctuations
sanchayan721 Apr 11, 2023
a5e9407
feat(custom status field): added translation for the toggle label
sanchayan721 Apr 11, 2023
9c44ca7
refactor(filter recap): refactored component by implementing getCusto…
sanchayan721 Apr 11, 2023
e114019
fix(filter recap): added clearing the exclude not a bug status
sanchayan721 Apr 11, 2023
42c8af5
feat(custom status filter dropdown): adding support for exclude not a…
sanchayan721 Apr 11, 2023
0271b63
refactor(drawer): drawer refactored by implementing getExcludeNotABug…
sanchayan721 Apr 11, 2023
67ba3b7
style(prettier): refactored with prettier
sanchayan721 Apr 11, 2023
bf26b4f
Merge branch 'develop' into UN-801-not-a-bug-toggle
sanchayan721 Apr 11, 2023
6a8f7ea
feat(getexcludenotabuginfo): added drawerTitle in getExcludeNotABugInfo
sanchayan721 Apr 11, 2023
db0dc41
refactor(usetabledata): refactored bugsItems to remove unnecessary co…
sanchayan721 Apr 11, 2023
6dbfb54
refactor(custom status field and filter): refactored by using BugCust…
sanchayan721 Apr 11, 2023
cd2925c
style(prettier): prettier style formating
sanchayan721 Apr 11, 2023
41a0365
refactor(custom status field): refactoring shoulddisabletoggle
sanchayan721 Apr 11, 2023
7ef004f
refactor(usetabledata): remove unnecessary imports
sanchayan721 Apr 11, 2023
c1f3325
refactor(custom status field): refactoring for better coverage
sanchayan721 Apr 11, 2023
46bef34
refactor(custom status filter): refactoring for better code coverage
sanchayan721 Apr 11, 2023
8e3f98d
style(prettier): formatted style with prettier
sanchayan721 Apr 11, 2023
677ca32
refactor(custom status field): refactored by using getExcludeNotABugInfo
sanchayan721 Apr 12, 2023
2c1777d
style(prettier): retyled with prettier
sanchayan721 Apr 12, 2023
c04e053
fix(custom status component): closing the drawer and reopening change…
sanchayan721 Apr 12, 2023
94ee20f
fix(custom status field): updated the drawer selected filter includin…
sanchayan721 Apr 12, 2023
19cb848
feat(custom status field): translation added for label exclude 'not a…
sanchayan721 Apr 12, 2023
8ba8c14
feat(custom status field): translations for all labels
sanchayan721 Apr 12, 2023
c4fa355
✨ feat(constants.ts): add DEFAULT_NOT_A_BUG_CUSTOM_STATUS constant to…
marcbon Apr 17, 2023
b6f5f06
🌐 chore(translation.json): update translations for "Not a bug" exclus…
marcbon Apr 17, 2023
8313131
🔧 chore(getExcludeNotABugInfo.tsx): use constant for default not a bu…
marcbon Apr 17, 2023
89c6da8
🌐 feat(useTableData.tsx, CustomStatusField.tsx, index.tsx, CustomStat…
marcbon Apr 17, 2023
1f8fb7d
Merge pull request #544 from AppQuality/toggle-refactor
sanchayan721 Apr 17, 2023
0eb2af2
refactor(custom status field): removed spacer and added margin bottom
sanchayan721 Apr 17, 2023
41c68ef
style(custom status field): restyling code with prettier
sanchayan721 Apr 17, 2023
cab65a9
Merge pull request #540 from AppQuality/UN-801-not-a-bug-toggle
marcbon Apr 17, 2023
f59f56f
New translations translation.json (Italian)
cannarocks Apr 17, 2023
94bf642
feat(workspaces): add basic modal settings in header
cannarocks Apr 6, 2023
a5d6030
feat(workspace-settings): add delete, post action to users list
cannarocks Apr 17, 2023
037136e
feat(workspace-settings): update tags
cannarocks Apr 17, 2023
165b124
feat(workspace-settings): attach action to api
cannarocks Apr 18, 2023
e387ac7
Merge pull request #546 from AppQuality/UGG-9-add-workspace-settings-…
cannarocks Apr 18, 2023
8484bf5
New translations translation.json (Italian)
cannarocks Apr 18, 2023
dabc0be
refactor(header): Use HeaderItemText as base component in BrandItem
cannarocks Apr 18, 2023
2997993
Merge pull request #547 from AppQuality/UGG-9-add-workspace-settings-…
cannarocks Apr 18, 2023
cd21e31
fix(header): remove debug dropdown condition
cannarocks Apr 18, 2023
635246c
fix(workspace-settings): remove overflow from input body
cannarocks Apr 19, 2023
f54e07c
Merge pull request #545 from AppQuality/i18n-translations
cannarocks Apr 19, 2023
60ce154
New translations translation.json (Italian)
cannarocks Apr 20, 2023
a13ec06
New translations translation.json (Italian)
cannarocks Apr 20, 2023
f60025c
New translations translation.json (Italian)
cannarocks Apr 20, 2023
ebc4823
Merge pull request #548 from AppQuality/i18n-translations
cannarocks Apr 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/assets/icons/gear-fill.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/icons/overflow-vertical-fill.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/icons/x-stroke.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
106 changes: 106 additions & 0 deletions src/common/components/navigation/header/settings/addNewMember.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import {
Input,
Message,
Button,
Label,
} from '@appquality/unguess-design-system';
import { Field } from '@zendeskgarden/react-forms';
import { Form, Formik, FormikProps } from 'formik';
import { useTranslation } from 'react-i18next';
import styled from 'styled-components';
import { theme as globalTheme } from 'src/app/theme';
import * as Yup from 'yup';
import { usePostWorkspacesByWidUsersMutation } from 'src/features/api';
import { useAppSelector } from 'src/app/hooks';

const formInitialValues = {
email: '',
};

const EmailTextField = styled(Field)`
display: flex;
width: 100%;
align-items: first baseline;
button {
margin-left: ${({ theme }) => theme.space.sm};
}
`;

export const AddNewMemberInput = () => {
const { t } = useTranslation();
const { activeWorkspace } = useAppSelector((state) => state.navigation);
const [addNewMember] = usePostWorkspacesByWidUsersMutation();

if (!activeWorkspace) return null;

const validationSchema = Yup.object().shape({
email: Yup.string()
.email(t('__WORKSPACE_SETTINGS_ADD_MEMBER_INVALID_EMAIL_ERROR'))
.required(t('__WORKSPACE_SETTINGS_ADD_MEMBER_REQUIRED_EMAIL_ERROR')),
});

return (
<Formik
initialValues={formInitialValues}
validateOnChange
validateOnBlur
validationSchema={validationSchema}
onSubmit={(values, actions) => {
addNewMember({
wid: activeWorkspace?.id.toString() || '',
body: {
email: values.email,
},
})
.then(() => {
actions.setSubmitting(false);
})
.catch((err) => {
// eslint-disable-next-line no-console
console.error(err);
actions.setSubmitting(false);
});
}}
>
{({
errors,
getFieldProps,
handleSubmit,
...formProps
}: FormikProps<{ email: string }>) => (
<Form
onSubmit={handleSubmit}
style={{ marginBottom: globalTheme.space.sm }}
>
<Label>{t('__WORKSPACE_SETTINGS_ADD_MEMBER_EMAIL_LABEL')}</Label>
<EmailTextField>
<Input
placeholder={t(
'__WORKSPACE_SETTINGS_ADD_MEMBER_EMAIL_PLACEHOLDER'
)}
{...getFieldProps('email')}
{...(errors.email && { validation: 'error' })}
/>
<Button
isPrimary
isPill
themeColor={globalTheme.palette.water[600]}
type="submit"
disabled={formProps.isSubmitting}
>
{t('__WORKSPACE_SETTINGS_ADD_MEMBER_BUTTON')}
</Button>
</EmailTextField>
{errors.email && (
<Message
validation="error"
style={{ marginTop: globalTheme.space.xs }}
>
{errors.email}
</Message>
)}
</Form>
)}
</Formik>
);
};
30 changes: 30 additions & 0 deletions src/common/components/navigation/header/settings/modalFooter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Modal, Button } from '@appquality/unguess-design-system';
import { ReactComponent as LinkIcon } from 'src/assets/icons/link-stroke.svg';
import { getColor } from '@zendeskgarden/react-theming';
import styled from 'styled-components';
import { useTranslation } from 'react-i18next';

const FooterWithBorder = styled(Modal.Footer)`
border-top: 1px solid ${({ theme }) => getColor(theme.colors.neutralHue, 200)};
padding: ${({ theme }) =>
`${theme.space.base * 4}px ${theme.space.base * 8}px`};
justify-content: start;
`;

export const WorkspaceSettingsFooter = () => {
const { t } = useTranslation();

return (
<FooterWithBorder>
<Button
isBasic
onClick={() => navigator.clipboard.writeText(window.location.href)}
>
<Button.StartIcon>
<LinkIcon />
</Button.StartIcon>
{t('__WORKSPACE_SETTINGS_MODAL_CTA_COPY_LINK')}
</Button>
</FooterWithBorder>
);
};
124 changes: 124 additions & 0 deletions src/common/components/navigation/header/settings/userItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import {
Avatar,
Span,
Trigger,
Menu,
Button,
Dropdown,
Item,
Ellipsis,
} from '@appquality/unguess-design-system';
import { ReactComponent as ChevronIcon } from 'src/assets/icons/chevron-down-stroke.svg';
import {
GetWorkspacesByWidUsersApiResponse,
useDeleteWorkspacesByWidUsersMutation,
usePostWorkspacesByWidUsersMutation,
} from 'src/features/api';
import styled from 'styled-components';
import { useState } from 'react';
import { useAppSelector } from 'src/app/hooks';
import { useTranslation } from 'react-i18next';
import { theme as globalTheme } from 'src/app/theme';
import { getInitials } from '../utils';

const StyledEllipsis = styled(Ellipsis)``;
const UserListItem = styled.div`
display: flex;
padding: ${({ theme }) => `${theme.space.xs} 0`};
align-items: center;
gap: ${({ theme }) => theme.space.sm};

div.actions {
margin-left: auto;
}

${StyledEllipsis} {
width: 300px;
}
`;

export const UserItem = ({
user,
}: {
user: GetWorkspacesByWidUsersApiResponse['items'][number];
}) => {
const { t } = useTranslation();
const [rotated, setRotated] = useState<boolean>();
const { activeWorkspace } = useAppSelector((state) => state.navigation);
const { userData } = useAppSelector((state) => state.user);
const [removeUser] = useDeleteWorkspacesByWidUsersMutation();
const [addNewMember] = usePostWorkspacesByWidUsersMutation();

const isMe = userData?.email === user.email;
const displayName = user.name.length ? user.name : user.email;

if (!activeWorkspace) return null;

return (
<UserListItem key={`profile_${user.profile_id}`}>
<Avatar avatarType="text">{getInitials(displayName)}</Avatar>
<div>
<StyledEllipsis>
{displayName}{' '}
{isMe && t('__WORKSPACE_SETTINGS_CURRENT_MEMBER_YOU_LABEL')}
</StyledEllipsis>
</div>
<div className="actions">
{!isMe && (
<Dropdown
onStateChange={(options) =>
Object.hasOwn(options, 'isOpen') && setRotated(options.isOpen)
}
>
<Trigger>
<Button isBasic aria-label="user management actions">
{user.invitationPending ? (
<Span hue={globalTheme.palette.orange[600]}>
{t('__WORKSPACE_SETTINGS_MEMBER_INVITATION_PENDING_LABEL')}
</Span>
) : (
t('__WORKSPACE_SETTINGS_MEMBER_ACTIONS_LABEL')
)}
<Button.EndIcon isRotated={rotated}>
<ChevronIcon />
</Button.EndIcon>
</Button>
</Trigger>
<Menu placement="bottom-end">
{user.invitationPending && (
<Item
value="invite"
onClick={() =>
addNewMember({
wid: activeWorkspace.id.toString() || '0',
body: {
email: user.email,
},
}).unwrap()
}
>
{t('__WORKSPACE_SETTINGS_MEMBER_RESEND_INVITE_ACTION')}
</Item>
)}
<Item
value="remove"
onClick={() =>
removeUser({
wid: activeWorkspace.id.toString() || '0',
body: {
user_id: user.id,
},
}).unwrap()
}
>
<Span hue={globalTheme.colors.dangerHue}>
{t('__WORKSPACE_SETTINGS_MEMBER_REMOVE_USER_ACTION')}
</Span>
</Item>
</Menu>
</Dropdown>
)}
</div>
</UserListItem>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Button, Modal, ModalClose } from '@appquality/unguess-design-system';
import { useAppSelector } from 'src/app/hooks';
import styled from 'styled-components';
import { ReactComponent as GearIcon } from 'src/assets/icons/gear-fill.svg';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useGetWorkspacesByWidUsersQuery } from 'src/features/api';
import { AddNewMemberInput } from './addNewMember';
import { UserItem } from './userItem';
import { WorkspaceSettingsFooter } from './modalFooter';

const FlexContainer = styled.div<{ loading?: boolean }>`
display: flex;
flex-direction: column;
padding-top: ${({ theme }) => theme.space.base * 2}px;
margin-bottom: ${({ theme }) => theme.space.base * 6}px;
min-height: 0;
opacity: ${({ loading }) => (loading ? 0.5 : 1)};
`;

const FixedBody = styled(Modal.Body)`
overflow: hidden;
padding-bottom: 0;
`;

export const WorkspaceSettings = () => {
const { activeWorkspace } = useAppSelector((state) => state.navigation);
const { t } = useTranslation();
const [isModalOpen, setIsModalOpen] = useState(false);

const { isLoading, isFetching, data } = useGetWorkspacesByWidUsersQuery({
wid: activeWorkspace?.id.toString() || '0',
});

if (!activeWorkspace) return null;

return (
<>
<Button isBasic onClick={() => setIsModalOpen(true)}>
<Button.StartIcon>
<GearIcon />
</Button.StartIcon>
{t('__WORKSPACE_SETTINGS_CTA_TEXT')}
</Button>
{isModalOpen && (
<Modal onClose={() => setIsModalOpen(false)}>
<Modal.Header>{t('__WORKSPACE_SETTINGS_MODAL_TITLE')}</Modal.Header>
<FixedBody>
<AddNewMemberInput />
</FixedBody>
<Modal.Body style={{ paddingTop: 0 }}>
<FlexContainer loading={isLoading || isFetching}>
{data?.items.map((user) => (
<UserItem user={user} />
))}
</FlexContainer>
</Modal.Body>
<WorkspaceSettingsFooter />
<ModalClose />
</Modal>
)}
</>
);
};
17 changes: 10 additions & 7 deletions src/common/components/navigation/header/workspaceDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { useLocalizeRoute } from 'src/hooks/useLocalizedRoute';
import { useNavigate } from 'react-router-dom';
import { selectWorkspaces } from 'src/features/workspaces/selectors';
import { useTranslation } from 'react-i18next';
import { WorkspaceSettings } from './settings/workspaceSettings';

const StyledEllipsis = styled(Ellipsis)<{ isCompact?: boolean }>`
${({ theme, isCompact }) =>
Expand All @@ -44,11 +45,9 @@ const DropdownItem = styled(HeaderItem)`
}
`;

const BrandName = styled(HeaderItem)`
margin-right: auto;
margin-left: -8px;
const BrandName = styled(HeaderItemText)`
margin-right: ${({ theme }) => theme.space.sm}};
color: ${({ theme }) => theme.colors.primaryHue};
pointer-events: none;
font-family: ${({ theme }) => theme.fonts.system};
@media (max-width: ${({ theme }) => theme.breakpoints.md}) {
display: none;
Expand Down Expand Up @@ -121,10 +120,14 @@ export const WorkspacesDropdown = () => {
workspaces.map((item) => <Item value={item}>{item.company}</Item>)}
</Menu>
</Dropdown>
<WorkspaceSettings />
</DropdownItem>
) : (
<BrandName>
<HeaderItemText>{`${activeWorkspace?.company}'s Workspace`}</HeaderItemText>
</BrandName>
<>
<BrandName>{`${activeWorkspace?.company}'s Workspace`}</BrandName>
<DropdownItem>
<WorkspaceSettings />
</DropdownItem>
</>
);
};
10 changes: 10 additions & 0 deletions src/common/components/utils/getExcludeNotABugInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { TFunction } from 'i18next';
import { DEFAULT_NOT_A_BUG_CUSTOM_STATUS } from 'src/constants';

export const getExcludeNotABugInfo = (t: TFunction) => ({
customStatusId: DEFAULT_NOT_A_BUG_CUSTOM_STATUS.id,
customStatusName: DEFAULT_NOT_A_BUG_CUSTOM_STATUS.name,
actionIdentifier: 'excludeNotABug',
recapTitle: t('__BUGS_EXCLUDED_NOT_A_BUG'),
drawerTitle: t('__BUGS_EXCLUDE_NOT_A_BUG'),
});
5 changes: 5 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,8 @@ export const RELATIVE_DATE_FORMAT_OPTS: {
other: "EEEE',' d MMMM Y",
},
};

export const DEFAULT_NOT_A_BUG_CUSTOM_STATUS = {
id: 7,
name: 'not a bug',
};
Loading