fix(apps) UI release fixes [EE-5197] (#8702)

* fix(apps) searchbar flex resizing and insights

* UI fixes

* update stacks datatable

---------

Co-authored-by: testa113 <testa113>
pull/8716/head
Ali 2023-03-23 08:20:30 +13:00 committed by GitHub
parent 3636ac5c26
commit 30248eabb4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 277 additions and 217 deletions

View File

@ -14,6 +14,7 @@ import { DockerfileDetails } from '@/react/docker/images/ItemView/DockerfileDeta
import { HealthStatus } from '@/react/docker/containers/ItemView/HealthStatus'; import { HealthStatus } from '@/react/docker/containers/ItemView/HealthStatus';
import { GpusList } from '@/react/docker/host/SetupView/GpusList'; import { GpusList } from '@/react/docker/host/SetupView/GpusList';
import { GpusInsights } from '@/react/docker/host/SetupView/GpusInsights'; import { GpusInsights } from '@/react/docker/host/SetupView/GpusInsights';
import { InsightsBox } from '@/react/components/InsightsBox';
export const componentsModule = angular export const componentsModule = angular
.module('portainer.docker.react.components', []) .module('portainer.docker.react.components', [])
@ -53,4 +54,15 @@ export const componentsModule = angular
'gpusList', 'gpusList',
r2a(withControlledInput(GpusList), ['value', 'onChange']) r2a(withControlledInput(GpusList), ['value', 'onChange'])
) )
.component(
'insightsBox',
r2a(InsightsBox, [
'header',
'content',
'setHtmlContent',
'insightCloseId',
'type',
'className',
])
)
.component('gpusInsights', r2a(GpusInsights, [])).name; .component('gpusInsights', r2a(GpusInsights, [])).name;

View File

