From 0b1d4f52825b2036157e40002dfe58e36da32e48 Mon Sep 17 00:00:00 2001 From: Davit Date: Mon, 1 Jul 2024 12:36:23 +0400 Subject: [PATCH 1/4] add friendlyname and description debounced filtering --- .../Organizations/OrganizationsSkeleton.tsx | 14 +- .../Organizations/Organizations/index.tsx | 133 +++++++++++++----- src/pages/organizations/index.js | 9 +- 3 files changed, 117 insertions(+), 39 deletions(-) diff --git a/src/components/Organizations/Organizations/OrganizationsSkeleton.tsx b/src/components/Organizations/Organizations/OrganizationsSkeleton.tsx index 40191e0c..e0d9a676 100644 --- a/src/components/Organizations/Organizations/OrganizationsSkeleton.tsx +++ b/src/components/Organizations/Organizations/OrganizationsSkeleton.tsx @@ -5,7 +5,11 @@ import Box from 'components/Box'; import { Organization, OrganizationsPage, OrgsHeader, SearchInput } from './StyledOrganizations'; -const OrganizationsSkeleton = () => { +interface Props { + setSearch: React.Dispatch>; +} + +const OrganizationsSkeleton = ({ setSearch }: Props) => { const RenderSkeletonBox = (index: number) => { return ( @@ -27,7 +31,13 @@ const OrganizationsSkeleton = () => { - + setSearch(e.target.value)} + aria-labelledby="search" + className="searchInput" + type="text" + placeholder="Type to search" + /> <>{[...Array(numberOfItems)].map((_, idx) => RenderSkeletonBox(idx))} diff --git a/src/components/Organizations/Organizations/index.tsx b/src/components/Organizations/Organizations/index.tsx index 8d95711a..2ac00fb5 100644 --- a/src/components/Organizations/Organizations/index.tsx +++ b/src/components/Organizations/Organizations/index.tsx @@ -1,8 +1,11 @@ -import React, { useState } from 'react'; +import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import Highlighter from 'react-highlight-words'; +import { LoadingOutlined } from '@ant-design/icons'; +import { Spin } from 'antd'; import Box from 'components/Box'; import OrganizationLink from 'components/link/Organizations/Organization'; +import { debounce } from 'lib/util'; import { Organization, OrganizationsPage, OrgsHeader, SearchInput } from './StyledOrganizations'; @@ -14,29 +17,112 @@ export interface IOrganization { __typename: 'Organization'; } +interface OrganizationProps { + organizations: IOrganization[]; + initialSearch: string; +} /** * The primary list of organizations. */ -const Organizations = ({ organizations = [] }: { organizations: IOrganization[] }) => { - const [searchInput, setSearchInput] = useState(''); +const Organizations: FC = ({ organizations = [], initialSearch }) => { + const [searchInput, setSearchInput] = useState(initialSearch || ''); + + const [isFiltering, setIsFiltering] = useState(false); + const [filteredOrgs, setFilteredOrgs] = useState(organizations); + + const searchInputRef = useRef(null); + + useEffect(() => { + if (initialSearch && searchInputRef.current) { + searchInputRef.current.focus(); + } + }, []); + + const timerLengthPercentage = useMemo( + () => Math.min(1000, Math.max(40, Math.floor(organizations.length * 0.0725))), + [organizations.length] + ); + + const debouncedSearch = useCallback( + debounce((searchVal: string) => { + setSearchInput(searchVal); + }, timerLengthPercentage), + [] + ); + + const handleSearch = (searchVal: string) => { + setIsFiltering(true); + debouncedSearch(searchVal); + }; - const filteredOrganizations = organizations.filter(key => { - const sortByName = key.name.toLowerCase().includes(searchInput.toLowerCase()); - const sortByUrl = ''; - return ['name', 'environments', '__typename'].includes(key.name) ? false : (true && sortByName) || sortByUrl; - }); + useEffect(() => { + const filterOrgs = async (): Promise => { + return new Promise(resolve => { + const filteredOrganizations = organizations.filter(org => { + const searchStrLowerCase = searchInput.toLowerCase(); + const filterFn = (key?: string) => key?.toLowerCase().includes(searchStrLowerCase); + + const sortByName = filterFn(org.name); + const sortByDesc = filterFn(org.description); + const sortByFriendlyName = filterFn(org.friendlyName); + + if (['__typename', 'name', 'id'].includes(org.name)) { + return false; + } + return sortByName || sortByFriendlyName || sortByDesc; + }); + + resolve(filteredOrganizations); + }); + }; + + filterOrgs() + .then(filtered => setFilteredOrgs(filtered)) + .finally(() => setIsFiltering(false)); + }, [searchInput, organizations]); + + const filteredMappedOrgs = useMemo(() => { + return filteredOrgs.map(organization => ( + + + +

+ +

+
+ +
+
+
+
+
+ )); + }, [filteredOrgs]); return ( - + setSearchInput(e.target.value)} + onChange={e => handleSearch(e.target.value)} placeholder="Type to search" disabled={organizations.length === 0} /> @@ -48,37 +134,14 @@ const Organizations = ({ organizations = [] }: { organizations: IOrganization[]
)} - {searchInput && !filteredOrganizations.length && ( + {searchInput && !filteredMappedOrgs.length && (

No organizations matching "{searchInput}"

)} - {filteredOrganizations.map(organization => ( - - - -

- -

-
- -
-
-
-
-
- ))} + {filteredMappedOrgs} ); }; diff --git a/src/pages/organizations/index.js b/src/pages/organizations/index.js index c6d341f4..b95c99dd 100644 --- a/src/pages/organizations/index.js +++ b/src/pages/organizations/index.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState } from 'react'; import Head from 'next/head'; @@ -18,6 +18,7 @@ const OrganizationsPage = () => { const { data, error, loading } = useQuery(AllOrganizationsQuery, { displayName: 'AllOrganizationsQuery', }); + const [searchInput, setSearchInput] = useState(''); if (error) { return ; @@ -31,7 +32,11 @@ const OrganizationsPage = () => {

Organizations

- {loading ? : } + {loading ? ( + + ) : ( + + )}
From 0509a78dfd571ca0583385ba8d8b4ac9640c0e75 Mon Sep 17 00:00:00 2001 From: Davit Date: Mon, 1 Jul 2024 12:42:31 +0400 Subject: [PATCH 2/4] linr --- src/components/Organizations/Organizations/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Organizations/Organizations/index.tsx b/src/components/Organizations/Organizations/index.tsx index 2ac00fb5..00ac463c 100644 --- a/src/components/Organizations/Organizations/index.tsx +++ b/src/components/Organizations/Organizations/index.tsx @@ -76,7 +76,7 @@ const Organizations: FC = ({ organizations = [], initialSearc }); }; - filterOrgs() + void filterOrgs() .then(filtered => setFilteredOrgs(filtered)) .finally(() => setIsFiltering(false)); }, [searchInput, organizations]); From 3e31ce863e5bb8de879d1112b11cf92aa8942315 Mon Sep 17 00:00:00 2001 From: Davit Date: Mon, 1 Jul 2024 16:50:10 +0400 Subject: [PATCH 3/4] properly update notifications --- .../Organizations/Notifications/index.js | 800 +++++++++--------- 1 file changed, 405 insertions(+), 395 deletions(-) diff --git a/src/components/Organizations/Notifications/index.js b/src/components/Organizations/Notifications/index.js index cfa06c0b..e3e19dd3 100644 --- a/src/components/Organizations/Notifications/index.js +++ b/src/components/Organizations/Notifications/index.js @@ -100,6 +100,7 @@ const OrgNotifications = ({ open: false, type: '', current: {}, + updated: {}, }; const [editState, setEditState] = useState(initialEditState); @@ -130,8 +131,8 @@ const OrgNotifications = ({ const newValue = e.target.value; setEditState(prevState => ({ ...prevState, - current: { - ...prevState.current, + updated: { + ...prevState.updated, [property]: newValue, }, })); @@ -185,94 +186,95 @@ const OrgNotifications = ({ - - -
- -
- -
- -
- -
- -
-
-
- console.error(e)}> - {(updateSlack, { called, error, data }) => { - if (error) { - return
{error.message}
; - } - if (data) { - refresh().then(() => { - closeEditModal(); - }); - } - return ( - - ); - }} -
- -
-
- + }); + }} + > + Continue + + ); + }} + + + + + )} console.error(e)}> {(removeNotification, { called, error, data }) => { if (data) { @@ -316,93 +318,95 @@ const OrgNotifications = ({ - - -
- -
- -
- -
- -
- -
-
-
- console.error(e)}> - {(updateRocketChat, { called, error, data }) => { - if (error) { - return
{error.message}
; - } - if (data) { - refresh().then(() => { - closeEditModal(); - }); - } - return ( - - ); - }} -
- -
-
+ }); + }} + > + Continue + + ); + }} +
+ + + + )} console.error(e)}> {(removeNotification, { called, error, data }) => { if (error) { @@ -449,82 +453,84 @@ const OrgNotifications = ({ - - -
- -
- -
- - {!isValidEmail &&

Invalid email address

} -
-
-
- console.error(e)}> - {(updateEmail, { called, error, data }) => { - if (error) { - return
{error.message}
; - } - if (data) { - refresh().then(() => { - closeEditModal(); - }); - } - return ( - - ); - }} -
- -
-
+ {editState.current && editState.current.name === notification.name && ( + + +
+ +
+ +
+ + {!isValidEmail &&

Invalid email address

} +
+
+
+ console.error(e)}> + {(updateEmail, { called, error, data }) => { + if (error) { + return
{error.message}
; + } + if (data) { + refresh().then(() => { + closeEditModal(); + }); + } + return ( + + ); + }} +
+ +
+
+ )} console.error(e)}> {(removeNotification, { called, error, data }) => { if (data) { @@ -574,80 +580,81 @@ const OrgNotifications = ({ - - -
- -
- -
- -
-
-
- console.error(e)}> - {(updateWebhook, { called, error, data }) => { - if (error) { - return
{error.message}
; - } - if (data) { - refresh().then(() => { - closeEditModal(); - }); - } - return ( - - ); - }} -
- -
-
- + }); + }} + > + Continue + + ); + }} +
+ + + + )} console.error(e)}> {(removeNotification, { called, error, data }) => { if (data) { @@ -693,79 +700,82 @@ const OrgNotifications = ({ - - -
- -
- -
- -
-
-
- console.error(e)}> - {(updateTeams, { called, error, data }) => { - if (error) { - return
{error.message}
; - } - if (data) { - refresh().then(() => { - closeEditModal(); - }); - } - return ( - - ); - }} -
- -
-
+ }); + }} + > + Continue + + ); + }} +
+ + + + )} console.error(e)}> {(removeNotification, { called, error, data }) => { if (data) { From ef6950b701fce8f0446108be8b94bc9b18484b0b Mon Sep 17 00:00:00 2001 From: Davit Darsavelidze <76407236+DaveDarsa@users.noreply.github.com> Date: Thu, 4 Jul 2024 16:11:34 +0400 Subject: [PATCH 4/4] change: add branches and pullrequests during org project creation (#276) * add branches and pullrequests * textboxes for branches and prs * add tooltips * reduce spacing, add default indicator * fix pr/branches text * format tooltips as lists * cypress deployment tests * remove only * format * org project tests --- cypress/e2e/organizations/overview.cy.ts | 2 +- cypress/e2e/rbac/developer.cy.ts | 4 +- cypress/e2e/rbac/guest.cy.ts | 2 +- cypress/e2e/rbac/maintainer.cy.ts | 4 +- cypress/e2e/rbac/reporter.cy.ts | 4 +- .../actions/organizations/ProjectsActions.ts | 4 +- .../NewProject/StyledNewProject.tsx | 3 + .../Organizations/NewProject/index.js | 78 ++++++++++++++++++- src/layouts/GlobalStyles/index.tsx | 15 ++++ 9 files changed, 106 insertions(+), 10 deletions(-) diff --git a/cypress/e2e/organizations/overview.cy.ts b/cypress/e2e/organizations/overview.cy.ts index a02daa23..18debc2e 100644 --- a/cypress/e2e/organizations/overview.cy.ts +++ b/cypress/e2e/organizations/overview.cy.ts @@ -23,7 +23,7 @@ describe('Organization overview page', () => { overview.doQuotaFieldCheck(); }); - it.only('Changes org friendly name/description', () => { + it('Changes org friendly name/description', () => { registerIdleHandler('idle'); overview.changeOrgFriendlyname(testData.organizations.overview.friendlyName); diff --git a/cypress/e2e/rbac/developer.cy.ts b/cypress/e2e/rbac/developer.cy.ts index da29806a..a12fc488 100644 --- a/cypress/e2e/rbac/developer.cy.ts +++ b/cypress/e2e/rbac/developer.cy.ts @@ -114,7 +114,7 @@ describe('DEVELOPER permission test suites', () => { environmentOverview.doDeleteEnvironmentError('main'); }); - it('Deletes stating environment', () => { + it('Deletes staging environment', () => { cy.visit(`${Cypress.env('url')}/projects/lagoon-demo/lagoon-demo-staging`); cy.intercept('POST', Cypress.env('api'), req => { @@ -147,7 +147,7 @@ describe('DEVELOPER permission test suites', () => { }); it('Fails to cancel any deployment - no permission to CANCEL for DEVELOPER', () => { - cy.visit(`${Cypress.env('url')}/projects/lagoon-demo/lagoon-demo-staging/deployments`); + cy.visit(`${Cypress.env('url')}/projects/lagoon-demo/lagoon-demo-main/deployments`); registerIdleHandler('idle'); diff --git a/cypress/e2e/rbac/guest.cy.ts b/cypress/e2e/rbac/guest.cy.ts index 6a5679f6..0bed5fe7 100644 --- a/cypress/e2e/rbac/guest.cy.ts +++ b/cypress/e2e/rbac/guest.cy.ts @@ -146,7 +146,7 @@ describe('GUEST permission test suites', () => { }); it('Fails to do cancel a deployment - no permission for GUEST', () => { - cy.visit(`${Cypress.env('url')}/projects/lagoon-demo/lagoon-demo-staging/deployments`); + cy.visit(`${Cypress.env('url')}/projects/lagoon-demo/lagoon-demo-main/deployments`); registerIdleHandler('idle'); cy.intercept('POST', Cypress.env('api'), req => { diff --git a/cypress/e2e/rbac/maintainer.cy.ts b/cypress/e2e/rbac/maintainer.cy.ts index 9809a2b2..e7492e52 100644 --- a/cypress/e2e/rbac/maintainer.cy.ts +++ b/cypress/e2e/rbac/maintainer.cy.ts @@ -136,7 +136,7 @@ describe('MAINTAINER permission test suites', () => { environmentOverview.doDeleteEnvironmentError('main'); }); - it('Deletes stating environment', () => { + it('Deletes staging environment', () => { cy.visit(`${Cypress.env('url')}/projects/lagoon-demo/lagoon-demo-staging`); cy.intercept('POST', Cypress.env('api'), req => { @@ -169,7 +169,7 @@ describe('MAINTAINER permission test suites', () => { }); it('Cancels a staging deployment', () => { - cy.visit(`${Cypress.env('url')}/projects/lagoon-demo/lagoon-demo-staging/deployments`); + cy.visit(`${Cypress.env('url')}/projects/lagoon-demo/lagoon-demo-main/deployments`); registerIdleHandler('idle'); diff --git a/cypress/e2e/rbac/reporter.cy.ts b/cypress/e2e/rbac/reporter.cy.ts index 48c90573..4f916a7b 100644 --- a/cypress/e2e/rbac/reporter.cy.ts +++ b/cypress/e2e/rbac/reporter.cy.ts @@ -143,7 +143,7 @@ describe('REPORTER permission test suites', () => { }); it('Fails to do cancel a deployment - no permission for REPORTER', () => { - cy.visit(`${Cypress.env('url')}/projects/lagoon-demo/lagoon-demo-staging/deployments`); + cy.visit(`${Cypress.env('url')}/projects/lagoon-demo/lagoon-demo-main/deployments`); registerIdleHandler('idle'); @@ -168,6 +168,8 @@ describe('REPORTER permission test suites', () => { cy.waitForNetworkIdle('@idle', 500); deployment.navigateToRunningDeployment(); + + cy.waitForNetworkIdle('@idle', 500); deployment.doFailedCancelDeployment(); }); }); diff --git a/cypress/support/actions/organizations/ProjectsActions.ts b/cypress/support/actions/organizations/ProjectsActions.ts index 98bbc50b..18547b44 100644 --- a/cypress/support/actions/organizations/ProjectsActions.ts +++ b/cypress/support/actions/organizations/ProjectsActions.ts @@ -17,7 +17,7 @@ export default class ProjectsActions { projects.selectTarget(); - projects.getAddConfirm().click(); + projects.getAddConfirm().click({ force: true }); cy.wait('@gqladdProjectToOrganizationMutation'); @@ -32,7 +32,7 @@ export default class ProjectsActions { projects.selectTarget(); - projects.getAddConfirm().click(); + projects.getAddConfirm().click({ force: true }); cy.wait('@gqladdProjectToOrganizationMutation').then(interception => { expect(interception.response?.statusCode).to.eq(200); diff --git a/src/components/Organizations/NewProject/StyledNewProject.tsx b/src/components/Organizations/NewProject/StyledNewProject.tsx index ace03180..a5148fd5 100644 --- a/src/components/Organizations/NewProject/StyledNewProject.tsx +++ b/src/components/Organizations/NewProject/StyledNewProject.tsx @@ -20,6 +20,9 @@ export const StyledNewProject = styled.div` .form-box { margin-bottom: 1rem; + &.spacetop { + margin-top: 1rem; + } } .docs-link { diff --git a/src/components/Organizations/NewProject/index.js b/src/components/Organizations/NewProject/index.js index fd38b7ee..36c2ce42 100644 --- a/src/components/Organizations/NewProject/index.js +++ b/src/components/Organizations/NewProject/index.js @@ -72,6 +72,9 @@ const OrgNewProject = ({ refresh, }) => { const [addUserToProject, setAddUserToProject] = React.useState(true); + const [pullRequests, setPullRequests] = React.useState(''); + const [branches, setBranches] = React.useState(''); + return (
@@ -95,6 +98,8 @@ const OrgNewProject = ({ setProjectName({ target: { value: '' } }); setGitURL({ target: { value: '' } }); setProdEnv({ target: { value: '' } }); + setPullRequests(''); + setBranches(''); setSelectedDeployTarget({ target: { value: '' } }); closeModal(); }); @@ -174,6 +179,74 @@ const OrgNewProject = ({ /> + +
+ +
+ +
+ +
+ Add my user to this project +
@@ -219,7 +293,7 @@ const OrgNewProject = ({ inputGitURL.indexOf(' ') > 0 || inputProdEnv === '' || inputProdEnv.indexOf(' ') > 0 || - selectedDeployTarget === undefined + selectedDeployTarget == undefined } action={() => { addGroupProject({ @@ -230,6 +304,8 @@ const OrgNewProject = ({ productionEnvironment: inputProdEnv, organization: parseInt(organizationId, 10), addOrgOwner: addUserToProject, + ...(pullRequests ? { pullRequests } : {}), + ...(branches ? { branches } : {}), }, }); }} diff --git a/src/layouts/GlobalStyles/index.tsx b/src/layouts/GlobalStyles/index.tsx index 815bc326..401b7a36 100644 --- a/src/layouts/GlobalStyles/index.tsx +++ b/src/layouts/GlobalStyles/index.tsx @@ -41,6 +41,21 @@ body { .ant-tooltip-content .ant-tooltip-inner{ color: ${props => (props.theme.colorScheme === 'dark' ? '#000' : '#fff')}; background: ${props => (props.theme.colorScheme === 'dark' ? '#fff' : '#000')}; + + .tooltiplist{ + margin-left: 0.812rem; + li{ + margin-bottom: initial; + padding-left: 0; + list-style: disc; + } + } + } + &.lg{ + .ant-tooltip-content{ + width:max-content; + } + } } .componentTooltip {