@cloud-ru/ds-uikit-product-quota 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/LICENSE +201 -0
- package/README.md +458 -0
- package/dist/cjs/components/QuotaWidget/QuotaIncreaseButton.d.ts +4 -0
- package/dist/cjs/components/QuotaWidget/QuotaIncreaseButton.js +15 -0
- package/dist/cjs/components/QuotaWidget/QuotaMobileHeader.d.ts +4 -0
- package/dist/cjs/components/QuotaWidget/QuotaMobileHeader.js +15 -0
- package/dist/cjs/components/QuotaWidget/QuotaWidget.d.ts +12 -0
- package/dist/cjs/components/QuotaWidget/QuotaWidget.js +44 -0
- package/dist/cjs/components/QuotaWidget/QuotaWidgetContent.d.ts +27 -0
- package/dist/cjs/components/QuotaWidget/QuotaWidgetContent.js +33 -0
- package/dist/cjs/components/QuotaWidget/components/ProjectHeader/ProjectHeader.d.ts +7 -0
- package/dist/cjs/components/QuotaWidget/components/ProjectHeader/ProjectHeader.js +19 -0
- package/dist/cjs/components/QuotaWidget/components/ProjectHeader/index.d.ts +1 -0
- package/dist/cjs/components/QuotaWidget/components/ProjectHeader/index.js +17 -0
- package/dist/cjs/components/QuotaWidget/components/ProjectHeader/styles.module.css +30 -0
- package/dist/cjs/components/QuotaWidget/index.d.ts +2 -0
- package/dist/cjs/components/QuotaWidget/index.js +18 -0
- package/dist/cjs/components/QuotaWidget/styles.module.css +49 -0
- package/dist/cjs/components/QuotaWidgetCard/QuotaWidgetCard.d.ts +13 -0
- package/dist/cjs/components/QuotaWidgetCard/QuotaWidgetCard.js +53 -0
- package/dist/cjs/components/QuotaWidgetCard/components/QuotaTooltip/QuotaTooltip.d.ts +6 -0
- package/dist/cjs/components/QuotaWidgetCard/components/QuotaTooltip/QuotaTooltip.js +23 -0
- package/dist/cjs/components/QuotaWidgetCard/components/QuotaTooltip/index.d.ts +1 -0
- package/dist/cjs/components/QuotaWidgetCard/components/QuotaTooltip/index.js +17 -0
- package/dist/cjs/components/QuotaWidgetCard/components/QuotaTooltip/styles.module.css +34 -0
- package/dist/cjs/components/QuotaWidgetCard/index.d.ts +1 -0
- package/dist/cjs/components/QuotaWidgetCard/index.js +17 -0
- package/dist/cjs/components/QuotaWidgetCard/styles.module.css +97 -0
- package/dist/cjs/components/QuotaWidgetMini/QuotaWidgetMini.d.ts +7 -0
- package/dist/cjs/components/QuotaWidgetMini/QuotaWidgetMini.js +27 -0
- package/dist/cjs/components/QuotaWidgetMini/index.d.ts +1 -0
- package/dist/cjs/components/QuotaWidgetMini/index.js +17 -0
- package/dist/cjs/components/QuotaWidgetMini/styles.module.css +15 -0
- package/dist/cjs/components/index.d.ts +3 -0
- package/dist/cjs/components/index.js +19 -0
- package/dist/cjs/constants.d.ts +17 -0
- package/dist/cjs/constants.js +20 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/QuotaCardsGrid.d.ts +6 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/QuotaCardsGrid.js +32 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/Grid/Grid.d.ts +6 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/Grid/Grid.js +30 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/QuotaCardsSkeleton.d.ts +6 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/QuotaCardsSkeleton.js +16 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/index.d.ts +1 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/index.js +17 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/styles.module.css +10 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/Grid/index.d.ts +1 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/Grid/index.js +17 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/Grid/styles.module.css +9 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/QuotaError/QuotaError.d.ts +5 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/QuotaError/QuotaError.js +12 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/QuotaError/index.d.ts +1 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/QuotaError/index.js +17 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/index.d.ts +1 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/index.js +17 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/styles.module.css +16 -0
- package/dist/cjs/index.d.ts +5 -0
- package/dist/cjs/index.js +21 -0
- package/dist/cjs/locale/index.d.ts +91 -0
- package/dist/cjs/locale/index.js +50 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/style.css +260 -0
- package/dist/cjs/types.d.ts +34 -0
- package/dist/cjs/types.js +2 -0
- package/dist/cjs/utils/checkIsExceeded.d.ts +2 -0
- package/dist/cjs/utils/checkIsExceeded.js +5 -0
- package/dist/cjs/utils/formatNumber.d.ts +1 -0
- package/dist/cjs/utils/formatNumber.js +6 -0
- package/dist/cjs/utils/getPercent.d.ts +2 -0
- package/dist/cjs/utils/getPercent.js +9 -0
- package/dist/cjs/utils/index.d.ts +3 -0
- package/dist/cjs/utils/index.js +19 -0
- package/dist/esm/components/QuotaWidget/QuotaIncreaseButton.d.ts +4 -0
- package/dist/esm/components/QuotaWidget/QuotaIncreaseButton.js +9 -0
- package/dist/esm/components/QuotaWidget/QuotaMobileHeader.d.ts +4 -0
- package/dist/esm/components/QuotaWidget/QuotaMobileHeader.js +9 -0
- package/dist/esm/components/QuotaWidget/QuotaWidget.d.ts +12 -0
- package/dist/esm/components/QuotaWidget/QuotaWidget.js +41 -0
- package/dist/esm/components/QuotaWidget/QuotaWidgetContent.d.ts +27 -0
- package/dist/esm/components/QuotaWidget/QuotaWidgetContent.js +27 -0
- package/dist/esm/components/QuotaWidget/components/ProjectHeader/ProjectHeader.d.ts +7 -0
- package/dist/esm/components/QuotaWidget/components/ProjectHeader/ProjectHeader.js +13 -0
- package/dist/esm/components/QuotaWidget/components/ProjectHeader/index.d.ts +1 -0
- package/dist/esm/components/QuotaWidget/components/ProjectHeader/index.js +1 -0
- package/dist/esm/components/QuotaWidget/components/ProjectHeader/styles.module.css +30 -0
- package/dist/esm/components/QuotaWidget/index.d.ts +2 -0
- package/dist/esm/components/QuotaWidget/index.js +2 -0
- package/dist/esm/components/QuotaWidget/styles.module.css +49 -0
- package/dist/esm/components/QuotaWidgetCard/QuotaWidgetCard.d.ts +13 -0
- package/dist/esm/components/QuotaWidgetCard/QuotaWidgetCard.js +47 -0
- package/dist/esm/components/QuotaWidgetCard/components/QuotaTooltip/QuotaTooltip.d.ts +6 -0
- package/dist/esm/components/QuotaWidgetCard/components/QuotaTooltip/QuotaTooltip.js +17 -0
- package/dist/esm/components/QuotaWidgetCard/components/QuotaTooltip/index.d.ts +1 -0
- package/dist/esm/components/QuotaWidgetCard/components/QuotaTooltip/index.js +1 -0
- package/dist/esm/components/QuotaWidgetCard/components/QuotaTooltip/styles.module.css +34 -0
- package/dist/esm/components/QuotaWidgetCard/index.d.ts +1 -0
- package/dist/esm/components/QuotaWidgetCard/index.js +1 -0
- package/dist/esm/components/QuotaWidgetCard/styles.module.css +97 -0
- package/dist/esm/components/QuotaWidgetMini/QuotaWidgetMini.d.ts +7 -0
- package/dist/esm/components/QuotaWidgetMini/QuotaWidgetMini.js +21 -0
- package/dist/esm/components/QuotaWidgetMini/index.d.ts +1 -0
- package/dist/esm/components/QuotaWidgetMini/index.js +1 -0
- package/dist/esm/components/QuotaWidgetMini/styles.module.css +15 -0
- package/dist/esm/components/index.d.ts +3 -0
- package/dist/esm/components/index.js +3 -0
- package/dist/esm/constants.d.ts +17 -0
- package/dist/esm/constants.js +17 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/QuotaCardsGrid.d.ts +6 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/QuotaCardsGrid.js +26 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/Grid/Grid.d.ts +6 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/Grid/Grid.js +24 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/QuotaCardsSkeleton.d.ts +6 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/QuotaCardsSkeleton.js +10 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/index.d.ts +1 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/index.js +1 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/styles.module.css +10 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/Grid/index.d.ts +1 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/Grid/index.js +1 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/Grid/styles.module.css +9 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/QuotaError/QuotaError.d.ts +5 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/QuotaError/QuotaError.js +9 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/QuotaError/index.d.ts +1 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/QuotaError/index.js +1 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/index.d.ts +1 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/index.js +1 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/styles.module.css +16 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/locale/index.d.ts +91 -0
- package/dist/esm/locale/index.js +47 -0
- package/dist/esm/style.css +260 -0
- package/dist/esm/types.d.ts +34 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/utils/checkIsExceeded.d.ts +2 -0
- package/dist/esm/utils/checkIsExceeded.js +1 -0
- package/dist/esm/utils/formatNumber.d.ts +1 -0
- package/dist/esm/utils/formatNumber.js +3 -0
- package/dist/esm/utils/getPercent.d.ts +2 -0
- package/dist/esm/utils/getPercent.js +6 -0
- package/dist/esm/utils/index.d.ts +3 -0
- package/dist/esm/utils/index.js +3 -0
- package/dist/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/tsconfig.esm.tsbuildinfo +1 -0
- package/package.json +63 -0
- package/src/components/QuotaWidget/QuotaIncreaseButton.tsx +21 -0
- package/src/components/QuotaWidget/QuotaMobileHeader.tsx +18 -0
- package/src/components/QuotaWidget/QuotaWidget.tsx +109 -0
- package/src/components/QuotaWidget/QuotaWidgetContent.tsx +91 -0
- package/src/components/QuotaWidget/components/ProjectHeader/ProjectHeader.tsx +59 -0
- package/src/components/QuotaWidget/components/ProjectHeader/index.ts +1 -0
- package/src/components/QuotaWidget/components/ProjectHeader/styles.module.scss +29 -0
- package/src/components/QuotaWidget/index.ts +2 -0
- package/src/components/QuotaWidget/styles.module.scss +52 -0
- package/src/components/QuotaWidgetCard/QuotaWidgetCard.tsx +127 -0
- package/src/components/QuotaWidgetCard/components/QuotaTooltip/QuotaTooltip.tsx +48 -0
- package/src/components/QuotaWidgetCard/components/QuotaTooltip/index.ts +1 -0
- package/src/components/QuotaWidgetCard/components/QuotaTooltip/styles.module.scss +30 -0
- package/src/components/QuotaWidgetCard/index.ts +1 -0
- package/src/components/QuotaWidgetCard/styles.module.scss +97 -0
- package/src/components/QuotaWidgetMini/QuotaWidgetMini.tsx +93 -0
- package/src/components/QuotaWidgetMini/index.ts +1 -0
- package/src/components/QuotaWidgetMini/styles.module.scss +18 -0
- package/src/components/index.ts +3 -0
- package/src/constants.ts +17 -0
- package/src/helperComponents/QuotaCardsGrid/QuotaCardsGrid.tsx +54 -0
- package/src/helperComponents/QuotaCardsGrid/components/Grid/Grid.tsx +47 -0
- package/src/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/QuotaCardsSkeleton.tsx +24 -0
- package/src/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/index.ts +1 -0
- package/src/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/styles.module.scss +15 -0
- package/src/helperComponents/QuotaCardsGrid/components/Grid/index.ts +1 -0
- package/src/helperComponents/QuotaCardsGrid/components/Grid/styles.module.scss +12 -0
- package/src/helperComponents/QuotaCardsGrid/components/QuotaError/QuotaError.tsx +31 -0
- package/src/helperComponents/QuotaCardsGrid/components/QuotaError/index.ts +1 -0
- package/src/helperComponents/QuotaCardsGrid/index.ts +1 -0
- package/src/helperComponents/QuotaCardsGrid/styles.module.scss +16 -0
- package/src/index.ts +5 -0
- package/src/locale/index.ts +51 -0
- package/src/types.ts +35 -0
- package/src/utils/checkIsExceeded.ts +3 -0
- package/src/utils/formatNumber.ts +3 -0
- package/src/utils/getPercent.ts +9 -0
- package/src/utils/index.ts +3 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Accordion } from '@cloud-ru/ds-accordion';
|
|
2
|
+
import { Button } from '@cloud-ru/ds-button';
|
|
3
|
+
import { Counter } from '@cloud-ru/ds-counter';
|
|
4
|
+
import { TruncateString } from '@cloud-ru/ds-truncate-string';
|
|
5
|
+
import { WithSupportProps } from '@cloud-ru/ds-utils';
|
|
6
|
+
|
|
7
|
+
import { TEST_IDS } from '../../constants';
|
|
8
|
+
import { QuotaCardsGrid } from '../../helperComponents/QuotaCardsGrid';
|
|
9
|
+
import { quotaLocale } from '../../locale';
|
|
10
|
+
import { QuotaWidgetPropsBase } from '../../types';
|
|
11
|
+
import { checkIsExceeded } from '../../utils';
|
|
12
|
+
import styles from './styles.module.scss';
|
|
13
|
+
|
|
14
|
+
export type QuotaWidgetMiniProps = WithSupportProps<
|
|
15
|
+
QuotaWidgetPropsBase & {
|
|
16
|
+
/** Флаг раскрытия аккордиона по умолчанию */
|
|
17
|
+
defaultExpanded?: boolean;
|
|
18
|
+
}
|
|
19
|
+
>;
|
|
20
|
+
|
|
21
|
+
const ACCORDION_ID = 'quotas-widget-accordion';
|
|
22
|
+
|
|
23
|
+
export function QuotaWidgetMini({
|
|
24
|
+
quotas,
|
|
25
|
+
disableSorting,
|
|
26
|
+
loading,
|
|
27
|
+
error,
|
|
28
|
+
onRefresh,
|
|
29
|
+
projectName,
|
|
30
|
+
canEditQuota,
|
|
31
|
+
defaultExpanded,
|
|
32
|
+
hideIncreaseQuotaButton,
|
|
33
|
+
onIncreaseQuotaClick,
|
|
34
|
+
onWidgetOpen,
|
|
35
|
+
'data-test-id': dataTestId,
|
|
36
|
+
...props
|
|
37
|
+
}: QuotaWidgetMiniProps) {
|
|
38
|
+
const { t } = quotaLocale.useTranslations();
|
|
39
|
+
|
|
40
|
+
const exhaustedCount = quotas.filter(checkIsExceeded).length;
|
|
41
|
+
|
|
42
|
+
const handleExpandedChange = (expanded: string | undefined) => {
|
|
43
|
+
if (expanded) {
|
|
44
|
+
onWidgetOpen?.();
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div data-test-id={dataTestId ?? TEST_IDS.quotaWidgetMini.root}>
|
|
50
|
+
<Accordion
|
|
51
|
+
{...props}
|
|
52
|
+
expandedDefault={defaultExpanded ? ACCORDION_ID : undefined}
|
|
53
|
+
onExpandedChange={handleExpandedChange}
|
|
54
|
+
>
|
|
55
|
+
<Accordion.CollapseBlockSecondary
|
|
56
|
+
id={ACCORDION_ID}
|
|
57
|
+
className={styles.collapse}
|
|
58
|
+
data-test-id={TEST_IDS.quotaWidgetMini.trigger}
|
|
59
|
+
title={t('quotas')}
|
|
60
|
+
afterTitle={
|
|
61
|
+
!error && !loading && exhaustedCount > 0 ? (
|
|
62
|
+
<Counter value={exhaustedCount} size='xs' appearance='red' />
|
|
63
|
+
) : undefined
|
|
64
|
+
}
|
|
65
|
+
subTitle={<TruncateString maxLines={1} text={projectName} />}
|
|
66
|
+
>
|
|
67
|
+
<div className={styles.body} data-test-id={TEST_IDS.quotaWidgetMini.content}>
|
|
68
|
+
<QuotaCardsGrid
|
|
69
|
+
isAccordion
|
|
70
|
+
quotas={quotas}
|
|
71
|
+
disableSorting={disableSorting}
|
|
72
|
+
loading={loading}
|
|
73
|
+
error={error}
|
|
74
|
+
onRefresh={onRefresh}
|
|
75
|
+
/>
|
|
76
|
+
|
|
77
|
+
{!error && canEditQuota && !hideIncreaseQuotaButton && (
|
|
78
|
+
<Button
|
|
79
|
+
className={styles.button}
|
|
80
|
+
fullWidth
|
|
81
|
+
view='outline'
|
|
82
|
+
appearance='neutral'
|
|
83
|
+
label={t('increaseQuota')}
|
|
84
|
+
size='m'
|
|
85
|
+
onClick={onIncreaseQuotaClick}
|
|
86
|
+
/>
|
|
87
|
+
)}
|
|
88
|
+
</div>
|
|
89
|
+
</Accordion.CollapseBlockSecondary>
|
|
90
|
+
</Accordion>
|
|
91
|
+
</div>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './QuotaWidgetMini';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
|
|
2
|
+
|
|
3
|
+
.collapse {
|
|
4
|
+
width: 304px;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.body {
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
gap: base.$sn-primitive-dimension-16;
|
|
11
|
+
align-items: flex-start;
|
|
12
|
+
|
|
13
|
+
width: 100%;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.button {
|
|
17
|
+
width: 100%;
|
|
18
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const TEST_IDS = {
|
|
2
|
+
quotaWidget: {
|
|
3
|
+
root: 'quota-widget',
|
|
4
|
+
trigger: 'quota-widget__trigger',
|
|
5
|
+
content: 'quota-widget__content',
|
|
6
|
+
projectHeader: 'quota-widget__project-header',
|
|
7
|
+
},
|
|
8
|
+
quotaWidgetMini: {
|
|
9
|
+
root: 'quota-widget-mini',
|
|
10
|
+
trigger: 'quota-widget-mini__trigger',
|
|
11
|
+
content: 'quota-widget-mini__content',
|
|
12
|
+
},
|
|
13
|
+
quotaWidgetCard: {
|
|
14
|
+
root: 'quota-widget-card',
|
|
15
|
+
tooltip: 'quota-widget-card__tooltip',
|
|
16
|
+
},
|
|
17
|
+
} as const;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { isMobileLayout, useAdaptiveLayout } from '@cloud-ru/ds-adaptive';
|
|
2
|
+
import { Scroll } from '@cloud-ru/ds-scroll';
|
|
3
|
+
|
|
4
|
+
import { QuotaWidgetPropsBase } from '../../types';
|
|
5
|
+
import { Grid } from './components/Grid';
|
|
6
|
+
import { QuotaError } from './components/QuotaError';
|
|
7
|
+
import styles from './styles.module.scss';
|
|
8
|
+
|
|
9
|
+
type QuotaCardsGridProps = Pick<
|
|
10
|
+
QuotaWidgetPropsBase,
|
|
11
|
+
'quotas' | 'disableSorting' | 'loading' | 'error' | 'onRefresh'
|
|
12
|
+
> & {
|
|
13
|
+
isAccordion?: boolean;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export function QuotaCardsGrid({
|
|
17
|
+
quotas,
|
|
18
|
+
loading,
|
|
19
|
+
error,
|
|
20
|
+
onRefresh,
|
|
21
|
+
disableSorting = false,
|
|
22
|
+
isAccordion = false,
|
|
23
|
+
}: QuotaCardsGridProps) {
|
|
24
|
+
// На мобилке bottom-sheet-виджет full-height: снимаем фикс-cap высоты (`max-height`), карточки
|
|
25
|
+
// скроллятся телом листа. Для аккордеона (`QuotaWidgetMini`) это НЕ применяем — у него свой cap.
|
|
26
|
+
const isMobile = isMobileLayout(useAdaptiveLayout().layoutType);
|
|
27
|
+
|
|
28
|
+
const wrapperAttributes = {
|
|
29
|
+
className: styles.wrapper,
|
|
30
|
+
'data-accordion': isAccordion,
|
|
31
|
+
'data-mobile': isMobile && !isAccordion,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const gridProps = {
|
|
35
|
+
quotas,
|
|
36
|
+
loading,
|
|
37
|
+
disableSorting,
|
|
38
|
+
isAccordion,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
if (error) {
|
|
42
|
+
return (
|
|
43
|
+
<div {...wrapperAttributes}>
|
|
44
|
+
<QuotaError onRefresh={onRefresh} />
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<Scroll {...wrapperAttributes} size='s'>
|
|
51
|
+
<Grid {...gridProps} />
|
|
52
|
+
</Scroll>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { isMobileLayout, useAdaptiveLayout } from '@cloud-ru/ds-adaptive';
|
|
2
|
+
|
|
3
|
+
import { QuotaWidgetCard } from '../../../../components/QuotaWidgetCard';
|
|
4
|
+
import { TEST_IDS } from '../../../../constants';
|
|
5
|
+
import { QuotaItem, QuotaWidgetPropsBase } from '../../../../types';
|
|
6
|
+
import { getPercent } from '../../../../utils/getPercent';
|
|
7
|
+
import { QuotaWidgetCardsSkeleton } from './components/QuotaWidgetCardsSkeleton';
|
|
8
|
+
import styles from './styles.module.scss';
|
|
9
|
+
|
|
10
|
+
function sortQuotas(quotas: QuotaItem[]): QuotaItem[] {
|
|
11
|
+
return [...quotas].sort((first, second) => {
|
|
12
|
+
const percentFirst = getPercent(first);
|
|
13
|
+
const percentSecond = getPercent(second);
|
|
14
|
+
|
|
15
|
+
if (percentSecond !== percentFirst) {
|
|
16
|
+
return percentSecond - percentFirst;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return first.name.localeCompare(second.name);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type GridProps = Pick<QuotaWidgetPropsBase, 'quotas' | 'loading' | 'disableSorting'> & {
|
|
24
|
+
isAccordion?: boolean;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export function Grid({ quotas, loading, disableSorting = false, isAccordion = false }: GridProps) {
|
|
28
|
+
const sortedQuotas = disableSorting ? quotas : sortQuotas(quotas);
|
|
29
|
+
|
|
30
|
+
// На мобилке — строго одна колонка на всю ширину (BottomSheet-раскладка узкая, 2 колонки не влезают).
|
|
31
|
+
const { layoutType } = useAdaptiveLayout();
|
|
32
|
+
const isSingleColumn = (quotas.length <= 1 && !loading) || isAccordion || isMobileLayout(layoutType);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<div className={styles.grid} data-single={isSingleColumn}>
|
|
36
|
+
<QuotaWidgetCardsSkeleton loading={loading}>
|
|
37
|
+
{sortedQuotas.map(quota => (
|
|
38
|
+
<QuotaWidgetCard
|
|
39
|
+
key={quota.name}
|
|
40
|
+
quota={quota}
|
|
41
|
+
data-test-id={`${TEST_IDS.quotaWidgetCard.root}--${quota.name}`}
|
|
42
|
+
/>
|
|
43
|
+
))}
|
|
44
|
+
</QuotaWidgetCardsSkeleton>
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { SkeletonText } from '@cloud-ru/ds-skeleton';
|
|
2
|
+
import { PropsWithChildren } from 'react';
|
|
3
|
+
|
|
4
|
+
import styles from './styles.module.scss';
|
|
5
|
+
|
|
6
|
+
type QuotaWidgetCardsSkeletonProps = PropsWithChildren<{
|
|
7
|
+
loading: boolean;
|
|
8
|
+
}>;
|
|
9
|
+
|
|
10
|
+
const SKELETON_COUNT = 6;
|
|
11
|
+
|
|
12
|
+
export function QuotaWidgetCardsSkeleton({ loading, children }: QuotaWidgetCardsSkeletonProps) {
|
|
13
|
+
if (loading) {
|
|
14
|
+
return [...Array(SKELETON_COUNT)].map((_, index) => (
|
|
15
|
+
<div className={styles.card} key={index}>
|
|
16
|
+
<SkeletonText loading lines={1} variant='body' size='m' />
|
|
17
|
+
<SkeletonText loading lines={1} variant='body' size='m' />
|
|
18
|
+
<SkeletonText loading lines={1} variant='body' size='l' />
|
|
19
|
+
</div>
|
|
20
|
+
));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return children;
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './QuotaCardsSkeleton';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
|
|
2
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/components/card.module' as card;
|
|
3
|
+
|
|
4
|
+
.card {
|
|
5
|
+
display: flex;
|
|
6
|
+
flex: 1;
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
row-gap: base.$sn-primitive-dimension-4;
|
|
9
|
+
|
|
10
|
+
min-width: 0;
|
|
11
|
+
padding: base.$sn-primitive-dimension-8;
|
|
12
|
+
border-radius: card.$sn-card-anatomy-radius-s-container-borderRadius;
|
|
13
|
+
|
|
14
|
+
background-color: base.$sn-theme-color-neutral-decorTransparent;
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Grid';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
|
|
2
|
+
|
|
3
|
+
.grid {
|
|
4
|
+
display: grid;
|
|
5
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
6
|
+
gap: base.$sn-primitive-dimension-4 base.$sn-primitive-dimension-4;
|
|
7
|
+
width: 100%;
|
|
8
|
+
|
|
9
|
+
&[data-single='true'] {
|
|
10
|
+
grid-template-columns: minmax(0, 1fr);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Button } from '@cloud-ru/ds-button';
|
|
2
|
+
import { CrossSVG, UpdateSVG } from '@cloud-ru/ds-icons/interface/system';
|
|
3
|
+
import { InfoBlock } from '@cloud-ru/ds-info-block';
|
|
4
|
+
|
|
5
|
+
import { quotaLocale } from '../../../../locale';
|
|
6
|
+
|
|
7
|
+
type QuotaErrorProps = {
|
|
8
|
+
onRefresh: () => void;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export function QuotaError({ onRefresh }: QuotaErrorProps) {
|
|
12
|
+
const { t } = quotaLocale.useTranslations();
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<InfoBlock
|
|
16
|
+
size='m'
|
|
17
|
+
align='vertical'
|
|
18
|
+
content={t('errorText')}
|
|
19
|
+
icon={{ icon: CrossSVG, appearance: 'neutral', background: true }}
|
|
20
|
+
footer={
|
|
21
|
+
<Button
|
|
22
|
+
appearance='neutral'
|
|
23
|
+
size='m'
|
|
24
|
+
label={t('errorButton')}
|
|
25
|
+
icon={<UpdateSVG size={24} />}
|
|
26
|
+
onClick={onRefresh}
|
|
27
|
+
/>
|
|
28
|
+
}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './QuotaError';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './QuotaCardsGrid';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
.wrapper {
|
|
2
|
+
width: 100%;
|
|
3
|
+
height: auto;
|
|
4
|
+
max-height: 382px;
|
|
5
|
+
|
|
6
|
+
&[data-accordion='true'] {
|
|
7
|
+
max-height: 400px;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/* Mobile (full-height BottomSheet): без фикс-cap — карточки заполняют тело листа и скроллятся им. */
|
|
11
|
+
&[data-mobile='true'] {
|
|
12
|
+
flex: 1 1 auto;
|
|
13
|
+
min-height: 0;
|
|
14
|
+
max-height: none;
|
|
15
|
+
}
|
|
16
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { defineLocale, defineMessages } from '@cloud-ru/ds-locale';
|
|
2
|
+
|
|
3
|
+
const QUOTA_MESSAGES = defineMessages({
|
|
4
|
+
'en-GB': {
|
|
5
|
+
quotas: 'Quotas',
|
|
6
|
+
widgetTitle: {
|
|
7
|
+
withoutProject: 'Project quotas',
|
|
8
|
+
quotes: 'Project quotas «{{project}}»',
|
|
9
|
+
noQuotes: 'Project quotas {{project}}',
|
|
10
|
+
},
|
|
11
|
+
widgetSubtitle: 'Current quota balance',
|
|
12
|
+
increaseQuota: 'Increase quota',
|
|
13
|
+
cardAvailable: 'Available',
|
|
14
|
+
cardRemaining: 'Remaining',
|
|
15
|
+
tooltipAvailable: 'Available',
|
|
16
|
+
tooltipUsed: 'Used',
|
|
17
|
+
tooltipRemaining: 'Remaining',
|
|
18
|
+
tooltipExhaustedHint: {
|
|
19
|
+
first: 'Quota exhausted.',
|
|
20
|
+
second: 'To increase the quota, contact the quota or organization administrator.',
|
|
21
|
+
},
|
|
22
|
+
errorText: 'Failed to load data',
|
|
23
|
+
errorButton: 'Refresh',
|
|
24
|
+
},
|
|
25
|
+
'ru-RU': {
|
|
26
|
+
quotas: 'Квоты',
|
|
27
|
+
widgetTitle: {
|
|
28
|
+
withoutProject: 'Квоты проекта',
|
|
29
|
+
quotes: 'Квоты проекта «{{project}}»',
|
|
30
|
+
noQuotes: 'Квоты проекта {{project}}',
|
|
31
|
+
},
|
|
32
|
+
widgetSubtitle: 'Остаток по квотам на текущий момент',
|
|
33
|
+
increaseQuota: 'Увеличить квоту',
|
|
34
|
+
cardAvailable: 'Доступно',
|
|
35
|
+
cardRemaining: 'Остаток',
|
|
36
|
+
tooltipAvailable: 'Доступно',
|
|
37
|
+
tooltipUsed: 'Использовано',
|
|
38
|
+
tooltipRemaining: 'Остаток',
|
|
39
|
+
tooltipExhaustedHint: {
|
|
40
|
+
first: 'Квота исчерпана.',
|
|
41
|
+
second: 'Чтобы увеличить квоту, обратитесь к администратору квот или организации.',
|
|
42
|
+
},
|
|
43
|
+
errorText: 'Не удалось загрузить данные',
|
|
44
|
+
errorButton: 'Обновить',
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export type QuotaMessages = (typeof QUOTA_MESSAGES)['en-GB'];
|
|
49
|
+
|
|
50
|
+
/** locale компонента Quota: `quotaLocale.useTranslations()` в коде, `quotaLocale.extend(...)` в сервисе. */
|
|
51
|
+
export const quotaLocale = defineLocale('@cloud-ru/ds-uikit-product-quota', QUOTA_MESSAGES);
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type QuotaItem = {
|
|
2
|
+
/** Название квоты */
|
|
3
|
+
name: string;
|
|
4
|
+
/** Лимит квоты */
|
|
5
|
+
limit: number;
|
|
6
|
+
/** Потребление квоты */
|
|
7
|
+
usage: number;
|
|
8
|
+
/** Остаток квоты */
|
|
9
|
+
remains: number;
|
|
10
|
+
/** Единица измерения квоты */
|
|
11
|
+
unitDisplayName: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type QuotaWidgetPropsBase = {
|
|
15
|
+
/** Список квот для отображения */
|
|
16
|
+
quotas: QuotaItem[];
|
|
17
|
+
/** Флаг отключения сортировки квот */
|
|
18
|
+
disableSorting?: boolean;
|
|
19
|
+
/** Флаг загрузки квот */
|
|
20
|
+
loading: boolean;
|
|
21
|
+
/** Флаг ошибки при загрузке квот */
|
|
22
|
+
error: boolean;
|
|
23
|
+
/** Колбек на обновление списка квот при ошибке */
|
|
24
|
+
onRefresh: () => void;
|
|
25
|
+
/** Название проекта, по которому отображаются квоты */
|
|
26
|
+
projectName: string;
|
|
27
|
+
/** Флаг наличия прав на редактирование квот */
|
|
28
|
+
canEditQuota: boolean;
|
|
29
|
+
/** Флаг скрытия кнопки увеличения квоты */
|
|
30
|
+
hideIncreaseQuotaButton?: boolean;
|
|
31
|
+
/** Колбек нажатия на кнопку увеличения квот */
|
|
32
|
+
onIncreaseQuotaClick?: () => void;
|
|
33
|
+
/** Колбек открытия виджета квот */
|
|
34
|
+
onWidgetOpen?: () => void;
|
|
35
|
+
};
|