Skip to content

Commit d6a5e28

Browse files
first batch of UI updates
1 parent 72d3f0a commit d6a5e28

File tree

7 files changed

+82
-49
lines changed

7 files changed

+82
-49
lines changed

Diff for: packages/api-v4/src/quotas/types.ts

+17-26
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
1-
import { ObjectStorageEndpointTypes } from 'src/object-storage';
2-
import { Region } from 'src/regions';
3-
1+
import type { StorageSymbol } from '../../../utilities/src/helpers/unitConversions';
2+
import type { ObjectStorageEndpointTypes } from 'src/object-storage';
3+
import type { Region } from 'src/regions';
44
/**
55
* A Quota is a service used limit that is rated based on service metrics such
66
* as vCPUs used, instances or storage size.
77
*/
88
export interface Quota {
99
/**
10-
* A unique identifier for the quota.
10+
* Longer explanatory description for the quota.
1111
*/
12-
quota_id: number;
12+
description: string;
1313

1414
/**
15-
* Customer facing label describing the quota.
15+
* The OBJ endpoint type to which this limit applies.
16+
*
17+
* For OBJ limits only.
1618
*/
17-
quota_name: string;
19+
endpoint_type?: ObjectStorageEndpointTypes;
1820

1921
/**
20-
* Longer explanatory description for the quota.
22+
* A unique identifier for the quota.
2123
*/
22-
description: string;
24+
quota_id: number;
2325

2426
/**
2527
* The account-wide limit for this service, measured in units
@@ -28,33 +30,22 @@ export interface Quota {
2830
quota_limit: number;
2931

3032
/**
31-
* The unit of measurement for this service limit.
33+
* Customer facing label describing the quota.
3234
*/
33-
resource_metric:
34-
| 'instance'
35-
| 'CPU'
36-
| 'GPU'
37-
| 'VPU'
38-
| 'cluster'
39-
| 'node'
40-
| 'bucket'
41-
| 'object'
42-
| 'byte';
35+
quota_name: string;
4336

4437
/**
4538
* The region slug to which this limit applies.
4639
*
4740
* OBJ limits are applied by endpoint, not region.
4841
* This below really just is a `string` type but being verbose helps with reading comprehension.
4942
*/
50-
region_applied?: Region['id'] | 'global';
43+
region_applied?: 'global' | Region['id'];
5144

5245
/**
53-
* The OBJ endpoint type to which this limit applies.
54-
*
55-
* For OBJ limits only.
46+
* The unit of measurement for this service limit.
5647
*/
57-
endpoint_type?: ObjectStorageEndpointTypes;
48+
resource_metric: StorageSymbol;
5849

5950
/**
6051
* The S3 endpoint URL to which this limit applies.
@@ -81,7 +72,7 @@ export interface QuotaUsage {
8172
*
8273
* This can be null if the user does not have resources for the given Quota Name.
8374
*/
84-
used: number | null;
75+
usage: null | number;
8576
}
8677