@ -1,132 +1,144 @@
<div class="datatable"> <div class="datatable">
<!-- toolbar header actions and settings --> <!-- toolbar header actions and settings -->
<div ng-if="$ctrl.isPrimary" class="toolBar !flex-col gap-1"> <div ng-if="$ctrl.isPrimary" class="toolBar !flex-col !gap-0">
<div class="toolBar vertical-center w-full flex-wrap !gap-x-5 !gap-y-1 !p-0"> <div class="toolBar w-full !items-start !gap-x-5 !p-0">
<div class="toolBarTitle vertical-center"> <div class="toolBarTitle vertical-center">
<div class="widget-icon space-right"> <div class="widget-icon space-right">
<pr-icon icon="'box'"></pr-icon> <pr-icon icon="'box'"></pr-icon>
</div> </div>
Applications Applications
</div> </div>
<div class="form-group namespaces !mb-0 !mr-0 min-w-[280px]"> <!-- use row reverse to make the left most items wrap first to the right side in the next line -->
<div class="input-group"> <div class="inline-flex flex-row-reverse flex-wrap !gap-x-5 gap-y-3">
<span class="input-group-addon"> <div class="settings" data-cy="k8sApp-tableSettings">
<pr-icon icon="'filter'"></pr-icon> <span class="setting" ng-class="{ 'setting-active': $ctrl.settings.open }" uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.settings.open">
Namespace <span uib-dropdown-toggle aria-label="Settings">
</span> <pr-icon icon="'more-vertical'" class-name="'!mr-0 !h-4'"></pr-icon>
<select </span>
class="form-control" <div class="dropdown-menu dropdown-menu-right" uib-dropdown-menu>
ng-model="$ctrl.state.namespace" <div class="tableMenu">
ng-change="$ctrl.onChangeNamespace()" <div class="menuHeader"> Table settings </div>
data-cy="component-namespaceSelect" <div class="menuContent">
ng-options="o.Value as (o.Name + (o.IsSystem ? ' - system' : '')) for o in $ctrl.state.namespaces" <div>
> <div class="md-checkbox" ng-if="$ctrl.isAdmin">
</select> <input id="applications_setting_show_system" type="checkbox" ng-model="$ctrl.settings.showSystem" ng-change="$ctrl.onSettingsShowSystemChange()" />
</div> <label for="applications_setting_show_system">Show system resources</label>
</div> </div>
<div class="searchBar vertical-center !mr-0 min-w-[280px]"> <div class="md-checkbox">
<pr-icon icon="'search'" class-name="'searchIcon'"></pr-icon> <input
<input id="setting_auto_refresh"
type="text" type="checkbox"
class="searchInput" ng-model="$ctrl.settings.repeater.autoRefresh"
ng-model="$ctrl.state.textFilter" ng-change="$ctrl.onSettingsRepeaterChange()"
ng-change="$ctrl.onTextFilterChange()" data-cy="k8sApp-autoRefreshCheckbox"
placeholder="Search for an application..." />
auto-focus <label for="setting_auto_refresh">Auto refresh</label>
ng-model-options="{ debounce: 300 }" </div>
data-cy="k8sApp-searchApplicationsInput" <div ng-if="$ctrl.settings.repeater.autoRefresh">
/> <label for="settings_refresh_rate"> Refresh rate </label>
</div> <select
<div class="actionBar !mr-0 !gap-3"> id="settings_refresh_rate"
<button ng-model="$ctrl.settings.repeater.refreshRate"
ng-if="$ctrl.isPrimary" ng-change="$ctrl.onSettingsRepeaterChange()"
type="button" class="small-select"
class="btn btn-sm btn-dangerlight vertical-center !ml-0 h-fit" data-cy="k8sApp-refreshRateDropdown"
ng-disabled="$ctrl.state.selectedItemCount === 0" >
ng-click="$ctrl.removeAction($ctrl.state.selectedItems)" <option value="10">10s</option>
data-cy="k8sApp-removeAppButton" <option value="30">30s</option>
> <option value="60">1min</option>
<pr-icon icon="'trash-2'"></pr-icon> <option value="120">2min</option>
Remove <option value="300">5min</option>
</button> </select>
<button <span>
ng-if="$ctrl.isPrimary" <pr-icon id="refreshRateChange" icon="'check'" mode="'success'" style="display: none"></pr-icon>
type="button" </span>
class="btn btn-sm btn-secondary vertical-center !ml-0 h-fit" </div>
ui-sref="kubernetes.applications.new"
data-cy="k8sApp-addApplicationButton"
>
<pr-icon icon="'plus'" class-name="'!h-3'"></pr-icon>Add with form
</button>
<button
ng-if="$ctrl.isPrimary"
type="button"
class="btn btn-sm btn-primary vertical-center !ml-0 h-fit"
ui-sref="kubernetes.deploy"
data-cy="k8sApp-deployFromManifestButton"
>
<pr-icon icon="'plus'" class-name="'!h-3'"></pr-icon>Create from manifest
</button>
</div>
<div class="settings" data-cy="k8sApp-tableSettings">
<span class="setting" ng-class="{ 'setting-active': $ctrl.settings.open }" uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.settings.open">
<span uib-dropdown-toggle aria-label="Settings">
<pr-icon icon="'more-vertical'" class-name="'!mr-0 !h-4'"></pr-icon>
</span>
<div class="dropdown-menu dropdown-menu-right" uib-dropdown-menu>
<div class="tableMenu">
<div class="menuHeader"> Table settings </div>
<div class="menuContent">
<div>
<div class="md-checkbox" ng-if="$ctrl.isAdmin">
<input id="applications_setting_show_system" type="checkbox" ng-model="$ctrl.settings.showSystem" ng-change="$ctrl.onSettingsShowSystemChange()" />
<label for="applications_setting_show_system">Show system resources</label>
</div>
<div class="md-checkbox">
<input
id="setting_auto_refresh"
type="checkbox"
ng-model="$ctrl.settings.repeater.autoRefresh"
ng-change="$ctrl.onSettingsRepeaterChange()"
data-cy="k8sApp-autoRefreshCheckbox"
/>
<label for="setting_auto_refresh">Auto refresh</label>
</div>
<div ng-if="$ctrl.settings.repeater.autoRefresh">
<label for="settings_refresh_rate"> Refresh rate </label>
<select
id="settings_refresh_rate"
ng-model="$ctrl.settings.repeater.refreshRate"
ng-change="$ctrl.onSettingsRepeaterChange()"
class="small-select"
data-cy="k8sApp-refreshRateDropdown"
>
<option value="10">10s</option>
<option value="30">30s</option>
<option value="60">1min</option>
<option value="120">2min</option>
<option value="300">5min</option>
</select>
<span>
<pr-icon id="refreshRateChange" icon="'check'" mode="'success'" style="display: none"></pr-icon>
</span>
</div> </div>
</div> </div>
</div> <div>
<div> <a type="button" class="btn btn-sm btn-default btn-sm" ng-click="$ctrl.settings.open = false;" data-cy="k8sApp-tableSettingsCloseButton">Close</a>
<a type="button" class="btn btn-sm btn-default btn-sm" ng-click="$ctrl.settings.open = false;" data-cy="k8sApp-tableSettingsCloseButton">Close</a> </div>
</div> </div>
</div> </div>
</span>
</div>
<div class="actionBar !mr-0 !gap-3">
<button
ng-if="$ctrl.isPrimary"
type="button"
class="btn btn-sm btn-dangerlight vertical-center !ml-0 h-fit"
ng-disabled="$ctrl.state.selectedItemCount === 0"
ng-click="$ctrl.removeAction($ctrl.state.selectedItems)"
data-cy="k8sApp-removeAppButton"
>
<pr-icon icon="'trash-2'"></pr-icon>
Remove
</button>
<button
ng-if="$ctrl.isPrimary"
hide-deployment-option="form"
type="button"
class="btn btn-sm btn-secondary vertical-center !ml-0 h-fit"
ui-sref="kubernetes.applications.new"
data-cy="k8sApp-addApplicationButton"
>
<pr-icon icon="'plus'" class-name="'!h-3'"></pr-icon>Add with form
</button>
<button
ng-if="$ctrl.isPrimary"
type="button"
class="btn btn-sm btn-primary vertical-center !ml-0 h-fit"
ui-sref="kubernetes.deploy"
data-cy="k8sApp-deployFromManifestButton"
>
<pr-icon icon="'plus'" class-name="'!h-3'"></pr-icon>Create from manifest
</button>
</div>
<div class="searchBar">
<pr-icon icon="'search'" class-name="'searchIcon'"></pr-icon>
<input
type="text"
class="searchInput"
ng-model="$ctrl.state.textFilter"
ng-change="$ctrl.onTextFilterChange()"
placeholder="Search..."
auto-focus
ng-model-options="{ debounce: 300 }"
data-cy="k8sApp-searchApplicationsInput"
/>
</div>
<div class="form-group namespaces !mb-0 !mr-0 !h-[30px] min-w-[140px]">
<div class="input-group">
<span class="input-group-addon">
<pr-icon icon="'filter'" size="'sm'"></pr-icon>
Namespace
</span>
<select
class="form-control !h-[30px] !py-1"
ng-model="$ctrl.state.namespace"
ng-change="$ctrl.onChangeNamespace()"
data-cy="component-namespaceSelect"
ng-options="o.Value as (o.Name + (o.IsSystem ? ' - system' : '')) for o in $ctrl.state.namespaces"
>
</select>
</div> </div>
</span> </div>
</div> </div>
</div> </div>
<div class="flex w-full flex-row" ng-if="$ctrl.isAdmin && !$ctrl.settings.showSystem"> <div class="flex w-full flex-row" ng-if="$ctrl.isAdmin && !$ctrl.settings.showSystem">
<span class="small text-muted vertical-center mt-1"> <span class="small text-muted vertical-center mt-1">
<pr-icon icon="'info'" mode="'primary'" class="vertical-center"></pr-icon> <pr-icon icon="'info'" mode="'primary'"></pr-icon>
System resources are hidden, this can be changed in the table settings. System resources are hidden, this can be changed in the table settings.
</span> </span>
</div> </div>
<div class="w-full">
<div class="w-fit">
<insights-box class-name="'mt-2'" type="'slim'" header="'From 2.18 on, you can filter this view by namespace.'" insight-close-id="'k8s-namespace-filtering'"></insights-box>
</div>
</div>
</div> </div>
<!-- data table content --> <!-- data table content -->
<div ng-class="{ 'table-responsive': $ctrl.isPrimary, 'inner-datatable': !$ctrl.isPrimary }"> <div ng-class="{ 'table-responsive': $ctrl.isPrimary, 'inner-datatable': !$ctrl.isPrimary }">

