Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-13140-changed-1764317364992.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Changed
---

Logs Delivery UI changes after review ([#13140](https://github.com/linode/manager/pull/13140))
2 changes: 1 addition & 1 deletion packages/manager/src/features/Delivery/DeliveryLanding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export const DeliveryLanding = React.memo(() => {
<>
<ProductInformationBanner bannerLocation="Logs" />
<DocumentTitleSegment segment="Logs" />
<LandingHeader {...landingHeaderProps} spacingBottom={4} />
<LandingHeader {...landingHeaderProps} spacingBottom={24} />

<Tabs index={tabIndex} onChange={handleTabChange}>
<TanStackTabLinkList tabs={tabs} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ export const DestinationTableRow = React.memo(
<TableCell>
<DateTimeDisplay value={destination.updated} />
</TableCell>
<Hidden lgDown>
<TableCell>{destination.updated_by}</TableCell>
</Hidden>
<TableCell actionCell>
<DestinationActionMenu
destination={destination}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useDestinationsQuery } from '@linode/queries';
import { CircleProgress, ErrorState, Hidden } from '@linode/ui';
import { CircleProgress, ErrorState, Hidden, Paper } from '@linode/ui';
import { TableBody, TableHead, TableRow } from '@mui/material';
import Table from '@mui/material/Table';
import { useNavigate, useSearch } from '@tanstack/react-router';
Expand Down Expand Up @@ -119,7 +119,7 @@ export const DestinationsLanding = () => {
};

return (
<>
<Paper>
<DeliveryTabHeader
entity="Destination"
isSearching={isFetching}
Expand Down Expand Up @@ -177,6 +177,16 @@ export const DestinationsLanding = () => {
>
Last Modified
</TableSortCell>
<Hidden lgDown>
<TableSortCell
active={orderBy === 'updated_by'}
direction={order}
handleClick={handleOrderChange}
label="updated_by"
>
Last Modified By
</TableSortCell>
</Hidden>
<TableCell sx={{ width: '5%' }} />
</TableRow>
</TableHead>
Expand All @@ -188,7 +198,7 @@ export const DestinationsLanding = () => {
{...handlers}
/>
))}
{destinations?.results === 0 && <TableRowEmpty colSpan={6} />}
{destinations?.results === 0 && <TableRowEmpty colSpan={7} />}
</TableBody>
</Table>
<PaginationFooter
Expand All @@ -206,6 +216,6 @@ export const DestinationsLanding = () => {
/>
</>
)}
</>
</Paper>
);
};
23 changes: 20 additions & 3 deletions packages/manager/src/features/Delivery/Shared/LabelValue.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { Box, Typography } from '@linode/ui';
import { Box, Tooltip, Typography } from '@linode/ui';
import { styled, useTheme } from '@mui/material/styles';
import useMediaQuery from '@mui/material/useMediaQuery';
import * as React from 'react';

interface LabelValueProps {
children?: React.ReactNode;
compact?: boolean;
'data-testid'?: string;
label: string;
smHideTooltip?: boolean;
value: string;
}

Expand All @@ -17,8 +19,10 @@ export const LabelValue = (props: LabelValueProps) => {
value,
'data-testid': dataTestId,
children,
smHideTooltip,
} = props;
const theme = useTheme();
const matchesSmDown = useMediaQuery(theme.breakpoints.down('sm'));

return (
<Box
Expand All @@ -35,13 +39,18 @@ export const LabelValue = (props: LabelValueProps) => {
>
{label}:
</Typography>
<StyledValue data-testid={dataTestId}>{value}</StyledValue>
<StyledValue
data-testid={dataTestId}
title={!smHideTooltip && matchesSmDown ? value : undefined}
>
<Typography>{value}</Typography>
</StyledValue>
{children}
</Box>
);
};

const StyledValue = styled(Box, {
const StyledValue = styled(Tooltip, {
label: 'StyledValue',
})(({ theme }) => ({
alignItems: 'center',
Expand All @@ -51,4 +60,12 @@ const StyledValue = styled(Box, {
display: 'flex',
height: theme.spacingFunction(24),
padding: theme.spacingFunction(4, 8),
[theme.breakpoints.down('sm')]: {
display: 'block',
maxWidth: '174px',
textOverflow: 'ellipsis',
overflow: 'hidden',
whiteSpace: 'nowrap',
padding: theme.spacingFunction(1, 8),
},
}));
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useRegionsQuery } from '@linode/queries';
import { useIsGeckoEnabled } from '@linode/shared';
import {
Box,
Checkbox,
Expand All @@ -8,6 +10,10 @@ import {
Typography,
} from '@linode/ui';
import { capitalize } from '@linode/utilities';
import Grid from '@mui/material/Grid';
import { styled, type Theme } from '@mui/material/styles';
import useMediaQuery from '@mui/material/useMediaQuery';
import { useFlags } from 'launchdarkly-react-client-sdk';
import { enqueueSnackbar } from 'notistack';
import React, { useEffect, useMemo, useState } from 'react';
import { useWatch } from 'react-hook-form';
Expand All @@ -17,6 +23,7 @@ import { DebouncedSearchTextField } from 'src/components/DebouncedSearchTextFiel
import { sortData } from 'src/components/OrderBy';
import { PaginationFooter } from 'src/components/PaginationFooter/PaginationFooter';
import { MIN_PAGE_SIZE } from 'src/components/PaginationFooter/PaginationFooter.constants';
import { RegionSelect } from 'src/components/RegionSelect/RegionSelect';
import { Table } from 'src/components/Table';
import { StreamFormClusterTableContent } from 'src/features/Delivery/Streams/StreamForm/Clusters/StreamFormClustersTableContent';
import { useAllKubernetesClustersQuery } from 'src/queries/kubernetes';
Expand All @@ -41,11 +48,17 @@ export const StreamFormClusters = (props: StreamFormClustersProps) => {
const { control, setValue, formState, trigger } =
useFormContext<StreamAndDestinationFormType>();

const xsDown = useMediaQuery((theme: Theme) => theme.breakpoints.down('sm'));
const { gecko2 } = useFlags();
const { isGeckoLAEnabled } = useIsGeckoEnabled(gecko2?.enabled, gecko2?.la);
const { data: regions } = useRegionsQuery();

const [order, setOrder] = useState<'asc' | 'desc'>('asc');
const [orderBy, setOrderBy] = useState<OrderByKeys>('label');
const [page, setPage] = useState<number>(1);
const [pageSize, setPageSize] = useState<number>(MIN_PAGE_SIZE);
const [searchText, setSearchText] = useState<string>('');
const [regionFilter, setRegionFilter] = useState<string>('');

const {
data: clusters = [],
Expand Down Expand Up @@ -119,20 +132,30 @@ export const StreamFormClusters = (props: StreamFormClustersProps) => {
}
};

const filteredClusters = !searchText
? clusters
: clusters.filter((cluster) => {
const lowerSearch = searchText.toLowerCase();
const filteredClusters =
!searchText && !regionFilter
? clusters
: clusters.filter((cluster) => {
const lowerSearch = searchText.toLowerCase();

return (
cluster.label.toLowerCase().includes(lowerSearch) ||
cluster.region.toLowerCase().includes(lowerSearch) ||
(cluster.control_plane.audit_logs_enabled
? 'enabled'
: 'disabled'
).includes(lowerSearch)
);
});
let result = true;

if (searchText) {
result =
cluster.label.toLowerCase().includes(lowerSearch) ||
cluster.region.toLowerCase().includes(lowerSearch) ||
(cluster.control_plane.audit_logs_enabled
? 'enabled'
: 'disabled'
).includes(lowerSearch);
}

if (result && regionFilter) {
return cluster.region === regionFilter;
}

return result;
});

const sortedAndFilteredClusters = sortData<KubernetesCluster>(
orderBy,
Expand Down Expand Up @@ -201,24 +224,49 @@ export const StreamFormClusters = (props: StreamFormClustersProps) => {
)}
/>
</div>
<DebouncedSearchTextField
clearable
containerProps={{
sx: {
width: '40%',
mt: 2,
},
}}
debounceTime={250}
hideLabel
inputProps={{
'data-pendo-id': `Logs Delivery Streams ${capitalize(mode)}-Clusters-Search`,
<StyledGrid
sx={{
alignItems: 'center',
display: 'flex',
flexWrap: xsDown ? 'wrap' : 'nowrap',
gap: 3,
justifyContent: 'space-between',
flex: '1 1 auto',
mt: 2,
}}
label="Search"
onSearch={(value) => setSearchText(value)}
placeholder="Search"
value={searchText}
/>
>
<DebouncedSearchTextField
clearable
containerProps={{
sx: {
width: '40%',
},
}}
debounceTime={250}
hideLabel
inputProps={{
'data-pendo-id': `Logs Delivery Streams ${capitalize(mode)}-Clusters-Search`,
}}
label="Search"
onSearch={(value) => setSearchText(value)}
placeholder="Search"
value={searchText}
/>
<RegionSelect
currentCapability="Object Storage"
isGeckoLAEnabled={isGeckoLAEnabled}
label="Region"
onChange={(_, region) => {
setRegionFilter(region?.id ?? '');
}}
regionFilter="core"
regions={regions ?? []}
sx={{
width: '280px !important',
}}
value={regionFilter}
/>
</StyledGrid>
<Box sx={{ mt: 2 }}>
{!isAutoAddAllClustersEnabled &&
formState.errors.stream?.details?.cluster_ids?.message && (
Expand Down Expand Up @@ -258,3 +306,18 @@ export const StreamFormClusters = (props: StreamFormClustersProps) => {
</Paper>
);
};

const StyledGrid = styled(Grid)(({ theme }) => ({
'& .MuiAutocomplete-root > .MuiBox-root': {
display: 'flex',

'& > .MuiBox-root': {
margin: '0',

'& > .MuiInputLabel-root': {
margin: 0,
marginRight: theme.spacingFunction(12),
},
},
},
}));
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ describe('DestinationAkamaiObjectStorageDetailsSummary', () => {
);
});

it('renders info icon next to path when it is empty', async () => {
it('does not render log path when it is empty', async () => {
const details = {
bucket_name: 'test bucket',
host: 'test host',
Expand All @@ -49,6 +49,6 @@ describe('DestinationAkamaiObjectStorageDetailsSummary', () => {
);

// Log Path info icon:
expect(screen.getByTestId('tooltip-info-icon')).toBeVisible();
expect(screen.queryByText('tooltip-info-icon')).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
import { streamType } from '@linode/api-v4';
import { Stack, TooltipIcon, Typography } from '@linode/ui';
import React from 'react';

import { getStreamTypeOption } from 'src/features/Delivery/deliveryUtils';
import { LabelValue } from 'src/features/Delivery/Shared/LabelValue';

import type { AkamaiObjectStorageDetails } from '@linode/api-v4';

const sxTooltipIcon = {
marginLeft: '4px',
padding: '0px',
};

export const DestinationAkamaiObjectStorageDetailsSummary = (
props: AkamaiObjectStorageDetails
) => {
Expand All @@ -24,28 +16,16 @@ export const DestinationAkamaiObjectStorageDetailsSummary = (
<LabelValue
data-testid="access-key-id"
label="Access Key ID"
smHideTooltip={true}
value="*****************"
/>
<LabelValue
data-testid="secret-access-key"
label="Secret Access Key"
smHideTooltip={true}
value="*****************"
/>
<LabelValue label="Log Path" value={path}>
{!path && (
<TooltipIcon
status="info"
sxTooltipIcon={sxTooltipIcon}
text={
<Stack spacing={2}>
<Typography>Default paths:</Typography>
<Typography>{`${getStreamTypeOption(streamType.LKEAuditLogs)?.label} - {stream_type}/{log_type}/ {account}/{partition}/ {%Y/%m/%d/}`}</Typography>
<Typography>{`${getStreamTypeOption(streamType.AuditLogs)?.label} - {stream_type}/{log_type}/ {account}/{%Y/%m/%d/}`}</Typography>
</Stack>
}
/>
)}
</LabelValue>
{!!path && <LabelValue label="Log Path" value={path} />}
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ export const StreamFormGeneralInfo = (props: StreamFormGeneralInfoProps) => {
const capitalizedMode = capitalize(mode);
const description = {
audit_logs:
'Configuration and authentication audit logs that capture state-changing operations (mutations) on Linode cloud infrastructure resources and IAM authentication events. Delivered in cloudevents.io JSON format.',
'Audit logs record state-changing operations on cloud resources and authentication events, delivered in CloudEvents JSON format.',
lke_audit_logs:
'Kubernetes API server audit logs that capture state-changing operations (mutations) on LKE-E cluster resources.',
'Kubernetes API server audit logs capture state-changing operations on LKE-E cluster resources.',
};
const pendoIds = {
audit_logs: `Logs Delivery Streams ${capitalizedMode}-Audit Logs`,
Expand Down Expand Up @@ -136,6 +136,7 @@ export const StreamFormGeneralInfo = (props: StreamFormGeneralInfoProps) => {
sx={{
mt: theme.spacingFunction(16),
maxWidth: 480,
whiteSpace: 'preserve-spaces',
}}
>
{description[selectedStreamType]}
Expand Down
Loading