diff --git a/global.d.ts b/global.d.ts index de3b367a4..002d4f038 100644 --- a/global.d.ts +++ b/global.d.ts @@ -52,6 +52,7 @@ interface TInvite { organizationName: string; code: string; email: string; + name: string; createdAt: Date; } @@ -60,7 +61,8 @@ interface TMember { organizationId: string; fullName: string; email: string; - created_at: Date; + name: string; + created: Date; active: boolean; activation_token: string; } diff --git a/src/api/organizations/inviteApi.ts b/src/api/organizations/inviteApi.ts index 21ebd8bb3..30df5838a 100644 --- a/src/api/organizations/inviteApi.ts +++ b/src/api/organizations/inviteApi.ts @@ -7,13 +7,11 @@ import mockApi from '../mockApiData'; const inviteApi = ({ authenticationToken, name, - email, }: { authenticationToken: string; name: string; - email: string; -}): Promise => - fetchApiWithAuthRequest({ +}): Promise => +fetchApiWithAuthRequest({ url: apiUrl(endpoints.organizations.invite), method: httpMethods.post, authenticationToken, @@ -21,8 +19,7 @@ const inviteApi = ({ 'Content-Type': 'application/json', }, data: JSON.stringify({ - name, - email, + name }), }).catch((res) => { if (process.env.REACT_APP_MOCKAPI_RESPONSE) { diff --git a/src/api/session/emailUpdate.ts b/src/api/session/emailUpdate.ts index b72e0d331..2dc75a9ee 100644 --- a/src/api/session/emailUpdate.ts +++ b/src/api/session/emailUpdate.ts @@ -5,12 +5,12 @@ import { apiUrl } from '../apiUrl'; const emailUpdate = ({ userId, - email, + fullName, name, authenticationToken, }: { userId: string, - email: string + fullName: string name: string; authenticationToken: string; }): Promise => @@ -21,7 +21,7 @@ const emailUpdate = ({ headers: { 'Content-Type': 'application/json', }, - data: { email, name }, + data: { full_name: fullName, name }, }); export default emailUpdate; \ No newline at end of file diff --git a/src/api/session/loginApi.ts b/src/api/session/loginApi.ts index 028a2ae77..3570ef594 100644 --- a/src/api/session/loginApi.ts +++ b/src/api/session/loginApi.ts @@ -30,11 +30,11 @@ interface Params { // password: account.password, // }), // }).catch((res) => { -// // if (process.env.REACT_APP_MOCKAPI_RESPONSE) { +// if (process.env.REACT_APP_MOCKAPI_RESPONSE) { // res = { // data: mockApi.loginMockResponse, // }; -// // } +// } // return res; // }); @@ -50,4 +50,5 @@ const loginApi = ({ account }: Params): Promise => password: account.password, }), }); + export default loginApi; diff --git a/src/api/session/signUpApi.ts b/src/api/session/signUpApi.ts index 5425fae87..ee7a49402 100644 --- a/src/api/session/signUpApi.ts +++ b/src/api/session/signUpApi.ts @@ -9,8 +9,9 @@ export interface Response { } interface NewAccount { + userId: string; username: string; - fullname: any; + fullName: any; email: string; password: string; token: string; @@ -22,14 +23,14 @@ interface Params { const signUpApi = ({ account }: Params): Promise => fetchApi({ - url: apiUrl(endpoints.signup(account.username)), + url: apiUrl(endpoints.signup(account.userId)), method: httpMethods.put, headers: { 'Content-Type': 'application/json', }, data: JSON.stringify({ name: account.username, - full_name: account.fullname, + full_name: account.fullName, email: account.email, password: account.password, activation_token: account.token diff --git a/src/api/users/getMyUserApi.ts b/src/api/users/getMyUserApi.ts index 0138a36be..4959f193c 100644 --- a/src/api/users/getMyUserApi.ts +++ b/src/api/users/getMyUserApi.ts @@ -1,5 +1,5 @@ import { fetchApiWithAuthRequest } from '../fetchApi'; -import { endpoints } from '../endpoints'; +import { endpoints } from '../endpoints'; import { httpMethods } from '../constants'; import { apiUrl } from '../apiUrl'; import mockApi from '../mockApiData'; diff --git a/src/redux/actions/organizations/inviteAction.ts b/src/redux/actions/organizations/inviteAction.ts index d9ec2b5da..d97414db2 100644 --- a/src/redux/actions/organizations/inviteAction.ts +++ b/src/redux/actions/organizations/inviteAction.ts @@ -3,12 +3,10 @@ import inviteApi from '../../../api/organizations/inviteApi'; export const inviteAction = ({ name, - email, onFailure, onSuccess, }: { name: string; - email: string; onFailure?: (err: any) => void; onSuccess?: () => void; }): TRequestAction => ({ @@ -18,7 +16,7 @@ export const inviteAction = ({ isAuthenticated: true, failureActionType: organizationActionTypes.invite.failure, successActionType: organizationActionTypes.invite.success, - params: { name, email }, + params: { name }, onFailure, onSuccess, }, diff --git a/src/redux/actions/session/emailUpdate.ts b/src/redux/actions/session/emailUpdate.ts index c1c03947e..d686ef01c 100644 --- a/src/redux/actions/session/emailUpdate.ts +++ b/src/redux/actions/session/emailUpdate.ts @@ -3,13 +3,13 @@ import emailUpdateApi from '../../../api/session/emailUpdate'; export const emailUpdateAction = ({ userId, - email, + fullName, name, onSuccess, onFailure, }: { userId: string; - email: string; + fullName: string; name: string; onSuccess?: () => void; onFailure?: () => void; @@ -22,6 +22,6 @@ export const emailUpdateAction = ({ successActionType: updateEmailTypes.success, onSuccess, onFailure, - params: { userId, email, name }, + params: { userId, fullName, name }, }, }); diff --git a/src/redux/actions/session/signupAction.ts b/src/redux/actions/session/signupAction.ts index 5fc52a6e7..6598afd9e 100644 --- a/src/redux/actions/session/signupAction.ts +++ b/src/redux/actions/session/signupAction.ts @@ -2,6 +2,7 @@ import { signupActionTypes } from '../../actionTypes'; import signUpApi from '../../../api/session/signUpApi'; export const signUpAction = ({ + userId, username, email, fullName, @@ -10,6 +11,7 @@ export const signUpAction = ({ onSuccess, onFailure, }: { + userId: string; username: string; email: string; fullName: string; @@ -28,6 +30,7 @@ export const signUpAction = ({ onFailure, params: { account: { + userId, username, email, fullName, diff --git a/src/services/locales/zu.json b/src/services/locales/zu.json index 2080bdd11..f65177834 100644 --- a/src/services/locales/zu.json +++ b/src/services/locales/zu.json @@ -63,9 +63,9 @@ "label": "Change Password", "button": "Change Password" }, - "emailNameReset": { - "label": "Change Email and Username", - "button": "Change Email and Username" + "nameReset": { + "label": "Save Changes", + "button": "Save Changes" }, "toasts": { "successful": { @@ -76,8 +76,8 @@ } }, "popup": { - "title": "Change Email and Username", - "text": "Are you sure to change your email and username", + "title": "Change full name and Username", + "text": "Are you sure to change your full name and username", "successButton": { "text": "Yes" }, @@ -165,11 +165,10 @@ }, "popup": { "title": "Add a new Member", - "email": { - "label": "Email", - "placeholder": "Email", - "required": "Email is required", - "invalidEmail": "Email is not valid" + "username": { + "label": "Username", + "placeholder": "Username", + "required": "Username is required" }, "role": { "label": "Role", @@ -180,8 +179,8 @@ "text": "Invite" }, "generateInviteModal": { - "title": "Invitation Token", - "text": "Click generate token to re-generate invitation for", + "title": "New Invitation Token", + "text": " Generate a new invite token for", "button": { "text": "Generate Token" } diff --git a/src/ui/components/forms/index.tsx b/src/ui/components/forms/index.tsx index e71a3a31e..7881c6580 100644 --- a/src/ui/components/forms/index.tsx +++ b/src/ui/components/forms/index.tsx @@ -123,7 +123,7 @@ export const CopyField = ( }; return ( - + { useEffect(() => { const getDashboardData = async () => { - const { data } = await axios.get(`http://localhost:8080/v1/projects/${DEFAULT_PROJECT_NAME}/statistics`, { + const { data } = await axios.get(`${process.env.REACT_APP_BASE_API_URL}/projects/${DEFAULT_PROJECT_NAME}/statistics`, { headers: { 'Authorization': `bearer ${authToken}` } @@ -74,7 +73,7 @@ export const Home: React.FC = () => { setDashboardData(data) } getDashboardData() - }, []) + }, [authToken]) const preData = Object.entries(dashboardData) const data = preData?.map(([key, value]) => { diff --git a/src/ui/layouts/common/Table/index.tsx b/src/ui/layouts/common/Table/index.tsx index 525ad33db..66104de15 100644 --- a/src/ui/layouts/common/Table/index.tsx +++ b/src/ui/layouts/common/Table/index.tsx @@ -10,7 +10,6 @@ import { H3, Truncate, FullWidthSpinner, - // FullWidthSpinner, } from '../../../components'; import { getPaginationData } from '../../../../utils/pagination'; import { Pagination } from '../Pagination'; @@ -69,7 +68,6 @@ export const Table: React.FC = ({ 0 && !loading} - // condition={tableRows.length > 0} renderWhenTrue={() => ( <> diff --git a/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/Menu/index.tsx b/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/Menu/index.tsx index 9d9681a1f..b9ddfbf2a 100644 --- a/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/Menu/index.tsx +++ b/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/Menu/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { MenuItem } from './MenuItem'; import { routePaths } from '../../../../../../../routes/routePaths'; -import { Box, Separator, icons } from '../../../../../../components'; +import { icons } from '../../../../../../components'; import { iconSizes, iconColors } from '../../../../../../../constants'; import { translate } from '../translate'; import { useLocationPath } from '../../../../../../hooks'; @@ -18,16 +18,6 @@ export const Menu: React.FC = () => { return ( <> - } - to={routePaths.home} - text={translate('menu.home.text')} - exact - /> - - - - { return ( @@ -66,7 +56,6 @@ export const Menu: React.FC = () => { to={routePaths.stacks.list} text={translate('menu.stacks.text')} /> - {/*
console.log('asdasd')}> */} { return !!matchPath(locationPath, { @@ -82,10 +71,33 @@ export const Menu: React.FC = () => { )} text={translate('menu.stackComponents.text')} /> - {/*
*/} - {locationPath.includes('components') && ( - <> - {/* + {stackComponentsTypes?.map((item) => ( + { + return !!matchPath(locationPath, { + path: routePaths.stackComponents.base(item), + exact: false, + }); + }} + subItem={true} + Icon={() => ( + + )} + to={routePaths.stackComponents.base(item)} + text={item} + /> + ) + )} + + )} + + {/* { // return !!matchPath(locationPath, { // path: routePaths.stackComponents.base(item), @@ -99,40 +111,7 @@ export const Menu: React.FC = () => { to={routePaths.stackComponents.base(stackComponentsTypes[0])} text={translate('menu.stackComponents.text')} /> */} - ; - {stackComponentsTypes?.map((item) => ( - <> - { - return !!matchPath(locationPath, { - path: routePaths.stackComponents.base(item), - exact: false, - }); - }} - subItem={true} - Icon={() => ( - - )} - to={routePaths.stackComponents.base(item)} - text={item} - /> - ; - - ))} - {/* - ( - - )} - to={routePaths.datasources} - text={translate('menu.stackComponents.text')} - /> */} - - )} + {/* ( diff --git a/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/SideFooter/MenuItemExternal.module.scss b/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/SideFooter/MenuItemExternal.module.scss index c1c7b1712..1c582cd2c 100644 --- a/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/SideFooter/MenuItemExternal.module.scss +++ b/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/SideFooter/MenuItemExternal.module.scss @@ -10,7 +10,7 @@ $bgColor: rgba(201, 203, 208, 0.2); .menuItem { display: block; text-decoration: none; - border-radius: 4px + border-radius: 4px; } .menuItem, diff --git a/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/SideFooter/MenuItemExternal.tsx b/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/SideFooter/MenuItemExternal.tsx index 5065df801..0a8613373 100644 --- a/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/SideFooter/MenuItemExternal.tsx +++ b/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/SideFooter/MenuItemExternal.tsx @@ -10,7 +10,7 @@ export const MenuItemExternal: React.FC<{ }> = ({ text, to, Icon, subItem }) => { return ( - + diff --git a/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/SideFooter/index.tsx b/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/SideFooter/index.tsx index 036cc12a0..236a6fd8b 100644 --- a/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/SideFooter/index.tsx +++ b/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/SideFooter/index.tsx @@ -2,23 +2,31 @@ import React, { useState, useEffect } from 'react'; import { MenuItem } from '../Menu/MenuItem'; import { MenuItemExternal } from './MenuItemExternal'; import { routePaths } from '../../../../../../../routes/routePaths'; -import { Box, Separator, icons } from '../../../../../../components'; +import { Box, Separator, icons, Paragraph } from '../../../../../../components'; import { iconSizes, iconColors } from '../../../../../../../constants'; import { translate } from '../translate'; +import { sessionSelectors } from '../../../../../../../redux/selectors/session'; +import { useSelector } from '../../../../../../hooks'; import axios from 'axios'; export const SideFooter: React.FC = () => { - const [apiVersion, setApiVersion] = useState(''); - useEffect(() => { - const getApiVersion = async () => { - const { data } = await axios.get('http://localhost:8080/version'); - setApiVersion(data); - }; + const authToken = useSelector(sessionSelectors.authenticationToken); + const [apiVersion, setApiVersion] = useState('') - getApiVersion(); - }, []); + useEffect(() => { + const getApiVersion = async () => { + const { data } = await axios.get(`${process.env.REACT_APP_BASE_API_URL}/version`, { + headers: { + 'Authorization': `bearer ${authToken}` + } + }) + setApiVersion(data) + } + getApiVersion() + }, [authToken]) + return ( <> @@ -45,21 +53,12 @@ export const SideFooter: React.FC = () => { ( - )} - to={routePaths.settings.personalDetails} - text={translate('menu.setting.text')} - exact - /> + )} to={routePaths.settings.personalDetails} text={translate('menu.setting.text')} /> - -
UI Version v{process.env.REACT_APP_VERSION}
-
ZenMl v{apiVersion}
-
- + + UI Version v{process.env.REACT_APP_VERSION} + ZenML v{apiVersion} + + ); }; diff --git a/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/SideHeader/index.tsx b/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/SideHeader/index.tsx new file mode 100644 index 000000000..1d0e54193 --- /dev/null +++ b/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/SideHeader/index.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { MenuItem } from '../Menu/MenuItem'; +import { routePaths } from '../../../../../../../routes/routePaths'; +import { Box, Separator, icons } from '../../../../../../components'; +import { iconSizes, iconColors } from '../../../../../../../constants'; +import { translate } from '../translate'; + +export const SideHeader: React.FC = () => { + + return ( + <> + } + to={routePaths.home} + text={translate('menu.home.text')} + exact + /> + + + + + ); +}; diff --git a/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/index.tsx b/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/index.tsx index a7febb0e1..4e8774c43 100644 --- a/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/index.tsx +++ b/src/ui/layouts/common/layouts/AuthenticatedLayout/AuthenticatedSidebar/index.tsx @@ -1,6 +1,5 @@ import React from 'react'; import cn from 'classnames'; - import { FlexBox, Box, @@ -8,15 +7,19 @@ import { LinkBox, If, } from '../../../../../components'; - +import { usePushRoute } from '../../../../../hooks'; import { Menu } from './Menu'; import styles from './index.module.scss'; +import { SideHeader } from './SideHeader'; import { SideFooter } from './SideFooter'; export const AuthenticatedSidebar: React.FC<{ mobileMenuOpen: boolean; setMobileMenuOpen: (val: boolean) => void; }> = ({ mobileMenuOpen, setMobileMenuOpen }) => { + + const { push } = usePushRoute(); + return ( <> @@ -32,11 +35,12 @@ export const AuthenticatedSidebar: React.FC<{ className={cn(styles.sidebar, mobileMenuOpen && styles.mobileSidebarOpen)} > push('/')} > @@ -46,7 +50,8 @@ export const AuthenticatedSidebar: React.FC<{ justifyContent='space-between' style={{ height: '90%' }} > - + + diff --git a/src/ui/layouts/pipelines/PipelineDetail/Configuration/index.tsx b/src/ui/layouts/pipelines/PipelineDetail/Configuration/index.tsx index a090b4a80..76a1d8fa8 100644 --- a/src/ui/layouts/pipelines/PipelineDetail/Configuration/index.tsx +++ b/src/ui/layouts/pipelines/PipelineDetail/Configuration/index.tsx @@ -2,10 +2,14 @@ import React from 'react'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { okaidia } from 'react-syntax-highlighter/dist/esm/styles/prism'; -import { FlexBox, H4, GhostButton } from '../../../../components'; +import { Box, FlexBox, H4, GhostButton, icons } from '../../../../components'; -import { translate } from '../translate'; +import { useDispatch } from '../../../../hooks'; +import { showToasterAction } from '../../../../../redux/actions'; +import { toasterTypes } from '../../../../../constants'; +import { iconColors, iconSizes } from '../../../../../constants'; +import { translate } from '../translate'; import styles from './index.module.scss'; import { useService } from './useService'; @@ -14,6 +18,17 @@ export const Configuration: React.FC<{ pipelineId: TId }> = ({ }) => { const { downloadYamlFile, pipelineConfig } = useService({ pipelineId }); + const dispatch = useDispatch() + const handleCopy = () => { + navigator.clipboard.writeText(pipelineConfig) + dispatch( + showToasterAction({ + description: 'Config copied to clipboard', + type: toasterTypes.success, + }), + ); + } + return ( = ({ justifyContent="space-between" >

{translate('configuration.title.text')}

- - {translate('configuration.button.text')} - + + + {translate('configuration.button.text')} + + + + +
= ({ style={okaidia} > {pipelineConfig} - +
); diff --git a/src/ui/layouts/pipelines/PipelineDetail/index.tsx b/src/ui/layouts/pipelines/PipelineDetail/index.tsx index 8890297dd..1ff3143ba 100644 --- a/src/ui/layouts/pipelines/PipelineDetail/index.tsx +++ b/src/ui/layouts/pipelines/PipelineDetail/index.tsx @@ -1,5 +1,8 @@ import React from 'react'; +import { Box, Paragraph, icons } from '../../../components'; +import { iconColors, iconSizes } from '../../../../constants'; +import { formatDateToDisplay } from '../../../../utils'; import { routePaths } from '../../../../routes/routePaths'; import { translate } from './translate'; import { Configuration } from './Configuration'; @@ -47,13 +50,79 @@ export const PipelineDetail: React.FC = () => { const tabPages = getTabPages(pipeline.id); const breadcrumbs = getBreadcrumbs(pipeline.id); + const boxStyle = { + backgroundColor: '#E9EAEC', + padding: '30px 0', + borderRadius: '8px', + marginTop: '20px', + display: 'flex', + justifyContent: 'space-around', + }; + const headStyle = { color: '#828282' }; + return ( + > + + + ID + + {pipeline.id} + + + + NAME + + {pipeline.name} + + + + SHARED + + {pipeline.isShared ? ( + + ) : ( + + )} + + + + OWNER + + {pipeline.user.name} + + + + CREATED AT + + {formatDateToDisplay(pipeline.created)} + + + + + ); }; diff --git a/src/ui/layouts/pipelines/Pipelines/List/getHeaderCols.tsx b/src/ui/layouts/pipelines/Pipelines/List/getHeaderCols.tsx index a0b554c62..19f94373b 100644 --- a/src/ui/layouts/pipelines/Pipelines/List/getHeaderCols.tsx +++ b/src/ui/layouts/pipelines/Pipelines/List/getHeaderCols.tsx @@ -53,7 +53,7 @@ export const getHeaderCols = ({ ID ), - width: '13%', + width: '8%', renderRow: (pipeline: TPipeline) => ( {truncate(pipeline.id, ID_MAX_LENGTH)} @@ -66,7 +66,7 @@ export const getHeaderCols = ({ NAME ), - width: '15%', + width: '8%', renderRow: (pipeline: TPipeline) => ( {pipeline.name} ), @@ -77,14 +77,14 @@ export const getHeaderCols = ({ STATUS ), - width: '10%', + width: '8%', renderRow: (pipeline: TPipeline) => , }, { render: () => ( - AUTHOR + OWNER ), width: '11%', diff --git a/src/ui/layouts/session/Login/Form.tsx b/src/ui/layouts/session/Login/Form.tsx index ed8a2e606..79522b6de 100644 --- a/src/ui/layouts/session/Login/Form.tsx +++ b/src/ui/layouts/session/Login/Form.tsx @@ -56,6 +56,7 @@ export const Form: React.FC = () => { hasError: hasSubmittedWithErrors && password.trim() === '', text: translate('form.password.required'), }} + showPasswordOption /> void; hasSubmittedWithErrors: boolean; + userId: string; username: string, setUsername: (username: string) => void, email: string; @@ -26,8 +27,9 @@ export const useService = (): ServiceInterface => { const location = useLocation() const params = new URLSearchParams(location.search) - const preEmail = params.get('email') + const preUsername = params.get('username') const token = params.get('token') + const id = params.get('user') const [loading, setLoading] = useState(false); const [username, setUsername] = useState(''); @@ -36,13 +38,14 @@ export const useService = (): ServiceInterface => { const [password, setPassword] = useState(''); const [hasSubmittedWithErrors, setHasSubmittedWithErrors] = useState(false); + const userId = id ? id : username + const dispatch = useDispatch(); const { push } = usePushRoute(); useEffect(() => { - setUsername(preEmail ? preEmail : ''); - setEmail(preEmail ? preEmail : ''); - }, [preEmail]); + setUsername(preUsername ? preUsername : ''); + }, [preUsername]); return { signup: () => { @@ -51,6 +54,7 @@ export const useService = (): ServiceInterface => { if (username.trim() !== '' && email.trim() !== '' && password.trim() !== '') { dispatch( signUpAction({ + userId, username, email, fullName, @@ -80,6 +84,7 @@ export const useService = (): ServiceInterface => { } }, hasSubmittedWithErrors, + userId, username, setUsername, email, diff --git a/src/ui/layouts/settings/EmailPopup.tsx b/src/ui/layouts/settings/EmailPopup.tsx index 5d349ba53..a5ec58c78 100644 --- a/src/ui/layouts/settings/EmailPopup.tsx +++ b/src/ui/layouts/settings/EmailPopup.tsx @@ -19,23 +19,22 @@ import { useSelector } from '../../hooks'; export const EmailPopup: React.FC<{ userId: any; - email: any; + fullName: any; username: any; setPopupOpen: (attr: boolean) => void; -}> = ({ userId, email, username, setPopupOpen }) => { +}> = ({ userId, fullName, username, setPopupOpen }) => { + const [submitting, setSubmitting] = useState(false); const dispatch = useDispatch(); const translate = getTranslateByScope('ui.layouts.PersonalDetails'); - const authToken = useSelector(sessionSelectors.authenticationToken); - const changeEmail = async () => { setSubmitting(true); dispatch( sessionActions.emailUpdate({ userId, - email, + fullName, name: username, onFailure: () => { setSubmitting(false); diff --git a/src/ui/layouts/settings/Organization/DeleteMember.tsx b/src/ui/layouts/settings/Organization/DeleteMember.tsx index a6711c908..76e43b7f5 100644 --- a/src/ui/layouts/settings/Organization/DeleteMember.tsx +++ b/src/ui/layouts/settings/Organization/DeleteMember.tsx @@ -37,7 +37,7 @@ export const DeleteMember: React.FC<{ member: TInvite }> = ({ member }) => { onSuccess: () => { setPopupOpen(false); setSubmitting(false); - dispatch(organizationActions.getInvites({})); + dispatch(organizationActions.getMembers({})); dispatch( showToasterAction({ type: 'success', diff --git a/src/ui/layouts/settings/Organization/InvitePopup.tsx b/src/ui/layouts/settings/Organization/InvitePopup.tsx index 41f6e8469..af84691de 100644 --- a/src/ui/layouts/settings/Organization/InvitePopup.tsx +++ b/src/ui/layouts/settings/Organization/InvitePopup.tsx @@ -9,73 +9,55 @@ import { translate } from './translate'; import { Box, FlexBox, - FormEmailField, + FormTextField, CopyField, H3, PrimaryButton, } from '../../../components'; -import { useDispatch, useSelector } from '../../../hooks'; +import { useSelector, useDispatch } from '../../../hooks'; import { Popup } from '../../common/Popup'; -import { fieldValidation } from '../../../../utils'; import { organizationSelectors } from '../../../../redux/selectors'; -const emailHasError = (email: string, hasSubmittedWithErrors: boolean) => - (hasSubmittedWithErrors && email.trim() === '') || - (hasSubmittedWithErrors && !fieldValidation(email.trim()).isEmail()); +export const InvitePopup: React.FC<{ setPopupOpen: (attr: boolean) => void }> + = ({ setPopupOpen}) => { -const emailErrorText = (email: string) => - email.trim() !== '' && !fieldValidation(email.trim()).isEmail() - ? translate('popup.email.invalidEmail') - : translate('popup.email.required'); - -export const InvitePopup: React.FC<{ - setPopupOpen: (attr: boolean) => void; -}> = ({ setPopupOpen }) => { const [submitting, setSubmitting] = useState(false); - const [hasSubmittedWithErrors, setHasSubmittedWithErrors] = useState(false); - const [email, setEmail] = useState(''); - const [showTokField, setShowTokField] = useState(false); + const [name, setName] = useState('') + const [showTokField, setShowTokField] = useState(false) const dispatch = useDispatch(); const invite = useSelector(organizationSelectors.invite); const inviteNewMembers = () => { - setHasSubmittedWithErrors(true); - - let error = false; - if (emailHasError(email || '', true)) { - error = true; - } - - if (!error) { + setSubmitting(true); dispatch( - organizationActions.invite({ - name: email, - email: email, - onFailure: (errorText: string) => { - dispatch( - showToasterAction({ - description: errorText, - type: toasterTypes.failure, - }), - ); - setSubmitting(false); - }, - onSuccess: () => { - setShowTokField(true); - }, - }), - ); - } + organizationActions.invite({ + name, + onFailure: (errorText: string) => { + dispatch( + showToasterAction({ + description: errorText, + type: toasterTypes.failure, + }), + ); + setSubmitting(false); + }, + onSuccess: () => { + dispatch(organizationActions.getMembers({})); + setSubmitting(false); + setShowTokField(true) + } + }), + ); }; + return ( { setPopupOpen(false); - setHasSubmittedWithErrors(false); - }} + }} >

@@ -85,44 +67,45 @@ export const InvitePopup: React.FC<{

- - - - setEmail(val)} - error={{ - hasError: emailHasError(email || '', hasSubmittedWithErrors), - text: emailErrorText(email || ''), - }} - /> - - - {!showTokField && ( - - - {translate('popup.button.text')} - + + + + setName(val)} + error={{ + hasError: false, + text: '' + }} + /> - )} - - - {showTokField && ( - - - - )} - + + {!showTokField && ( + + + {translate('popup.button.text')} + + + )} + + + {showTokField && ( + + + + )} +
); diff --git a/src/ui/layouts/settings/Organization/index.tsx b/src/ui/layouts/settings/Organization/index.tsx index 0b88725b4..a21df8c35 100644 --- a/src/ui/layouts/settings/Organization/index.tsx +++ b/src/ui/layouts/settings/Organization/index.tsx @@ -1,17 +1,16 @@ -import React, { useEffect, useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { useSelector } from 'react-redux'; import { organizationActions } from '../../../../redux/actions'; import { organizationSelectors } from '../../../../redux/selectors'; -import { getInitials } from '../../../../utils'; + import { FlexBox, Box, - ColoredSquare, Paragraph, PrimaryButton, LinkBox, } from '../../../components'; -import { useRequestOnMount } from '../../../hooks'; +import { useRequestOnMount, useDispatch } from '../../../hooks'; import { Table } from '../../common/Table'; import { translate } from './translate'; import { useMemberHeaderCols } from './useHeaderCols'; @@ -20,48 +19,40 @@ import { InvitePopup } from './InvitePopup'; type Table = 'members' | 'invites'; export const Organization: React.FC = () => { + + const dispatch = useDispatch() + const [fetchingMembers, setFetchingMembers] = useState(true); const [popupOpen, setPopupOpen] = useState(false); const [currentTable, setCurrentTable] = useState('members'); - useRequestOnMount(organizationActions.getMy); - useRequestOnMount(organizationActions.getRoles); - - useRequestOnMount(() => - organizationActions.getMembers({ - onSuccess: () => setFetchingMembers(false), - onFailure: () => setFetchingMembers(false), - }), - ); - const organization = useSelector(organizationSelectors.myOrganization); const members = useSelector(organizationSelectors.myMembers); - // const invites = useSelector(organizationSelectors.invites); const memberHeaderCols = useMemberHeaderCols(); + + useRequestOnMount(organizationActions.getMy); + useRequestOnMount(organizationActions.getRoles); + useEffect(() => { - //This is important - }, [members]); + dispatch(organizationActions.getMembers({ + onSuccess: () => setFetchingMembers(false), + onFailure: () => setFetchingMembers(false), + }), + ); + }, [dispatch]) + if (!organization) return null; return ( <> - {popupOpen && } - + {popupOpen && ( + + )} - - - - - - {getInitials(organization.name)} - - - - - {organization.name} - - + setPopupOpen(true)}> {translate('button.text')} diff --git a/src/ui/layouts/settings/Organization/tokenPopup.tsx b/src/ui/layouts/settings/Organization/tokenPopup.tsx index 79de2a978..c737d04c7 100644 --- a/src/ui/layouts/settings/Organization/tokenPopup.tsx +++ b/src/ui/layouts/settings/Organization/tokenPopup.tsx @@ -9,7 +9,7 @@ import { translate } from './translate'; import { Box, FlexBox, - FormEmailField, + FormTextField, Paragraph, CopyField, H3, @@ -20,11 +20,12 @@ import { Popup } from '../../common/Popup'; import { organizationSelectors } from '../../../../redux/selectors'; export const TokenPopup: React.FC<{ - id: string; - email: string; - active: boolean; -}> = ({ id, email, active }) => { - const [popupOpen, setPopupOpen] = useState(false); + id: string; + username: string; + active: boolean +}> = ({ id, username, active }) => { + + const [popupOpen, setPopupOpen] = useState(false) const [submitting, setSubmitting] = useState(false); const [showTokField, setShowTokField] = useState(false); @@ -33,26 +34,30 @@ export const TokenPopup: React.FC<{ const inviteCode = useSelector(organizationSelectors.inviteForCode); const generateToken = () => { - setSubmitting(true); - dispatch( - organizationActions.inviteByCode({ - username: email, - onFailure: (errorText: string) => { - dispatch( - showToasterAction({ - description: errorText, - type: toasterTypes.failure, + setSubmitting(true); + dispatch( + organizationActions.inviteByCode({ + username, + onFailure: (errorText: string) => { + dispatch( + showToasterAction({ + description: errorText, + type: toasterTypes.failure, + }), + ); + setSubmitting(false); + setPopupOpen(false) + }, + onSuccess: () => { + setShowTokField(true) + } }), ); setSubmitting(false); setPopupOpen(false); - }, - onSuccess: () => { - setShowTokField(true); - }, - }), - ); - }; + } + + const onClose = () => { setShowTokField(false); @@ -62,33 +67,27 @@ export const TokenPopup: React.FC<{ return ( <> - setPopupOpen(true)} - > - {!active && 'Pending'} - - - {popupOpen && ( - - -

- {translate('popup.generateInviteModal.title')} -

-
- - {`${translate( - 'popup.generateInviteModal.text', - )} ${email}`} + setPopupOpen(true)} >{!active && 'Pending'} + + {popupOpen && ( + + +

+ {translate('popup.generateInviteModal.title')} +

+
+ + {`${translate('popup.generateInviteModal.text')} ${username}. This will invalidate the currently active token.`} - @@ -110,14 +109,14 @@ export const TokenPopup: React.FC<{ {showTokField && ( - - - - )} + + + + )}
diff --git a/src/ui/layouts/settings/Organization/useHeaderCols.tsx b/src/ui/layouts/settings/Organization/useHeaderCols.tsx index 1bd8c0cc2..4908aa353 100644 --- a/src/ui/layouts/settings/Organization/useHeaderCols.tsx +++ b/src/ui/layouts/settings/Organization/useHeaderCols.tsx @@ -23,7 +23,7 @@ export const useInviteHeaderCols = (): HeaderCol[] => { ), width: '70%', renderRow: (invite: TInvite) => { - const initials = getInitialsFromEmail(invite.email); + const initials = getInitialsFromEmail(invite.name); return ( @@ -31,7 +31,7 @@ export const useInviteHeaderCols = (): HeaderCol[] => { {initials} - {invite.email} + {invite.name} ); }, @@ -74,7 +74,7 @@ export const useMemberHeaderCols = (): HeaderCol[] => { ), width: '15%', renderRow: (member: TMember) => { - const initials = getInitialsFromEmail(member.email); + const initials = getInitialsFromEmail(member.name); return ( @@ -82,7 +82,7 @@ export const useMemberHeaderCols = (): HeaderCol[] => { {initials} - {member.email} + {member.name} ); }, @@ -97,7 +97,7 @@ export const useMemberHeaderCols = (): HeaderCol[] => { renderRow: (member: TMember) => ( {member.active === false ? ( - + ) : ( Accepted )} @@ -117,7 +117,7 @@ export const useMemberHeaderCols = (): HeaderCol[] => {
- {formatDateToDisplay(member.created_at)} + {formatDateToDisplay(member.created)} ), diff --git a/src/ui/layouts/settings/PersonalDetails.tsx b/src/ui/layouts/settings/PersonalDetails.tsx index a64283bbf..71538d5d6 100644 --- a/src/ui/layouts/settings/PersonalDetails.tsx +++ b/src/ui/layouts/settings/PersonalDetails.tsx @@ -1,12 +1,9 @@ import React, { useState } from 'react'; -import { getInitials } from '../../../utils'; import { Box, - ColoredSquare, FlexBox, FormTextField, FormPasswordField, - Paragraph, Row, Col, } from '../../components'; @@ -37,11 +34,11 @@ export const PersonalDetails: React.FC = () => { const [submitting, setSubmitting] = useState(false); const [popupOpen, setPopupOpen] = useState(false); - const [email, setEmail] = useState(user?.email); - const [username, setUsername] = useState(user?.name); - const [currentPassword, setCurrentPassword] = useState(''); - const [newPassword, setNewPassword] = useState(''); - const [confirmPassword, setConfirmPassword] = useState(''); + const [fullName, setFullName] = useState(user?.fullName) + const [username, setUsername] = useState(user?.name) + const [currentPassword, setCurrentPassword] = useState('') + const [newPassword, setNewPassword] = useState('') + const [confirmPassword, setConfirmPassword] = useState('') if (!organization || !user) return null; @@ -84,38 +81,20 @@ export const PersonalDetails: React.FC = () => { return ( <> - {popupOpen && ( - - )} - - - - - - {getInitials(organization.name)} - - - - - {organization.name} - - - - + {popupOpen && ( + + )} + +
setEmail(val)} + label={translate('form.fullName.label')} + labelColor='#000' + placeholder={translate('form.fullName.placeholder')} + value={fullName ? fullName : ''} + onChange={(val: string) => setFullName(val)} /> @@ -129,15 +108,11 @@ export const PersonalDetails: React.FC = () => { /> - - setPopupOpen(true)} - disabled={email === user.email && username === user.name} - > - {translate('emailNameReset.label')} - - + + setPopupOpen(true)} disabled={fullName === user.fullName && username === user.name} > + {translate('nameReset.label')} + + @@ -204,7 +179,7 @@ export const PersonalDetails: React.FC = () => { > ( - FLAVOUR + FLAVOR ), width: '15%', @@ -68,7 +68,7 @@ export const getHeaderCols = ({ { render: () => ( - Shared + SHARED ), width: '15%', @@ -96,7 +96,7 @@ export const getHeaderCols = ({ { render: () => ( - USER + OWNER ), width: '15%', diff --git a/src/ui/layouts/stacks/RunsTable/HeaderCols/index.tsx b/src/ui/layouts/stacks/RunsTable/HeaderCols/index.tsx index 4276dd91c..5fcfd3730 100644 --- a/src/ui/layouts/stacks/RunsTable/HeaderCols/index.tsx +++ b/src/ui/layouts/stacks/RunsTable/HeaderCols/index.tsx @@ -165,7 +165,7 @@ export const useHeaderCols = ({ { render: () => ( - STACK NAME + OWNER ), width: '10%', @@ -173,7 +173,6 @@ export const useHeaderCols = ({ const initials = getInitialsFromEmail( run.user.full_name ? run.user.full_name : run.user.name, ); - console.log(run.status); return ( @@ -210,7 +209,7 @@ export const useHeaderCols = ({ activeSortingDirection={activeSortingDirection} > - CREATED AT + CREATED ), diff --git a/src/ui/layouts/stacks/StackDetail/Configuration/useService.ts b/src/ui/layouts/stacks/StackDetail/Configuration/useService.ts index 2dfb3542c..522706413 100644 --- a/src/ui/layouts/stacks/StackDetail/Configuration/useService.ts +++ b/src/ui/layouts/stacks/StackDetail/Configuration/useService.ts @@ -17,9 +17,9 @@ export const useService = ({ stackId }: { stackId: TId }): ServiceInterface => { }; Object.keys(stack.components).forEach((element) => { yamlConfigObj.components[element] = { - flavor: stack.components[element][0].flavor, - name: stack.components[element][0].name, - ...stack.components[element][0].configuration, + flavor: stack?.components[element][0]?.flavor_name, + name: stack?.components[element][0]?.name, + ...stack?.components[element][0]?.configuration, }; }); diff --git a/src/ui/layouts/stacks/StackDetail/index.tsx b/src/ui/layouts/stacks/StackDetail/index.tsx index 98c38dc31..eddb45c84 100644 --- a/src/ui/layouts/stacks/StackDetail/index.tsx +++ b/src/ui/layouts/stacks/StackDetail/index.tsx @@ -64,12 +64,12 @@ export const StackDetail: React.FC = () => { - Stack ID + ID @@ -77,7 +77,15 @@ export const StackDetail: React.FC = () => { - Shared + NAME + + {stack.name} + + + + SHARED { - Author + OWNER - {stack.userName} + {stack.user.name} - Created + CREATED - {formatDateToDisplay(stack.creationDate)} + {formatDateToDisplay(stack.created)} diff --git a/src/ui/layouts/stacks/Stacks/List/getHeaderCols.tsx b/src/ui/layouts/stacks/Stacks/List/getHeaderCols.tsx index d2dd5609f..9ec3b4d60 100644 --- a/src/ui/layouts/stacks/Stacks/List/getHeaderCols.tsx +++ b/src/ui/layouts/stacks/Stacks/List/getHeaderCols.tsx @@ -51,7 +51,7 @@ export const getHeaderCols = ({ { render: () => ( - STACK ID + ID ), width: '8%', @@ -62,7 +62,7 @@ export const getHeaderCols = ({ { render: () => ( - STACK NAME + NAME ), width: '8%',