Skip to content

Commit

Permalink
feat(ui): adding truncate and line clamp option (#279)
Browse files Browse the repository at this point in the history
Co-authored-by: Tristan Holaday <40547442+TristanHoladay@users.noreply.github.com>
  • Loading branch information
BillyFigueroa and TristanHoladay authored Sep 16, 2024
1 parent 81bead7 commit de760fb
Show file tree
Hide file tree
Showing 10 changed files with 129 additions and 26 deletions.
6 changes: 6 additions & 0 deletions ui/src/app.postcss
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,12 @@
td.emphasize {
@apply text-gray-900 dark:text-white;
}

td.truncate {
overflow: hidden;
text-overflow: ellipsis;
max-width: 0;
}
}
}
}
Expand Down
84 changes: 84 additions & 0 deletions ui/src/lib/components/Tooltip/component.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<script lang="ts">
export let title = ''
let isHovered = false
let xOffset: number
let yOffset: number
let isWider: boolean = false
type MouseEventType = MouseEvent & {
currentTarget: EventTarget & HTMLDivElement
}
const mouseOver = (event: MouseEventType) => {
const createElWidth = getElementWidth('div', event.currentTarget.children[0].textContent)
// This offset is the padding for the table > tr > td element in app.postcss. The class of px-4 is 1em or 16px
if (createElWidth - event.currentTarget.offsetLeft * 2 > event.currentTarget.clientWidth) {
isWider = true
} else {
isWider = false
}
isHovered = true
xOffset = event.pageX
yOffset = event.pageY
}
const mouseMove = (event: MouseEventType) => {
// calculate if the columns is a certain percent off right side and render on the left side
const diff = ((window.innerWidth - event.pageX) / window.innerWidth) * 100
const tooltipOffset = diff < 15 ? 500 : 200
xOffset = event.pageX - tooltipOffset
yOffset = event.pageY - 110
}
const mouseLeave = () => (isHovered = false)
const getElementWidth = (type: string, textContent: string | null): number => {
if (textContent) {
const newEl = document.createElement(type)
const newContent = document.createTextNode(textContent)
// add the text node to the newly created div
newEl.appendChild(newContent)
newEl.setAttribute('id', 'test-el')
// Inline block so it does not take full width of screen
newEl.style.display = 'inline-block'
// Ensure the element is not visible
newEl.style.position = 'fixed'
newEl.style.zIndex = '0'
// add the newly created element and its content into the DOM
const bodyEl = document.querySelector('body')!
bodyEl.appendChild(newEl)
const createdEL = document.getElementById('test-el')
const createElWidth = createdEL?.clientWidth
bodyEl.removeChild(newEl)
return createElWidth || 0
}
return 0
}
</script>

<div
id="container"
role="button"
tabindex={0}
on:mouseover={mouseOver}
on:mouseleave={mouseLeave}
on:mousemove={mouseMove}
on:focus
>
<slot />
</div>

