Skip to content

Commit

Permalink
chore: list update
Browse files Browse the repository at this point in the history
  • Loading branch information
shivani170 committed Feb 7, 2025
1 parent 7b8a5ee commit bf62d2e
Show file tree
Hide file tree
Showing 10 changed files with 376 additions and 322 deletions.
1 change: 0 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,6 @@ src/components/external-apps/ExternalApps.tsx
src/components/externalArgoApps/ExternalArgoApp.tsx
src/components/externalArgoApps/ExternalArgoAppDetail.tsx
src/components/externalLinks/ExternalLinks.component.tsx
src/components/externalLinks/ExternalLinks.service.ts
src/components/externalLinks/ExternalLinksCRUD/AddExternalLink.tsx
src/components/externalLinks/ExternalLinksCRUD/ConfigureLinkAction.tsx
src/components/externalLinks/ExternalLinksCRUD/DeleteExternalLinkDialog.tsx
Expand Down
32 changes: 32 additions & 0 deletions src/components/common/helpers/InteractiveCellText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Tooltip } from '@devtron-labs/devtron-fe-common-lib'

interface InteractiveCellTextProps {
text: string
linkRedirectsTo?: () => void
dataTestId?: string
}

export const InteractiveCellText = ({ text, linkRedirectsTo, dataTestId }: InteractiveCellTextProps) => (
<Tooltip
content={text}
placement="bottom"
showOnTruncate={!!text}
className="mxh-210 dc__overflow-auto"
interactive
>
{typeof linkRedirectsTo === 'function' ? (
<button
type="button"
onClick={linkRedirectsTo}
className="flex left dc__unset-button-styles lh-20 dc__ellipsis-right fs-13 cb-5 dc__no-decor cursor"
data-testid={dataTestId}
>
{text || '-'}
</button>
) : (
<p className="lh-20 dc__ellipsis-right m-0 fs-13" data-testid={dataTestId}>
{text || '-'}
</p>
)}
</Tooltip>
)
51 changes: 51 additions & 0 deletions src/components/externalLinks/ExternalLinkFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { FilterSelectPicker } from '@devtron-labs/devtron-fe-common-lib'
import { useEffect } from 'react'
import {
ExternalLinkFiltersProps,
ExternalLinkFilters,
IdentifierOptionType,
ExternalLinkIdentifierType,
} from './ExternalLinks.type'

const createAppFilterKey = (value: string) => {
const appValue = value.split('|')
return `${appValue[0]}_${appValue[2] === ExternalLinkIdentifierType.DevtronApp ? 'd' : 'h'}`
}

export const ExternalLinkFilter = ({
allApps,
updateSearchParams,
appliedApps,
setAppliedApps,
queryParams,
}: ExternalLinkFiltersProps) => {
// To update the dropdown selections on query param value change or page reload
useEffect(() => {
if (allApps.length > 0 && queryParams.has('apps')) {
const _appliedAppIds = queryParams.get('apps').split(',')
const _appliedApps = allApps.filter((app) => _appliedAppIds.includes(createAppFilterKey(app.value)))

setAppliedApps(_appliedApps)
}
}, [allApps, queryParams.get('apps')])

const handleUpdateFilters = (filterKey: ExternalLinkFilters) => (selectedOptions: IdentifierOptionType[]) => {
console.log(selectedOptions, 'selectedOptions')

Check warning on line 33 in src/components/externalLinks/ExternalLinkFilter.tsx

View workflow job for this annotation

GitHub Actions / ci

Unexpected console statement
setAppliedApps(selectedOptions)
updateSearchParams({ [filterKey]: selectedOptions.map((option) => String(option.value)) })
}

return (
<div className="filters-wrapper ml-8">
<FilterSelectPicker
placeholder="Application"
inputId="app-list-app-status-select"
options={allApps}
appliedFilterOptions={appliedApps}
isDisabled={false}
isLoading={false}
handleApplyFilter={handleUpdateFilters(ExternalLinkFilters.APPS)}
/>
</div>
)
}
168 changes: 102 additions & 66 deletions src/components/externalLinks/ExternalLinkList.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { Trash } from '@Components/common'
import { Button, ButtonVariantType, ButtonStyleType, ComponentSizeType } from '@devtron-labs/devtron-fe-common-lib'
import Tippy from '@tippyjs/react'
import {
Button,
ButtonVariantType,
ButtonStyleType,
ComponentSizeType,
GenericFilterEmptyState,
} from '@devtron-labs/devtron-fe-common-lib'
import { Fragment } from 'react'
import { ReactComponent as Edit } from '@Icons/ic-pencil.svg'
import { InteractiveCellText } from '@Components/common/helpers/InteractiveCellText'
import { useLocation } from 'react-router-dom'
import { getMonitoringToolIcon, getScopeLabel, onImageLoadError } from './ExternalLinks.utils'
import { ExternalLink, ExternalLinkListProps } from './ExternalLinks.type'

