Skip to content

Commit

Permalink
feat(web): deployments list pagination & filtering (#1021)
Browse files Browse the repository at this point in the history
  • Loading branch information
robot9706 authored Jan 7, 2025
1 parent 50c0759 commit b8e4652
Show file tree
Hide file tree
Showing 20 changed files with 159 additions and 182 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ test.describe('Deployment Copy', () => {
await copyButton.click()

const newPrefix = 'dcpy-second'
await page.locator(`button:has-text("${DAGENT_NODE}")`).click()
await page.locator(`button:has-text("${DAGENT_NODE}")`).first().click()
await fillDeploymentPrefix(page, newPrefix)

const currentUrl = page.url()
Expand Down
5 changes: 5 additions & 0 deletions web/crux-ui/e2e/with-login/nodes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,13 @@ test('Stopping the underlying container of a log stream should not affect the co
TEAM_ROUTES.node.containerLog(nodeId, {
name: containerName,
}),
{
waitUntil: 'domcontentloaded',
},
)

await page.waitForSelector(`h4:text-is("Log of ${containerName}")`)

await stopContainer(containerName)

// check status
Expand Down
2 changes: 1 addition & 1 deletion web/crux-ui/e2e/with-login/resource-copy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ test.describe("Deleting copied deployment's parent", () => {
const copyButton = page.locator('button:has-text("Copy")')
await copyButton.click()

await page.locator(`button:has-text("${DAGENT_NODE}")`).click()
await page.locator(`button:has-text("${DAGENT_NODE}")`).first().click()
await fillDeploymentPrefix(page, `${prefix}-other`)

const currentUrl = page.url()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
containerPrefixNameOf,
ContainersStateListMessage,
DeploymentRoot,
nameOfInstance,
containerNameOfInstance,
WatchContainerStatusMessage,
WS_TYPE_CONTAINERS_STATE_LIST,
WS_TYPE_WATCH_CONTAINERS_STATE,
Expand Down Expand Up @@ -50,7 +50,7 @@ const DeploymentContainerStatusList = (props: DeploymentContainerStatusListProps
configId: it.config.id,
id: {
prefix: deployment.prefix,
name: nameOfInstance(it),
name: containerNameOfInstance(it),
},
createdAt: null,
state: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import DyoIcon from '@app/elements/dyo-icon'
import DyoLink from '@app/elements/dyo-link'
import DyoTable, { DyoColumn, dyoCheckboxColumn, sortDate, sortString } from '@app/elements/dyo-table'
import useTeamRoutes from '@app/hooks/use-team-routes'
import { Instance, nameOfInstance } from '@app/models'
import { Instance, containerNameOfInstance } from '@app/models'
import { utcDateToLocale } from '@app/utils'
import useTranslation from 'next-translate/useTranslation'
import { DeploymentActions, DeploymentState } from './use-deployment-state'
Expand Down Expand Up @@ -34,9 +34,9 @@ const DeploymentViewList = (props: DeploymentViewListProps) => {
header={t('containerName')}
className="w-4/12"
sortable
sortField={nameOfInstance}
sortField={containerNameOfInstance}
sort={sortString}
body={nameOfInstance}
body={containerNameOfInstance}
/>
<DyoColumn
header={t('common:registry')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ import { useRouter } from 'next/router'
import { QA_MODAL_LABEL_DEPLOYMENT_NOTE } from 'quality-assurance'
import { useState } from 'react'

interface NodeDeploymentListProps {
type NodeDeploymentListProps = {
deployments: Deployment[]
}

type DeploymentFilter = TextFilter & EnumFilter<DeploymentStatus>

const NodeDeploymentList = (props: NodeDeploymentListProps) => {
const FilteredDeploymentList = (props: NodeDeploymentListProps) => {
const { deployments: propsDeployments } = props

const { t } = useTranslation('deployments')
Expand Down Expand Up @@ -78,6 +78,7 @@ const NodeDeploymentList = (props: NodeDeploymentListProps) => {
sortField="project.name"
sort={sortString}
/>

<DyoColumn
header={t('common:version')}
body={(it: Deployment) => it.version.name}
Expand All @@ -86,6 +87,7 @@ const NodeDeploymentList = (props: NodeDeploymentListProps) => {
sortField="version.name"
sort={sortString}
/>

<DyoColumn
header={t('common:prefix')}
field="prefix"
Expand All @@ -94,6 +96,7 @@ const NodeDeploymentList = (props: NodeDeploymentListProps) => {
sortField="prefix"
sort={sortString}
/>

<DyoColumn
header={t('common:updatedAt')}
body={(it: Deployment) => auditToLocaleDate(it.audit)}
Expand All @@ -103,6 +106,7 @@ const NodeDeploymentList = (props: NodeDeploymentListProps) => {
sortField={it => it.audit.updatedAt ?? it.audit.createdAt}
sort={sortDate}
/>

<DyoColumn
header={t('common:status')}
body={(it: Deployment) => <DeploymentStatusTag status={it.status} className="w-fit mx-auto" />}
Expand All @@ -111,6 +115,7 @@ const NodeDeploymentList = (props: NodeDeploymentListProps) => {
sortField="status"
sort={sortEnum(DEPLOYMENT_STATUS_VALUES)}
/>

<DyoColumn
header={t('common:actions')}
className="w-40 text-center"
Expand Down Expand Up @@ -158,4 +163,4 @@ const NodeDeploymentList = (props: NodeDeploymentListProps) => {
)
}

export default NodeDeploymentList
export default FilteredDeploymentList
2 changes: 1 addition & 1 deletion web/crux-ui/src/components/nodes/select-node-chips.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const SelectNodeChips = (props: SelectNodeChipsProps) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [nodes])

const baseChoices = allowNull === true ? [null] : []
const baseChoices = allowNull ? [null] : []
const choices = [...baseChoices, ...(nodes ?? [])]

return fetchError ? (
Expand Down
3 changes: 2 additions & 1 deletion web/crux-ui/src/models/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export type Instance = {
config: ConcreteContainerConfig
}

export const nameOfInstance = (instance: Instance) => instance.config.name ?? containerNameOfImage(instance.image)
export const containerNameOfInstance = (instance: Instance) =>
instance.config.name ?? containerNameOfImage(instance.image)
107 changes: 15 additions & 92 deletions web/crux-ui/src/pages/[teamSlug]/config-bundles/[configBundleId].tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,29 @@
import ConfigBundleCard from '@app/components/config-bundles/config-bundle-card'
import EditConfigBundleCard from '@app/components/config-bundles/edit-config-bundle-card'
import DeploymentStatusTag from '@app/components/deployments/deployment-status-tag'
import FilteredDeploymentList from '@app/components/deployments/filtered-deployment-list'
import { Layout } from '@app/components/layout'
import { BreadcrumbLink } from '@app/components/shared/breadcrumb'
import PageHeading from '@app/components/shared/page-heading'
import { DetailsPageMenu } from '@app/components/shared/page-menu'
import { PaginationSettings } from '@app/components/shared/paginator'
import { DyoCard } from '@app/elements/dyo-card'
import DyoIcon from '@app/elements/dyo-icon'
import DyoLink from '@app/elements/dyo-link'
import DyoTable, { DyoColumn, sortDate, sortEnum, sortString } from '@app/elements/dyo-table'
import { defaultApiErrorHandler } from '@app/errors'
import usePagination from '@app/hooks/use-pagination'
import useSubmit from '@app/hooks/use-submit'
import useTeamRoutes from '@app/hooks/use-team-routes'
import {
ConfigBundleDetails,
Deployment,
DEPLOYMENT_STATUS_VALUES,
DeploymentQuery,
detailsToConfigBundle,
PaginatedList,
PaginationQuery,
} from '@app/models'
import { ConfigBundleDetails, Deployment, detailsToConfigBundle } from '@app/models'
import { TeamRoutes } from '@app/routes'
import { auditToLocaleDate, withContextAuthorization } from '@app/utils'
import { withContextAuthorization } from '@app/utils'
import { getCruxFromContext } from '@server/crux-api'
import { GetServerSidePropsContext } from 'next'
import useTranslation from 'next-translate/useTranslation'
import { useRouter } from 'next/router'
import { useCallback, useState } from 'react'

const defaultPagination: PaginationSettings = { pageNumber: 0, pageSize: 10 }
import { useState } from 'react'

type ConfigBundleDetailsPageProps = {
configBundle: ConfigBundleDetails
deployments: Deployment[]
}

const ConfigBundleDetailsPage = (props: ConfigBundleDetailsPageProps) => {
const { configBundle: propsConfigBundle } = props
const { configBundle: propsConfigBundle, deployments } = props

const { t } = useTranslation('config-bundles')
const router = useRouter()
Expand All @@ -51,30 +36,6 @@ const ConfigBundleDetailsPage = (props: ConfigBundleDetailsPageProps) => {

const submit = useSubmit()

const fetchData = useCallback(
async (paginationQuery: PaginationQuery): Promise<PaginatedList<Deployment>> => {
const query: DeploymentQuery = {
...paginationQuery,
configBundleId: propsConfigBundle.id,
}

const res = await fetch(routes.deployment.api.list(query))

if (!res.ok) {
await onApiError(res)
return null
}

return (await res.json()) as PaginatedList<Deployment>
},
[routes, onApiError],
)

const [pagination, setPagination] = usePagination({
defaultSettings: defaultPagination,
fetchData,
})

const onDelete = async () => {
const res = await fetch(routes.configBundle.api.details(configBundle.id), {
method: 'DELETE',
Expand Down Expand Up @@ -114,58 +75,14 @@ const ConfigBundleDetailsPage = (props: ConfigBundleDetailsPageProps) => {
})}
/>
</PageHeading>

{editing ? (
<EditConfigBundleCard submit={submit} configBundle={configBundle} onConfigBundleEdited={setConfigBundle} />
) : (
<ConfigBundleCard configBundle={detailsToConfigBundle(configBundle)} />
)}
<DyoCard className="relative mt-4">
<DyoTable
data={pagination.data ?? []}
dataKey="id"
pagination="server"
paginationTotal={pagination.total}
onServerPagination={setPagination}
initialSortColumn={4}
initialSortDirection="desc"
>
<DyoColumn header={t('common:project')} field="project.name" className="w-2/12" sortable sort={sortString} />
<DyoColumn header={t('common:version')} field="version.name" className="w-2/12" sortable sort={sortString} />
<DyoColumn header={t('common:node')} field="node.name" className="w-2/12" sortable sort={sortString} />
<DyoColumn header={t('common:prefix')} field="prefix" className="w-2/12" sortable sort={sortString} />
<DyoColumn
header={t('common:updatedAt')}
className="w-2/12"
suppressHydrationWarning
sortable
sortField={(it: Deployment) => it.audit.updatedAt ?? it.audit.createdAt}
sort={sortDate}
body={(it: Deployment) => auditToLocaleDate(it.audit)}
/>
<DyoColumn
header={t('common:status')}
className="w-2/12 text-center"
sortable
sortField="status"
sort={sortEnum(DEPLOYMENT_STATUS_VALUES)}
body={(it: Deployment) => <DeploymentStatusTag status={it.status} className="w-fit mx-auto" />}
/>
<DyoColumn
header={t('common:actions')}
className="w-40 text-center"
preventClickThrough
body={(it: Deployment) => (
<DyoLink
className="inline-block mr-2"
href={routes.deployment.details(it.id)}
qaLabel="deployment-list-view-icon"
>
<DyoIcon src="/eye.svg" alt={t('common:view')} size="md" />
</DyoLink>
)}
/>
</DyoTable>
</DyoCard>

{deployments.length > 0 && <FilteredDeploymentList deployments={deployments} />}
</Layout>
)
}
Expand All @@ -182,9 +99,15 @@ const getPageServerSideProps = async (context: GetServerSidePropsContext) => {
routes.configBundle.api.details(configBundleId),
)

const deployments = await getCruxFromContext<Deployment[]>(
context,
routes.configBundle.api.deployments(configBundleId),
)

return {
props: {
configBundle,
deployments,
},
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,13 +337,12 @@ const ContainerConfigPage = (props: ContainerConfigPageProps) => {
patch.current = newPatch

throttle(() => {
const conf = patch.current
patch.current = {}

sock.send(WS_TYPE_PATCH_CONFIG, {
id: resettableConfig.id,
config: conf,
config: patch.current,
} as PatchConfigMessage)

patch.current = {}
})
}

Expand Down
6 changes: 3 additions & 3 deletions web/crux-ui/src/pages/[teamSlug]/nodes/[nodeId].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import EditNodeSection from '@app/components/nodes/edit-node-section'
import NodeAuditList from '@app/components/nodes/node-audit-list'
import NodeConnectionCard from '@app/components/nodes/node-connection-card'
import NodeContainersList from '@app/components/nodes/node-containers-list'
import NodeDeploymentList from '@app/components/nodes/node-deployment-list'
import FilteredDeploymentList from '@app/components/deployments/filtered-deployment-list'
import NodeSectionsHeading from '@app/components/nodes/node-sections-heading'
import useNodeDetailsState from '@app/components/nodes/use-node-details-state'
import { BreadcrumbLink } from '@app/components/shared/breadcrumb'
Expand All @@ -24,7 +24,7 @@ import useTranslation from 'next-translate/useTranslation'
import { useRouter } from 'next/dist/client/router'
import { useSWRConfig } from 'swr'

interface NodeDetailsPageProps {
type NodeDetailsPageProps = {
node: NodeDetails
deployments: Deployment[]
}
Expand Down Expand Up @@ -123,7 +123,7 @@ const NodeDetailsPage = (props: NodeDetailsPageProps) => {
) : state.section === 'logs' ? (
<NodeAuditList node={node} />
) : (
<NodeDeploymentList deployments={deployments} />
<FilteredDeploymentList deployments={deployments} />
)}
</>
)}
Expand Down
2 changes: 2 additions & 0 deletions web/crux-ui/src/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,8 @@ class ConfigBundleApi {
list = () => this.root

details = (id: string) => `${this.root}/${id}`

deployments = (id: string) => `${this.details(id)}/deployments`
}

class ConfigBundleRoutes {
Expand Down
Loading

0 comments on commit b8e4652

Please sign in to comment.