View File

@ -1,115 +1,122 @@
<div class="datatable"> <div class="datatable">
<!-- table title and action menu --> <!-- table title and action menu -->
<div class="toolBar !flex-col gap-1"> <div class="toolBar !flex-col !gap-0">
<div class="toolBar vertical-center w-full flex-wrap !gap-x-5 !gap-y-1 !p-0"> <div class="toolBar w-full !items-start !gap-x-5 !p-0">
<!-- title -->
<div class="toolBarTitle vertical-center"> <div class="toolBarTitle vertical-center">
<div class="widget-icon space-right"> <div class="widget-icon space-right">
<pr-icon icon="'list'"></pr-icon> <pr-icon icon="'list'"></pr-icon>
</div> </div>
Stacks Stacks
</div> </div>
<!-- actions --> <!-- use row reverse to make the left most items wrap first to the right side in the next line -->
<div class="form-group namespaces !mb-0 !mr-0 min-w-[280px]"> <div class="inline-flex flex-row-reverse flex-wrap !gap-x-5 gap-y-3">
<div class="input-group"> <div class="actionBar !mr-0 !gap-3">
<span class="input-group-addon"> <button
<pr-icon icon="'filter'"></pr-icon> type="button"
Namespace class="btn btn-sm btn-dangerlight vertical-center !ml-0 h-fit"
</span> ng-disabled="$ctrl.state.selectedItemCount === 0"
<select ng-click="$ctrl.removeAction($ctrl.state.selectedItems)"
class="form-control" data-cy="k8sApp-removeStackButton"
ng-model="$ctrl.state.namespace"
ng-change="$ctrl.onChangeNamespace()"
data-cy="component-namespaceSelect"
ng-options="o.Value as (o.Name + (o.IsSystem ? ' - system' : '')) for o in $ctrl.state.namespaces"
> >
</select> <pr-icon icon="'trash-2'"></pr-icon>
</div> Remove
</div> </button>
<div class="searchBar vertical-center"> <div class="settings" data-cy="k8sApp-StackTableSettings">
<pr-icon icon="'search'" class-name="'!h-3'"></pr-icon> <span class="setting" ng-class="{ 'setting-active': $ctrl.settings.open }" uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.settings.open">
<input <span uib-dropdown-toggle>
type="text" <pr-icon icon="'more-vertical'" class-name="'!mr-0 !h-4'"></pr-icon>
class="searchInput min-w-min self-start" </span>
ng-model="$ctrl.state.textFilter" <div class="dropdown-menu dropdown-menu-right" uib-dropdown-menu>
ng-change="$ctrl.onTextFilterChange()" <div class="tableMenu">
placeholder="Search for a stack..." <div class="menuHeader"> Table settings </div>
auto-focus <div class="menuContent">
ng-model-options="{ debounce: 300 }" <div>
/> <div class="md-checkbox" ng-if="$ctrl.isAdmin">
</div> <input id="applications_setting_show_system" type="checkbox" ng-model="$ctrl.settings.showSystem" ng-change="$ctrl.onSettingsShowSystemChange()" />
<div class="actionBar !mr-0 !gap-3"> <label for="applications_setting_show_system">Show system resources</label>
<button </div>
type="button" <div class="md-checkbox">
class="btn btn-sm btn-dangerlight vertical-center !ml-0 h-fit" <input
ng-disabled="$ctrl.state.selectedItemCount === 0" id="setting_auto_refresh"
ng-click="$ctrl.removeAction($ctrl.state.selectedItems)" type="checkbox"
data-cy="k8sApp-removeStackButton" ng-model="$ctrl.settings.repeater.autoRefresh"
> ng-change="$ctrl.onSettingsRepeaterChange()"
<pr-icon icon="'trash-2'"></pr-icon> data-cy="k8sApp-autoRefreshCheckbox-stack"
Remove />
</button> <label for="setting_auto_refresh">Auto refresh</label>
<div class="settings" data-cy="k8sApp-StackTableSettings"> </div>
<span class="setting" ng-class="{ 'setting-active': $ctrl.settings.open }" uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.settings.open"> <div ng-if="$ctrl.settings.repeater.autoRefresh">
<span uib-dropdown-toggle> <label for="settings_refresh_rate"> Refresh rate </label>
<pr-icon icon="'more-vertical'" class-name="'!mr-0 !h-4'"></pr-icon> <select
</span> id="settings_refresh_rate"
<div class="dropdown-menu dropdown-menu-right" uib-dropdown-menu> ng-model="$ctrl.settings.repeater.refreshRate"
<div class="tableMenu"> ng-change="$ctrl.onSettingsRepeaterChange()"
<div class="menuHeader"> Table settings </div> class="small-select"
<div class="menuContent"> data-cy="k8sApp-refreshRateDropdown-stack"
<div> >
<div class="md-checkbox" ng-if="$ctrl.isAdmin"> <option value="10">10s</option>
<input id="applications_setting_show_system" type="checkbox" ng-model="$ctrl.settings.showSystem" ng-change="$ctrl.onSettingsShowSystemChange()" /> <option value="30">30s</option>
<label for="applications_setting_show_system">Show system resources</label> <option value="60">1min</option>
</div> <option value="120">2min</option>
<div class="md-checkbox"> <option value="300">5min</option>
<input </select>
id="setting_auto_refresh" <span>
type="checkbox" <pr-icon id="refreshRateChange" icon="'check'" mode="'success'" style="display: none"></pr-icon>
ng-model="$ctrl.settings.repeater.autoRefresh" </span>
ng-change="$ctrl.onSettingsRepeaterChange()" </div>
data-cy="k8sApp-autoRefreshCheckbox-stack"
/>
<label for="setting_auto_refresh">Auto refresh</label>
</div>
<div ng-if="$ctrl.settings.repeater.autoRefresh">
<label for="settings_refresh_rate"> Refresh rate </label>
<select
id="settings_refresh_rate"
ng-model="$ctrl.settings.repeater.refreshRate"
ng-change="$ctrl.onSettingsRepeaterChange()"
class="small-select"
data-cy="k8sApp-refreshRateDropdown-stack"
>
<option value="10">10s</option>
<option value="30">30s</option>
<option value="60">1min</option>
<option value="120">2min</option>
<option value="300">5min</option>
</select>
<span>
<pr-icon id="refreshRateChange" icon="'check'" mode="'success'" style="display: none"></pr-icon>
</span>
</div> </div>
</div> </div>
</div> <div>
<div> <a type="button" class="btn btn-sm btn-default btn-sm" ng-click="$ctrl.settings.open = false;" data-cy="k8sApp-tableSettingsCloseButton-stack">Close</a>
<a type="button" class="btn btn-sm btn-default btn-sm" ng-click="$ctrl.settings.open = false;" data-cy="k8sApp-tableSettingsCloseButton-stack">Close</a> </div>
</div> </div>
</div> </div>
</div> </span>
</span> </div>
</div>
<div class="searchBar vertical-center">
<pr-icon icon="'search'" class-name="'!h-3'"></pr-icon>
<input
type="text"
class="searchInput min-w-min self-start"
ng-model="$ctrl.state.textFilter"
ng-change="$ctrl.onTextFilterChange()"
placeholder="Search..."
auto-focus
ng-model-options="{ debounce: 300 }"
/>
</div>
<div class="form-group namespaces !mb-0 !mr-0 !h-[30px] w-fit min-w-[140px]">
<div class="input-group">
<span class="input-group-addon">
<pr-icon icon="'filter'" size="'sm'"></pr-icon>
Namespace
</span>
<select
class="form-control !h-[30px] !py-1"
ng-model="$ctrl.state.namespace"
ng-change="$ctrl.onChangeNamespace()"
data-cy="component-namespaceSelect"
ng-options="o.Value as (o.Name + (o.IsSystem ? ' - system' : '')) for o in $ctrl.state.namespaces"
>
</select>
</div>
</div> </div>
</div> </div>
</div> </div>
<!-- info text --> <!-- info text -->
<div class="flex w-full flex-row"> <div class="flex w-full flex-row" ng-if="$ctrl.isAdmin && !$ctrl.settings.showSystem">
<span class="small text-muted vertical-center mt-1" ng-if="$ctrl.isAdmin && !$ctrl.settings.showSystem"> <span class="small text-muted vertical-center mt-1">
<pr-icon icon="'info'" mode="'primary'"></pr-icon> <pr-icon icon="'info'" mode="'primary'"></pr-icon>
System resources are hidden, this can be changed in the table settings. System resources are hidden, this can be changed in the table settings.
</span> </span>
</div> </div>
<div class="w-full">
<div class="w-fit">
<insights-box class-name="'mt-2'" type="'slim'" header="'From 2.18 on, you can filter this view by namespace.'" insight-close-id="'k8s-namespace-filtering'"></insights-box>
</div>
</div>
</div> </div>
<div class="table-responsive"> <div class="table-responsive">
<table class="table-hover nowrap-cells table"> <table class="table-hover nowrap-cells table">

