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
This commit is contained in:
Neel Khamar 2024-11-13 10:59:23 +00:00 committed by Harness
parent e077918d6f
commit 0ae23353c7
10 changed files with 183 additions and 38 deletions

View File

@ -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)
<DropDown
width={180}
buttonTestId="gitspace-owner-select"
items={dropdownList.map((each: GitspaceOwnerTypeListItem) => ({
...each,
label: each.label
}))}
items={dropdownList}
value={value}
onChange={option => {
onChange(option.value as GitspaceOwnerType)
}}
placeholder={getString('cde.owners')}
addClearBtn
/>
)
}

View File

@ -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 (
<DropDown
width={180}
buttonTestId="gitspace-sort-select"
items={dropdownList}
value={value}
onChange={option => {
onChange(option.value as EnumGitspaceSort)
}}
placeholder={getString('cde.sortBy')}
addClearBtn
/>
)
}

View File

@ -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 (
<MultiSelectDropdownList
<MultiSelectDropdownList<GitspaceStatus>
width={120}
buttonTestId="gitspace-status-select"
items={dropdownList.map((each: GitspaceStatusTypesListItem) => ({

View File

@ -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
}
]

View File

@ -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<pageCDEBrowser>()
@ -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
}

View File

@ -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<pageCDEBrowser>()
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<Response>) {
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)}
/>
</Layout.Horizontal>
<Layout.Horizontal spacing="small" flex={{ alignItems: 'center', justifyContent: 'flex-start' }}>
<SortByDropdown value={sortConfig?.sort} onChange={(val: any) => handleSort('sort', val)} />
<Button
icon={sortConfig.order === 'asc' ? 'sort-asc' : 'sort-desc'}
className={css.sortOrder}
minimal
withoutBoxShadow
onClick={() => handleSort('order', sortConfig.order === 'asc' ? 'desc' : 'asc')}
disabled={!sortConfig.sort}
/>
</Layout.Horizontal>
</Page.SubHeader>
)}
</>
@ -164,6 +211,9 @@ const GitspaceListing = () => {
}}>
{(data?.length || hasFilter) && (
<>
<Text className={css.totalItems}>
{getString('cde.total')}: {totalItems}
</Text>
<ListGitspaces data={(data as Unknown) || []} hasFilter={hasFilter} refreshList={refetch} />
<ResourceListingPagination response={response} page={page} setPage={setPage} />
</>

View File

@ -17,3 +17,13 @@
.main {
margin: var(--spacing-xxlarge) !important;
}
.sortOrder {
border: 1px solid silver !important;
}
.totalItems {
font-size: var(--font-size-normal) !important;
font-weight: bold !important;
color: black !important;
}

View File

@ -17,3 +17,5 @@
/* eslint-disable */
// This is an auto-generated file
export declare const main: string
export declare const sortOrder: string
export declare const totalItems: string

View File

@ -32,6 +32,7 @@ eventTimeline: Event Timeline
cpu: CPU
memory: Memory
disk: Disk
created: Created
regionSelectWarning: Select a region first
gitspaceUpdateSuccess: Gitspace updated successfully
regionValidationMessage: Region is required
@ -141,10 +142,12 @@ changesTooltip:
description: A gitspace is meant to be used just like a user might use an IDE locally in their laptop. To check if a gitspace has any changes which a user might want to save/sync with the remote repo before deleting it, the user needs to start the gitspace and check.
learnMore: Learn more about Gitspace changes
gitspaceStatus:
running: Running
active: Active
stopped: Stopped
error: Error
owners: Owners
gitspaceOwners:
allGitspaces: All Gitspaces
myGitspaces: Only My Gitspaces
myGitspaces: My Gitspaces
sortBy: Sort By
total: Total

View File

@ -1230,6 +1230,7 @@ export interface StringsMap {
'cde.createGitspace': string
'cde.createImport': string
'cde.createRepo': string
'cde.created': string
'cde.deleteGitspace': string
'cde.deleteGitspaceText': string
'cde.deleteGitspaceTitle': string
@ -1261,8 +1262,8 @@ export interface StringsMap {
'cde.gitspaceDetail': string
'cde.gitspaceOwners.allGitspaces': string
'cde.gitspaceOwners.myGitspaces': string
'cde.gitspaceStatus.active': string
'cde.gitspaceStatus.error': string
'cde.gitspaceStatus.running': string
'cde.gitspaceStatus.stopped': string
'cde.gitspaceUpdateSuccess': string
'cde.gitspaces': string
@ -1330,6 +1331,7 @@ export interface StringsMap {
'cde.repositoryAndBranch': string
'cde.retry': string
'cde.sessionDuration': string
'cde.sortBy': string
'cde.sshSelect.180days': string
'cde.sshSelect.30days': string
'cde.sshSelect.90days': string
@ -1339,6 +1341,7 @@ export interface StringsMap {
'cde.startingGitspace': string
'cde.status': string
'cde.stopingGitspace': string
'cde.total': string
'cde.updateGitspace': string
'cde.used': string
'cde.viewGitspace': string