8778
export const quotaTypes = {

Diff for: packages/manager/src/factories/quotas.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ export const quotaFactory = Factory.Sync.makeFactory<Quota>({
1313

1414
export const quotaUsageFactory = Factory.Sync.makeFactory<QuotaUsage>({
1515
quota_limit: 50,
16-
used: 25,
16+
usage: 25,
1717
});

Diff for: packages/manager/src/features/Account/Quotas/Quotas.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,11 @@ export const Quotas = () => {
8383
<Typography>
8484
This table shows quotas and usage. If you need to increase a quota,
8585
select Request Increase from the Actions menu. Usage can also be
86-
found using the <Link to="#">S3 APIs</Link>.
86+
found using the{' '}
87+
<Link to="https://techdocs.akamai.com/cloud-computing/docs/use-s3cmd-with-object-storage">
88+
S3 APIs
89+
</Link>
90+
.
8791
</Typography>
8892
<Stack direction="column" spacing={2}>
8993
<QuotasTable

Diff for: packages/manager/src/features/Account/Quotas/QuotasTable.test.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ describe('QuotasTable', () => {
4141
it('should render', () => {
4242
const { getByRole, getByTestId, getByText } = renderWithTheme(
4343
<QuotasTable
44+
selectedLocation={null}
4445
selectedService={{
4546
label: 'Linodes',
4647
value: 'linode',
4748
}}
48-
selectedLocation={null}
4949
/>
5050
);
5151
expect(
@@ -72,7 +72,7 @@ describe('QuotasTable', () => {
7272
];
7373
const quotaUsage = quotaUsageFactory.build({
7474
quota_limit: 100,
75-
used: 10,
75+
usage: 10,
7676
});
7777
queryMocks.useQueries.mockReturnValue([
7878
{
@@ -115,7 +115,7 @@ describe('QuotasTable', () => {
115115
expect(getByLabelText(quota.description)).toBeInTheDocument();
116116
expect(getByTestId('linear-progress')).toBeInTheDocument();
117117
expect(
118-
getByText(`${quotaUsage.used} of ${quotaUsage.quota_limit} CPUs used`)
118+
getByText(`${quotaUsage.usage} of ${quotaUsage.quota_limit} CPUs used`)
119119
).toBeInTheDocument();
120120
expect(
121121
getByLabelText(`Action menu for quota ${quota.quota_name}`)

Diff for: packages/manager/src/features/Account/Quotas/QuotasTable.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export const QuotasTable = (props: QuotasTableProps) => {
112112
{hasSelectedLocation && isFetchingQuotas ? (
113113
<TableRowLoading
114114
columns={4}
115-
rows={5}
115+
rows={3}
116116
sx={{ height: quotaRowMinHeight }}
117117
/>
118118
) : !selectedLocation ? (
@@ -129,7 +129,7 @@ export const QuotasTable = (props: QuotasTableProps) => {
129129
/>
130130
) : (
131131
quotasWithUsage.map((quota, index) => {
132-
const hasQuotaUsage = quota.usage?.used !== null;
132+
const hasQuotaUsage = quota.usage?.usage !== null;
133133

134134
return (
135135
<QuotasTableRow

Diff for: packages/manager/src/features/Account/Quotas/QuotasTableRow.tsx

+44-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Box, CircleProgress, TooltipIcon, Typography } from '@linode/ui';
2+
import { readableBytes } from '@linode/utilities';
23
import ErrorOutline from '@mui/icons-material/ErrorOutline';
34
import { useTheme } from '@mui/material/styles';
45
import * as React from 'react';
@@ -13,6 +14,7 @@ import { useIsAkamaiAccount } from 'src/hooks/useIsAkamaiAccount';
1314
import { getQuotaError } from './utils';
1415

1516
import type { Quota, QuotaUsage } from '@linode/api-v4';
17+
import type { StorageSymbol } from '@linode/utilities';
1618
import type { UseQueryResult } from '@tanstack/react-query';
1719
import type { Action } from 'src/components/ActionMenu/ActionMenu';
1820

@@ -60,6 +62,39 @@ export const QuotasTableRow = (props: QuotasTableRowProps) => {
6062
title: 'Request an Increase',
6163
};
6264

65+
const convertResourceMetric = ({
66+
initialResourceMetric,
67+
initialUsage,
68+
initialLimit,
69+
}: {
70+
initialLimit: number;
71+
initialResourceMetric: StorageSymbol;
72+
initialUsage: number;
73+
}) => {
74+
if (initialResourceMetric === 'byte') {
75+
// First determine the appropriate unit based on the larger number (limit)
76+
const limitReadable = readableBytes(initialLimit);
77+
// Then use that same unit for both values
78+
return {
79+
usage: readableBytes(initialUsage, { unit: limitReadable.unit }).value,
80+
resourceMetric: limitReadable.unit,
81+
limit: limitReadable.value,
82+
};
83+
}
84+
85+
return {
86+
usage: initialUsage,
87+
limit: initialLimit,
88+
resourceMetric: initialResourceMetric,
89+
};
90+
};
91+
92+
const { usage, limit, resourceMetric } = convertResourceMetric({
93+
initialResourceMetric: quota.resource_metric,
94+
initialUsage: quota.usage?.usage ?? 0,
95+
initialLimit: quota.quota_limit,
96+
});
97+
6398
return (
6499
<TableRow key={quota.quota_id} sx={{ height: quotaRowMinHeight }}>
65100
<TableCell>
@@ -72,17 +107,20 @@ export const QuotasTableRow = (props: QuotasTableRowProps) => {
72107
{quota.quota_name}
73108
</Typography>
74109
<TooltipIcon
110+
placement="top"
111+
status="help"
75112
sxTooltipIcon={{
76113
position: 'relative',
77114
top: -2,
78115
}}
79-
placement="top"
80-
status="help"
81116
text={quota.description}
82117
/>
83118
</Box>
84119
</TableCell>
85-
<TableCell>{quota.quota_limit}</TableCell>
120+
<TableCell>
121+
{limit} {resourceMetric}
122+
{quota.quota_limit > 1 ? 's' : ''}
123+
</TableCell>
86124
<TableCell>
87125
<Box sx={{ maxWidth: '80%' }}>
88126
{quotaUsageQueries[index]?.isLoading ? (
@@ -122,11 +160,11 @@ export const QuotasTableRow = (props: QuotasTableRowProps) => {
122160
max={quota.quota_limit}
123161
rounded
124162
sx={{ mb: 1, mt: 2, padding: '3px' }}
125-
value={quota.usage?.used ?? 0}
163+
value={quota.usage?.usage ?? 0}
126164
/>
127165
<Typography sx={{ mb: 1 }}>
128-
{`${quota.usage?.used} of ${quota.quota_limit} ${
129-
quota.resource_metric
166+
{`${usage} of ${limit} ${
167+
resourceMetric
130168
}${quota.quota_limit > 1 ? 's' : ''} used`}
131169
</Typography>
132170
</>

Diff for: packages/manager/src/mocks/presets/crud/handlers/quotas.ts

+10-10
Original file line numberDiff line numberDiff line change
@@ -201,43 +201,43 @@ export const getQuotas = () => [
201201
return makeResponse(
202202
quotaUsageFactory.build({
203203
quota_limit: quota.quota_limit,
204-
used: 45,
204+
usage: 45,
205205
})
206206
);
207207
case 'GPU':
208208
return makeResponse(
209209
quotaUsageFactory.build({
210210
quota_limit: quota.quota_limit,
211-
used: 3,
211+
usage: 3,
212212
})
213213
);
214214
case 'Shared CPU':
215215
return makeResponse(
216216
quotaUsageFactory.build({
217217
quota_limit: quota.quota_limit,
218-
used: 24,
218+
usage: 24,
219219
})
220220
);
221221
case 'VPU':
222222
return makeResponse(
223223
quotaUsageFactory.build({
224224
quota_limit: quota.quota_limit,
225-
used: 7,
225+
usage: 7,
226226
})
227227
);
228228
default:
229229
return makeResponse(
230230
quotaUsageFactory.build({
231231
quota_limit: quota.quota_limit,
232-
used: null,
232+
usage: null,
233233
})
234234
);
235235
}
236236
case 'lke':
237237
return makeResponse(
238238
quotaUsageFactory.build({
239239
quota_limit: quota.quota_limit,
240-
used: pickRandom([2, 27, 5, 38, 49]),
240+
usage: pickRandom([2, 27, 5, 38, 49]),
241241
})
242242
);
243243
case 'object-storage':
@@ -246,28 +246,28 @@ export const getQuotas = () => [
246246
return makeResponse(
247247
quotaUsageFactory.build({
248248
quota_limit: quota.quota_limit,
249-
used: 75,
249+
usage: 75,
250250
})
251251
);
252252
case 'Number of Objects':
253253
return makeResponse(
254254
quotaUsageFactory.build({
255255
quota_limit: quota.quota_limit,
256-
used: 10_000_000,
256+
usage: 10_000_000,
257257
})
258258
);
259259
case 'Total Capacity':
260260
return makeResponse(
261261
quotaUsageFactory.build({
262262
quota_limit: quota.quota_limit,
263-
used: 100_000_000_000_000,
263+
usage: 100_000_000_000_000,
264264
})
265265
);
266266
default:
267267
makeResponse(
268268
quotaUsageFactory.build({
269269
quota_limit: quota.quota_limit,
270-
used: null,
270+
usage: null,
271271
})
272272
);
273273
}

0 commit comments

Comments
 (0)