View File

@ -66,7 +66,12 @@
.toolBar .searchBar { .toolBar .searchBar {
margin-right: 10px; margin-right: 10px;
display: inline-flex; display: inline-flex;
min-height: 30px; flex-basis: 7rem;
flex-grow: 1;
flex-shrink: 1;
align-items: center;
min-width: 7rem;
max-width: 14rem;
} }
.datatable .searchBar input[type='text'] { .datatable .searchBar input[type='text'] {

View File

@ -8,13 +8,21 @@ import { Button } from '@@/buttons';
import { insightStore } from './insights-store'; import { insightStore } from './insights-store';
export type Props = { export type Props = {
header: string; header?: string;
content: ReactNode; content?: ReactNode;
setHtmlContent?: boolean; setHtmlContent?: boolean;
insightCloseId?: string; // set if you want to be able to close the box and not show it again insightCloseId?: string; // set if you want to be able to close the box and not show it again
type?: 'default' | 'slim';
className?: string;
}; };
export function InsightsBox({ header, content, insightCloseId }: Props) { export function InsightsBox({
header,
content,
insightCloseId,
type = 'default',
className,
}: Props) {
// allow to close the box and not show it again in local storage with zustand // allow to close the box and not show it again in local storage with zustand
const { addInsightIDClosed, isClosed } = useStore(insightStore); const { addInsightIDClosed, isClosed } = useStore(insightStore);
const isInsightClosed = isClosed(insightCloseId); const isInsightClosed = isClosed(insightCloseId);
@ -24,26 +32,42 @@ export function InsightsBox({ header, content, insightCloseId }: Props) {
} }
return ( return (
<div className="relative flex w-full gap-1 rounded-lg bg-gray-modern-3 p-4 text-sm th-highcontrast:bg-legacy-grey-3 th-dark:bg-legacy-grey-3"> <div
<div className="shrink-0"> className={clsx(
'relative flex w-full gap-1 rounded-lg bg-gray-modern-3 p-4 text-sm th-highcontrast:bg-legacy-grey-3 th-dark:bg-legacy-grey-3',
type === 'slim' && 'p-2',
className
)}
>
<div className="mt-0.5 shrink-0">
<Lightbulb className="h-4 text-warning-7 th-highcontrast:text-warning-6 th-dark:text-warning-6" /> <Lightbulb className="h-4 text-warning-7 th-highcontrast:text-warning-6 th-dark:text-warning-6" />
</div> </div>
<div> <div>
<p {header && (
className={clsx( <p
// text-[0.9em] matches .form-horizontal .control-label font-size used in many labels in portainer className={clsx(
'mb-2 text-[0.9em] font-medium', // text-[0.9em] matches .form-horizontal .control-label font-size used in many labels in portainer
insightCloseId && 'pr-4' 'align-middle text-[0.9em] font-medium',
)} insightCloseId && 'pr-10',
> content ? 'mb-2' : 'mb-0'
{header} )}
</p> >
<div className="small">{content}</div> {header}
</p>
)}
{content && (
<div className={clsx('small', !header && insightCloseId && 'pr-6')}>
{content}
</div>
)}
</div> </div>
{insightCloseId && ( {insightCloseId && (
<Button <Button
icon={X} icon={X}
className="absolute top-2 right-2 flex !text-gray-7 hover:!text-gray-8 th-highcontrast:!text-gray-6 th-highcontrast:hover:!text-gray-5 th-dark:!text-gray-6 th-dark:hover:!text-gray-5" className={clsx(
'absolute top-3 right-2 flex !text-gray-7 hover:!text-gray-8 th-highcontrast:!text-gray-6 th-highcontrast:hover:!text-gray-5 th-dark:!text-gray-6 th-dark:hover:!text-gray-5',
type === 'slim' && insightCloseId && 'top-1'
)}
color="link" color="link"
size="medium" size="medium"
onClick={() => addInsightIDClosed(insightCloseId)} onClick={() => addInsightIDClosed(insightCloseId)}