{#if isHovered && isWider}
<div
class="absolute bg-gray-900 text-white opacity-90 text-xs focus:border-gray-200 focus:outline-none focus:ring-0 dark:border-gray-700 p-4 rounded-[4px]"
style="top: {yOffset}px; left: {xOffset}px; padding: 10px"
>
{title}
</div>
{/if}
1 change: 1 addition & 0 deletions ui/src/lib/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export { default as AnsiDisplay } from './AnsiDisplay/component.svelte'
export { default as DataTable } from './k8s/DataTable/component.svelte'
export { default as Drawer } from './k8s/Drawer/component.svelte'
export { default as Link } from './Link/component.svelte'
export { default as Tooltip } from './Tooltip/component.svelte'
10 changes: 8 additions & 2 deletions ui/src/lib/components/k8s/DataTable/component.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import { goto } from '$app/navigation'
import { page } from '$app/stores'
import { Drawer, Link } from '$components'
import { Drawer, Link, Tooltip } from '$components'
import type { Row as NamespaceRow } from '$features/k8s/namespaces/store'
import { type ResourceStoreInterface } from '$features/k8s/types'
import { addToast } from '$features/toast'
Expand Down Expand Up @@ -259,7 +259,7 @@
{#if value.component}
<svelte:component this={value.component} {...value.props} />
{:else if value.list}
<ul class="mt-4 text-sm">
<ul class="line-clamp-4 mt-4 text-sm">
{#each value.list as item}
<li data-testid={`${item}-list-item-test-id`}>- {item}</li>
{/each}
Expand All @@ -275,6 +275,12 @@
>
{value}
</button>
{:else if style?.includes('truncate')}
<Tooltip title={value}>
<div class={`w-full ${style}`}>
{value}
</div>
</Tooltip>
{:else}
{value.text || (value === 0 ? '0' : value) || '-'}
{/if}
Expand Down
18 changes: 9 additions & 9 deletions ui/src/lib/features/k8s/workloads/pods/component.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
import { resourceDescriptions } from '$lib/utils/descriptions'
export let columns: Columns = [
['name', 'emphasize'],
['namespace'],
['controlled_by'],
['containers'],
['status'],
['restarts'],
['metrics'],
['node'],
['age'],
['name', 'emphasize w-3/12 truncate'],
['namespace', 'w-2/12'],
['controlled_by', 'w-1/12'],
['containers', '1/12'],
['status', 'w-1/12'],
['restarts', 'w-1/12'],
['metrics', 'w-1/12'],
['node', 'w-1/12 truncate'],
['age', 'w-1/12'],
]
const name = 'Pods'
const description = resourceDescriptions[name]
Expand Down
18 changes: 9 additions & 9 deletions ui/src/lib/features/k8s/workloads/pods/component.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ suite('PodTable Component', () => {
testK8sTableWithDefaults(Component, {
createStore,
columns: [
['name', 'emphasize'],
['namespace'],
['controlled_by'],
['containers'],
['status'],
['restarts'],
['metrics'],
['node'],
['age'],
['name', 'emphasize w-3/12 truncate'],
['namespace', 'w-2/12'],
['controlled_by', 'w-1/12'],
['containers', '1/12'],
['status', 'w-1/12'],
['restarts', 'w-1/12'],
['metrics', 'w-1/12'],
['node', 'w-1/12 truncate'],
['age', 'w-1/12'],
],
name,
description,
Expand Down
2 changes: 1 addition & 1 deletion ui/tests/api-auth.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ test.describe.serial('Authentication Tests', () => {
await page.goto(`/auth?token=${extractedToken}`)
await page.getByRole('button', { name: 'Workloads' }).click()
await page.getByRole('link', { name: 'Pods' }).click()
const element = page.locator(`.emphasize:has-text("podinfo")`)
const element = page.locator(`.emphasize:has-text("podinfo")`).first()
await expect(element).toBeVisible()

// Check details view
Expand Down
7 changes: 6 additions & 1 deletion ui/tests/navigation.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import { expect, test } from '@playwright/test'

test.describe('Navigation', async () => {
test.beforeEach(async ({ page }) => {
await page.setViewportSize({
width: 3024,
height: 1964,
})

await page.goto('/')
})

Expand Down Expand Up @@ -44,7 +49,7 @@ test.describe('Navigation', async () => {
await page.getByRole('button', { name: 'Workloads' }).click()
await page.getByRole('link', { name: 'Pods' }).click()

const element = page.locator(`.emphasize:has-text("podinfo")`)
const element = page.locator(`.emphasize:has-text("podinfo")`).first()
await expect(element).toBeVisible()
})

Expand Down
7 changes: 4 additions & 3 deletions ui/tests/sse.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ async function deletePod(namespace: string, podName: string, force: boolean = tr
test.describe('SSE and reactivity', async () => {
test('Pods are updated', async ({ page }) => {
await page.goto('/workloads/pods')
const originalPodName = await page.getByRole('cell', { name: 'podinfo-' }).first().textContent()
let originalPodName = await page.getByRole('cell', { name: 'podinfo-' }).first().textContent()
originalPodName = originalPodName ? originalPodName.trim() : ''

// get pod name
expect(originalPodName).not.toBeNull()

// delete pod and wait for it to disappear
await deletePod('podinfo', originalPodName ?? '')
await expect(page.getByRole('cell', { name: originalPodName ?? '' })).toBeHidden()
await deletePod('podinfo', originalPodName)
await expect(page.getByRole('cell', { name: originalPodName })).toBeHidden()

// get new pod
const newPodName = await page.getByRole('cell', { name: 'podinfo' }).first().textContent()
Expand Down
2 changes: 1 addition & 1 deletion ui/tests/table.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ test.describe('DataTable', async () => {
})

test('filters rows when we click the namespace link in a row', async ({ page }) => {
await page.getByRole('button', { name: 'podinfo' }).click()
await page.getByRole('button', { name: 'podinfo' }).last().click()

expect(await page.getByTestId('table-header-results').textContent()).toBe('(showing 1 of 8)')

Expand Down

0 comments on commit de760fb

Please sign in to comment.