From 0ae23353c7a4028f788f52f226e4a3bf910da353 Mon Sep 17 00:00:00 2001 From: Neel Khamar Date: Wed, 13 Nov 2024 10:59:23 +0000 Subject: [PATCH] feat: [CDE-456]: Sorting functionality code changes (#2984) * UI Fixes * UI Fixes * Reolved lint warnings * Reolved lint warnings * Reolved lint warnings * Reolved lint warnings * Reolved lint warnings * Resolved PR comments * Sorting functionality code changes * Generic code changes --- .../GitspaceOwnerDropdown.tsx | 8 +- .../SortByDropdown/SortByDropdown.tsx | 44 ++++++++++ .../StatusDropdown/StatusDropdown.tsx | 10 +-- web/src/cde-gitness/constants/index.ts | 28 +++++- web/src/cde-gitness/hooks/useLisitngApi.tsx | 21 +++-- .../pages/GitspaceListing/GitspaceListing.tsx | 86 +++++++++++++++---- .../GitspacesListing.module.scss | 10 +++ .../GitspacesListing.module.scss.d.ts | 2 + web/src/cde-gitness/strings/strings.en.yaml | 7 +- web/src/framework/strings/stringTypes.ts | 5 +- 10 files changed, 183 insertions(+), 38 deletions(-) create mode 100644 web/src/cde-gitness/components/SortByDropdown/SortByDropdown.tsx diff --git a/web/src/cde-gitness/components/GitspaceOwnerDropdown/GitspaceOwnerDropdown.tsx b/web/src/cde-gitness/components/GitspaceOwnerDropdown/GitspaceOwnerDropdown.tsx index a6e0eab2a..48eec5f6a 100644 --- a/web/src/cde-gitness/components/GitspaceOwnerDropdown/GitspaceOwnerDropdown.tsx +++ b/web/src/cde-gitness/components/GitspaceOwnerDropdown/GitspaceOwnerDropdown.tsx @@ -16,7 +16,7 @@ import React from 'react' import { DropDown } from '@harnessio/uicore' -import { GitspaceOwnerType, GitspaceOwnerTypeListItem, GitspaceOwnerTypes } from 'cde-gitness/constants' +import { GitspaceOwnerType, GitspaceOwnerTypes } from 'cde-gitness/constants' import { useStrings } from 'framework/strings' interface GitspaceOwnerDropdownProps { @@ -31,16 +31,12 @@ export default function GitspaceOwnerDropdown(props: GitspaceOwnerDropdownProps) ({ - ...each, - label: each.label - }))} + items={dropdownList} value={value} onChange={option => { onChange(option.value as GitspaceOwnerType) }} placeholder={getString('cde.owners')} - addClearBtn /> ) } diff --git a/web/src/cde-gitness/components/SortByDropdown/SortByDropdown.tsx b/web/src/cde-gitness/components/SortByDropdown/SortByDropdown.tsx new file mode 100644 index 000000000..9503498ad --- /dev/null +++ b/web/src/cde-gitness/components/SortByDropdown/SortByDropdown.tsx @@ -0,0 +1,44 @@ +/* + * Copyright 2024 Harness, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react' +import { DropDown } from '@harnessio/uicore' +import { SortByTypes } from 'cde-gitness/constants' +import { useStrings } from 'framework/strings' +import type { EnumGitspaceSort } from 'services/cde' + +interface SortByDropdownProps { + value?: EnumGitspaceSort + onChange: (val: EnumGitspaceSort) => void +} +export default function SortByDropdown(props: SortByDropdownProps): JSX.Element { + const { value, onChange } = props + const { getString } = useStrings() + const dropdownList = SortByTypes(getString) + return ( + { + onChange(option.value as EnumGitspaceSort) + }} + placeholder={getString('cde.sortBy')} + addClearBtn + /> + ) +} diff --git a/web/src/cde-gitness/components/StatusDropdown/StatusDropdown.tsx b/web/src/cde-gitness/components/StatusDropdown/StatusDropdown.tsx index 250e7ff51..01ad9a881 100644 --- a/web/src/cde-gitness/components/StatusDropdown/StatusDropdown.tsx +++ b/web/src/cde-gitness/components/StatusDropdown/StatusDropdown.tsx @@ -15,20 +15,20 @@ */ import React from 'react' -import { GitspaceStatusTypes, GitspaceStatusTypesListItem } from 'cde-gitness/constants' +import { GitspaceStatus, GitspaceStatusTypes, GitspaceStatusTypesListItem } from 'cde-gitness/constants' import { useStrings } from 'framework/strings' import MultiSelectDropdownList from '../MultiDropdownSelect/MultiDropdownSelect' interface StatusDropdownProps { - value: string[] - onChange: (val: string[]) => void + value: GitspaceStatus[] + onChange: (val: GitspaceStatus[]) => void } export default function StatusDropdown(props: StatusDropdownProps): JSX.Element { const { value, onChange } = props const { getString } = useStrings() - const dropdownList = GitspaceStatusTypes(getString) + const dropdownList: GitspaceStatusTypesListItem[] = GitspaceStatusTypes(getString) return ( - width={120} buttonTestId="gitspace-status-select" items={dropdownList.map((each: GitspaceStatusTypesListItem) => ({ diff --git a/web/src/cde-gitness/constants/index.ts b/web/src/cde-gitness/constants/index.ts index 3a759eddf..1219c1260 100644 --- a/web/src/cde-gitness/constants/index.ts +++ b/web/src/cde-gitness/constants/index.ts @@ -49,7 +49,7 @@ export const GitspaceStatusTypes = (getString: any) => [ value: GitspaceStatus.ERROR }, { - label: getString('cde.gitspaceStatus.running'), + label: getString('cde.gitspaceStatus.active'), value: GitspaceStatus.RUNNING }, { @@ -90,3 +90,29 @@ export enum GitspaceRegion { Europe = 'Europe', Australia = 'Australia' } + +export enum SortByType { + CREATED = 'created', + LAST_USED = 'last_used', + LAST_ACTIVATED = 'last_activated' +} + +export interface SortByTypeListItem { + label: string + value: SortByType +} + +export const SortByTypes = (getString: any) => [ + { + label: getString('cde.created'), + value: SortByType.CREATED + }, + { + label: getString('cde.lastUsed'), + value: SortByType.LAST_USED + }, + { + label: getString('cde.lastActivated'), + value: SortByType.LAST_ACTIVATED + } +] diff --git a/web/src/cde-gitness/hooks/useLisitngApi.tsx b/web/src/cde-gitness/hooks/useLisitngApi.tsx index d3583dff6..82fd51f71 100644 --- a/web/src/cde-gitness/hooks/useLisitngApi.tsx +++ b/web/src/cde-gitness/hooks/useLisitngApi.tsx @@ -20,16 +20,23 @@ import type { TypesGitspaceConfig } from 'cde-gitness/services' import { LIST_FETCHING_LIMIT } from 'utils/Utils' import { useGetCDEAPIParams } from 'cde-gitness/hooks/useGetCDEAPIParams' import { useAppContext } from 'AppContext' -import { useListGitspaces } from 'services/cde' +import { type EnumGitspaceSort, useListGitspaces } from 'services/cde' import { useQueryParams } from 'hooks/useQueryParams' interface pageCDEBrowser { page?: string gitspace_states?: string gitspace_owner?: string + sort?: EnumGitspaceSort + order: 'asc' | 'desc' } -export const useLisitngApi = ({ page, filter }: { page: number; filter: any }) => { +interface sortProps { + sort: EnumGitspaceSort + order: 'asc' | 'desc' +} + +export const useLisitngApi = ({ page, filter, sortConfig }: { page: number; filter: any; sortConfig: sortProps }) => { const { standalone } = useAppContext() const pageBrowser = useQueryParams() @@ -53,7 +60,9 @@ export const useLisitngApi = ({ page, filter }: { page: number; filter: any }) = page, limit: LIST_FETCHING_LIMIT, gitspace_owner: filter.gitspace_owner || undefined, - gitspace_states: filter.gitspace_states.length ? filter.gitspace_states : undefined + gitspace_states: filter.gitspace_states.length ? filter.gitspace_states : undefined, + order: sortConfig.sort ? sortConfig.order : undefined, + sort: sortConfig.sort }, queryParamStringifyOptions: { arrayFormat: 'repeat' @@ -73,7 +82,9 @@ export const useLisitngApi = ({ page, filter }: { page: number; filter: any }) = page, limit: LIST_FETCHING_LIMIT, gitspace_owner: filter.gitspace_owner || undefined, - gitspace_states: filter.gitspace_states.length ? filter.gitspace_states : undefined + gitspace_states: filter?.gitspace_states?.length ? filter.gitspace_states : undefined, + order: sortConfig.sort ? sortConfig.order : undefined, + sort: sortConfig.sort } cde.refetch({ queryParams, @@ -82,7 +93,7 @@ export const useLisitngApi = ({ page, filter }: { page: number; filter: any }) = } }) } - }, [page, filter]) + }, [page, filter, sortConfig]) return standalone ? gitness : cde } diff --git a/web/src/cde-gitness/pages/GitspaceListing/GitspaceListing.tsx b/web/src/cde-gitness/pages/GitspaceListing/GitspaceListing.tsx index 53c11ebbd..cf32b366d 100644 --- a/web/src/cde-gitness/pages/GitspaceListing/GitspaceListing.tsx +++ b/web/src/cde-gitness/pages/GitspaceListing/GitspaceListing.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import React, { useState } from 'react' +import React, { useMemo, useState } from 'react' import { Button, Page, @@ -42,8 +42,10 @@ import UsageMetrics from 'cde-gitness/components/UsageMetrics/UsageMetrics' import StatusDropdown from 'cde-gitness/components/StatusDropdown/StatusDropdown' import GitspaceOwnerDropdown from 'cde-gitness/components/GitspaceOwnerDropdown/GitspaceOwnerDropdown' -import { GitspaceOwnerType } from 'cde-gitness/constants' +import { GitspaceOwnerType, GitspaceStatus } from 'cde-gitness/constants' +import SortByDropdown from 'cde-gitness/components/SortByDropdown/SortByDropdown' +import type { EnumGitspaceSort } from 'services/cde' import { useLisitngApi } from '../../hooks/useLisitngApi' import zeroDayCss from 'cde-gitness/components/CDEHomePage/CDEHomePage.module.scss' import css from './GitspacesListing.module.scss' @@ -51,44 +53,77 @@ import css from './GitspacesListing.module.scss' interface pageCDEBrowser { page?: string gitspace_states?: string - gitspace_owner?: string + gitspace_owner?: GitspaceOwnerType + sort?: EnumGitspaceSort + order?: 'asc' | 'desc' +} + +interface filterProps { + gitspace_states: GitspaceStatus[] + gitspace_owner: GitspaceOwnerType +} + +interface sortProps { + sort: EnumGitspaceSort + order: 'asc' | 'desc' } const GitspaceListing = () => { const space = useGetSpaceParam() - const { replaceQueryParams } = useUpdateQueryParams() + const { updateQueryParams } = useUpdateQueryParams() + const history = useHistory() const { getString } = useStrings() const { routes, standalone } = useAppContext() const pageBrowser = useQueryParams() - const filterInit = { - gitspace_states: pageBrowser.gitspace_states?.split(',') ?? [], + const statesString: any = pageBrowser.gitspace_states + const filterInit: filterProps = { + gitspace_states: statesString?.split(',')?.map((state: string) => state.trim() as GitspaceStatus) ?? [], gitspace_owner: pageBrowser.gitspace_owner ?? GitspaceOwnerType.SELF } const pageInit = pageBrowser.page ? parseInt(pageBrowser.page) : 1 const [page, setPage] = usePageIndex(pageInit) const [filter, setFilter] = useState(filterInit) + + const sortInit: sortProps = { sort: (pageBrowser.sort as EnumGitspaceSort) ?? '', order: 'desc' } + const [sortConfig, setSortConfig] = useState(sortInit) const [hasFilter, setHasFilter] = useState(!!(pageBrowser.gitspace_states || pageBrowser.gitspace_owner)) - const { data = '', loading = false, error = undefined, refetch, response } = useLisitngApi({ page, filter }) + const { + data = '', + loading = false, + error = undefined, + refetch, + response + } = useLisitngApi({ page, filter, sortConfig }) + + function useParsePaginationInfo(responseData: Nullable) { + const totalData = useMemo(() => parseInt(responseData?.headers?.get('x-total') || '0'), [responseData]) + + return totalData + } + const totalItems = useParsePaginationInfo(response) const handleFilterChange = (key: string, value: any) => { const payload: any = { ...filter } payload[key] = value setFilter(payload) - const queryParams: any = {} - Object.keys(payload).forEach((entity: string) => { - const val = payload[entity] - if (val && typeof val === 'string') { - queryParams[entity] = val - } else if (Array.isArray(val) && val?.length) { - queryParams[entity] = val?.toString() - } - }) - if (queryParams.gitspace_states?.length) { + if (typeof value === 'string') { + updateQueryParams({ [key]: value }) + } else if (Array.isArray(value)) { + updateQueryParams({ [key]: value?.toString() }) + } + if (payload.gitspace_states?.length || payload.gitspace_owner) { setHasFilter(true) } - replaceQueryParams(queryParams) + } + + const handleSort = (key: string, value: string) => { + updateQueryParams({ [key]: value }) + setSortConfig({ + ...sortConfig, + [key]: value + }) } return ( @@ -134,6 +169,18 @@ const GitspaceListing = () => { onChange={(val: any) => handleFilterChange('gitspace_owner', val)} /> + + + handleSort('sort', val)} /> +