Expand All @@ -14,7 +21,11 @@ export const ExternalLinkList = ({
setShowDeleteDialog,
setShowAddLinkDialog,
monitoringTools,
appliedClusters,
}: ExternalLinkListProps) => {
const location = useLocation()
const queryParams = new URLSearchParams(location.search)

const onClickEditLink = (link: ExternalLink): void => {
setSelectedLink(link)
setShowAddLinkDialog(true)
Expand All @@ -25,88 +36,113 @@ export const ExternalLinkList = ({
setShowDeleteDialog(true)
}

return (
<div className="external-links__list dc__overflow-auto">
const renderExternalLinksHeader = (): JSX.Element => (
<div
className={`external-link-list__row dc__align-items-center h-40 fs-12 fw-6 dc__uppercase px-20 py-6 dc__gap-16 dc__border-bottom dc__position-sticky dc__top-0 cn-7 ${
isAppConfigView ? 'app-config-view' : ''
}`}
>
<span className="icon-dim-24" />
<span className="lh-20">Name</span>
<span className="lh-20">Description</span>
{!isAppConfigView && <span className="lh-20">Scope</span>}
<span className="lh-20">Url Template</span>
</div>
)

const renderActionButton = (link: ExternalLink) => (
<div className="flex dc__visible-hover--child">
<div className="flex dc__gap-4">
<Button
icon={<Edit />}
variant={ButtonVariantType.borderLess}
style={ButtonStyleType.neutral}
size={ComponentSizeType.xs}
ariaLabel="Edit"
data-link={link}
dataTestId={`external-link-edit-button-${link.name}`}
onClick={() => onClickEditLink(link)}
/>
<Button
icon={<Trash />}
variant={ButtonVariantType.borderLess}
style={ButtonStyleType.negativeGrey}
size={ComponentSizeType.xs}
ariaLabel="Delete"
dataTestId={`external-link-delete-button-${link.name}`}
onClick={() => onClickDeleteLink(link)}
/>
</div>
</div>
)

const renderExternalListContent = () => (
<div className="dc__overflow-auto">
{filteredExternalLinks.map((link, idx) => (
<Fragment key={`external-link-${link.name}`}>
<div
className={`dc__visible-hover dc__visible-hover--parent external-link dc__hover-n50 ${isAppConfigView ? 'app-config-view' : ''}`}
className={`external-link-list__row dc__align-items-center dc__gap-16 dc__visible-hover dc__visible-hover--parent dc__hover-n50 cn-9 fs-13 px-20 py-10 ${isAppConfigView ? 'app-config-view' : ''}`}
>
<div className="external-links__cell--icon">
<div className="p-2 flex">
<img
src={getMonitoringToolIcon(monitoringTools, link.monitoringToolId)}
className="icon-dim-24"
className="flex icon-dim-20 dc__no-shrink"
onError={onImageLoadError}
alt="external-link-icon"
/>
</div>
<div
className="external-links__cell--tool__name cn-9 fs-13 dc__ellipsis-right"
data-testid={`external-link-name-${link.name}`}
>
{link.name}
</div>
<div className="external-links__cell--tool__name cn-9 fs-13 dc__ellipsis-right">
{link.description ? (
<Tippy
className="default-tt dc__mxw-300 dc__word-break"
arrow={false}
placement="top-start"
content={link.description}
>
<span data-testid={`external-link-description-${link.name}`}>
{link.description}
</span>
</Tippy>
) : (
'-'
)}
</div>
<InteractiveCellText text={link.name} data-testid={`external-link-name-${link.name}`} />
<InteractiveCellText
text={link.description}
data-testid={`external-link-description-${link.name}`}
/>

{!isAppConfigView && (
<div
className="external-links__cell--scope cn-9 fs-13 dc__ellipsis-right"
data-testid={`external-link-scope-${link.name}`}
>
<div className=" dc__ellipsis-right" data-testid={`external-link-scope-${link.name}`}>
{getScopeLabel(link)}
</div>
)}
<div className="external-links__cell--url__template cn-9 fs-13 dc__ellipsis-right">
<Tippy
className="default-tt dc__mxw-300 dc__word-break"
arrow={false}
placement="top-start"
content={link.url}
>
<span data-testid={`external-link-url-${link.name}`}>{link.url}</span>
</Tippy>
</div>
<div className="flex dc__visible-hover--child">
<div className="flex dc__gap-4">
<Button
icon={<Edit />}
variant={ButtonVariantType.borderLess}
style={ButtonStyleType.neutral}
size={ComponentSizeType.xs}
ariaLabel="Edit"
data-link={link}
dataTestId={`external-link-edit-button-${link.name}`}
onClick={() => onClickEditLink(link)}
/>
<Button
icon={<Trash />}
variant={ButtonVariantType.borderLess}
style={ButtonStyleType.negativeGrey}
size={ComponentSizeType.xs}
ariaLabel="Delete"
dataTestId={`external-link-delete-button-${link.name}`}
onClick={() => onClickDeleteLink(link)}
/>
</div>
</div>
<InteractiveCellText text={link.url} data-testid={`external-link-url-${link.name}`} />
{renderActionButton(link)}
</div>
{idx !== filteredLinksLen - 1 && <div className="external-link__divider w-100 bcn-1" />}
</Fragment>
))}
</div>
)

const renderClearFilterButton = () => (
<div className="dc__align-center dc__gap-16 dc__mt-24">
<Button
size={ComponentSizeType.medium}
variant={ButtonVariantType.primary}
style={ButtonStyleType.default}
onClick={() => {
queryParams.delete('searchKey')
queryParams.delete('clusterId')
queryParams.delete('monitoringToolId')
window.history.replaceState({}, '', `${location.pathname}?${queryParams}`)
}}
dataTestId="clear-filter-button"
text="Clear Filters"
/>
</div>
)

if ((appliedClusters.length > 0 || queryParams.get('searchKey')) && filteredLinksLen === 0) {
return (
<GenericFilterEmptyState
classname="dc__align-reload-center"
isButtonAvailable
renderButton={renderClearFilterButton}
/>
)
}

return (
<div className={`external-links bg__primary ${isAppConfigView ? 'app-config-view__listing' : ''}`}>
{renderExternalLinksHeader()}
{renderExternalListContent()}
</div>
)
}
4 changes: 3 additions & 1 deletion src/components/externalLinks/ExternalLinks.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,19 +101,21 @@ export const NoExternalLinksView = ({

export const RoleBasedInfoNote = ({ userRole, listingView }: RoleBasedInfoNoteProps) => {
return (
<div className="flexbox-col px-20">
<InfoColourBar
message={
userRole === UserRoleType.SuperAdmin
? 'Only links editable by application admins are shown here. To check all configured links,'
: 'Only links editable by application admins are shown here. All configured links are available to super admins in'
}
classname={`info_bar fs-12 pl-12 pr-12 ${listingView ? 'mt-12 mb-12' : 'dc__mxw-300 m-20'}`}
classname={`info_bar fs-12 px-12 ${listingView ? '' : 'dc__mxw-300 m-20'}`}
Icon={InfoIcon}
iconClass="h-20"
linkText={userRole === UserRoleType.SuperAdmin ? 'Go to Global configurations' : 'Global Configurations.'}
internalLink
redirectLink={URLS.GLOBAL_CONFIG_EXTERNAL_LINKS}
/>
</div>
)
}

Expand Down
6 changes: 3 additions & 3 deletions src/components/externalLinks/ExternalLinks.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ const getURLWithQueryParams = (clusterId?: number, identifier?: string, type?: E
type: type?.toString(),
}

for (const param in queryParams) {
if (!queryParams[param]) {
Object.entries(queryParams).forEach(([param, value]) => {
if (!value) {
delete queryParams[param]
}
}
})

_url += `?${new URLSearchParams(queryParams).toString()}`
}
Expand Down
Loading

0 comments on commit bf62d2e

Please sign in to comment.