Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
af16dd47
Commit
af16dd47
authored
Apr 07, 2022
by
Ammar Alakkad
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert "Merge branch '350646-use-statistics-block' into 'master'"
This reverts merge request !79525
parent
238e5184
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
265 additions
and
409 deletions
+265
-409
app/views/projects/usage_quotas/index.html.haml
app/views/projects/usage_quotas/index.html.haml
+1
-1
ee/app/assets/javascripts/usage_quotas/components/statistics_card.vue
...s/javascripts/usage_quotas/components/statistics_card.vue
+6
-0
ee/app/assets/javascripts/usage_quotas/components/storage_statistics_card.vue
...ripts/usage_quotas/components/storage_statistics_card.vue
+0
-91
ee/app/assets/javascripts/usage_quotas/storage/components/usage_statistics.vue
...ipts/usage_quotas/storage/components/usage_statistics.vue
+100
-79
ee/app/assets/javascripts/usage_quotas/storage/components/usage_statistics_card.vue
...usage_quotas/storage/components/usage_statistics_card.vue
+79
-0
ee/app/assets/javascripts/usage_quotas/storage/utils.js
ee/app/assets/javascripts/usage_quotas/storage/utils.js
+4
-29
ee/spec/frontend/usage_quotas/components/statistics_card_spec.js
.../frontend/usage_quotas/components/statistics_card_spec.js
+6
-0
ee/spec/frontend/usage_quotas/components/storage_statistics_card_spec.js
...d/usage_quotas/components/storage_statistics_card_spec.js
+0
-85
ee/spec/frontend/usage_quotas/storage/components/usage_statistics_spec.js
.../usage_quotas/storage/components/usage_statistics_spec.js
+51
-99
ee/spec/frontend/usage_quotas/storage/utils_spec.js
ee/spec/frontend/usage_quotas/storage/utils_spec.js
+0
-16
locale/gitlab.pot
locale/gitlab.pot
+18
-9
No files found.
app/views/projects/usage_quotas/index.html.haml
View file @
af16dd47
...
...
@@ -7,7 +7,7 @@
.col-sm-12
=
s_
(
'UsageQuota|Usage of project resources across the %{strong_start}%{project_name}%{strong_end} project'
).
html_safe
%
{
strong_start:
'<strong>'
.
html_safe
,
strong_end:
'</strong>'
.
html_safe
,
project_name:
@project
.
name
}
+
'.'
%a
{
href:
help_page_path
(
'user/usage_quotas.md'
),
target:
'_blank'
,
rel:
'noopener noreferrer'
}
=
s_
(
'UsageQuota|Learn more about usage quotas
.'
)
=
s_
(
'UsageQuota|Learn more about usage quotas
'
)
+
'.'
=
gl_tabs_nav
do
=
gl_tab_link_to
'#storage-quota-tab'
,
item_active:
true
do
...
...
ee/app/assets/javascripts/usage_quotas/components/statistics_card.vue
View file @
af16dd47
...
...
@@ -55,6 +55,11 @@ export default {
required
:
false
,
default
:
null
,
},
cssClass
:
{
type
:
String
,
required
:
false
,
default
:
null
,
},
},
};
</
script
>
...
...
@@ -63,6 +68,7 @@ export default {
<div
class=
"gl-bg-white gl-border-1 gl-border-gray-100 gl-border-solid gl-p-5 gl-rounded-base"
data-testid=
"container"
:class=
"cssClass"
>
<div
class=
"gl-display-flex gl-justify-content-space-between"
>
<p
...
...
ee/app/assets/javascripts/usage_quotas/components/storage_statistics_card.vue
deleted
100644 → 0
View file @
238e5184
<
script
>
import
{
GlProgressBar
}
from
'
@gitlab/ui
'
;
import
{
formatSizeAndSplit
}
from
'
ee/usage_quotas/storage/utils
'
;
export
default
{
name
:
'
StorageStatisticsCard
'
,
components
:
{
GlProgressBar
},
props
:
{
totalStorage
:
{
type
:
Number
,
required
:
false
,
default
:
null
,
},
usedStorage
:
{
type
:
Number
,
required
:
false
,
default
:
null
,
},
},
computed
:
{
formattedUsage
()
{
// we want to show the usage only if there's purchased storage
if
(
this
.
totalStorage
===
null
)
{
return
null
;
}
return
this
.
formatSizeAndSplit
(
this
.
usedStorage
);
},
formattedTotal
()
{
return
this
.
formatSizeAndSplit
(
this
.
totalStorage
);
},
percentage
()
{
// don't show the progress bar if there's no total storage
if
(
!
this
.
totalStorage
||
this
.
usedStorage
===
null
)
{
return
null
;
}
return
Math
.
min
(
Math
.
round
((
this
.
usedStorage
/
this
.
totalStorage
)
*
100
),
100
);
},
usageValue
()
{
if
(
!
this
.
totalStorage
&&
!
this
.
usedStorage
)
{
// if there is no total storage and no used storage, we want
// to show `0` instead of the formatted `0.0`
return
'
0
'
;
}
return
this
.
formattedUsage
?.
value
;
},
usageUnit
()
{
return
this
.
formattedUsage
?.
unit
;
},
totalValue
()
{
return
this
.
formattedTotal
?.
value
;
},
totalUnit
()
{
return
this
.
formattedTotal
?.
unit
;
},
shouldRenderTotalBlock
()
{
// only show the total block if the used and total storage are not 0
return
this
.
usedStorage
&&
this
.
totalStorage
;
},
},
methods
:
{
formatSizeAndSplit
,
},
};
</
script
>
<
template
>
<div
class=
"gl-bg-white gl-border-1 gl-border-gray-100 gl-border-solid gl-p-5 gl-rounded-base"
data-testid=
"container"
>
<div
class=
"gl-display-flex gl-justify-content-space-between"
>
<p
class=
"gl-font-size-h-display gl-font-weight-bold gl-mb-3"
data-testid=
"denominator"
>
{{
usageValue
}}
<span
class=
"gl-font-lg"
>
{{
usageUnit
}}
</span>
<span
v-if=
"shouldRenderTotalBlock"
data-testid=
"denominator-total"
>
/
{{
totalValue
}}
<span
class=
"gl-font-lg"
>
{{
totalUnit
}}
</span>
</span>
</p>
<div
data-testid=
"actions"
>
<slot
name=
"actions"
></slot>
</div>
</div>
<p
class=
"gl-font-weight-bold"
data-testid=
"description"
>
<slot
name=
"description"
></slot>
</p>
<gl-progress-bar
v-if=
"percentage !== null"
:value=
"percentage"
/>
</div>
</
template
>
ee/app/assets/javascripts/usage_quotas/storage/components/usage_statistics.vue
View file @
af16dd47
<
script
>
import
{
Gl
Icon
,
GlLink
,
Gl
Button
}
from
'
@gitlab/ui
'
;
import
{
GlButton
}
from
'
@gitlab/ui
'
;
import
{
helpPagePath
}
from
'
~/helpers/help_page_helper
'
;
import
{
s__
}
from
'
~/locale
'
;
import
StorageStatisticsCard
from
'
ee/usage_quotas/components/storage_statistics_card.vue
'
;
import
{
formatUsageSize
}
from
'
../utils
'
;
import
UsageStatisticsCard
from
'
./usage_statistics_card.vue
'
;
export
default
{
components
:
{
GlIcon
,
GlLink
,
GlButton
,
Stor
ageStatisticsCard
,
Us
ageStatisticsCard
,
},
inject
:
[
'
purchaseStorageUrl
'
,
'
buyAddonTargetAttr
'
],
props
:
{
...
...
@@ -18,93 +17,115 @@ export default {
type
:
Object
,
},
},
i18n
:
{
purchasedUsageHelpLink
:
helpPagePath
(
'
user/usage_quotas
'
),
purchasedUsageHelpText
:
s__
(
'
UsageQuota|Learn more about usage quotas.
'
),
usedUsageHelpLink
:
helpPagePath
(
'
user/usage_quotas
'
),
usedUsageHelpText
:
s__
(
'
UsageQuota|Learn more about usage quotas.
'
),
purchaseButtonText
:
s__
(
'
UsageQuota|Buy storage
'
),
totalUsageDescription
:
s__
(
'
UsageQuota|Namespace storage used
'
),
},
computed
:
{
usedStorageAmount
()
{
const
{
additionalPurchasedStorageSize
,
actualRepositorySizeLimit
,
totalRepositorySize
,
}
=
this
.
rootStorageStatistics
;
if
(
additionalPurchasedStorageSize
&&
totalRepositorySize
>
actualRepositorySizeLimit
)
{
return
actualRepositorySizeLimit
;
}
return
totalRepositorySize
;
formattedActualRepoSizeLimit
()
{
return
formatUsageSize
(
this
.
rootStorageStatistics
.
actualRepositorySizeLimit
);
},
purchasedUsageDescription
()
{
if
(
this
.
rootStorageStatistics
.
additionalPurchasedStorageSize
)
{
return
s__
(
'
UsageQuota|Purchased storage used
'
);
}
return
s__
(
'
UsageQuota|Purchased storage
'
);
totalUsage
()
{
return
{
usage
:
this
.
formatSizeAndSplit
(
this
.
rootStorageStatistics
.
totalRepositorySize
),
description
:
s__
(
'
UsageQuota|Total namespace storage used
'
),
footerNote
:
s__
(
'
UsageQuota|This is the total amount of storage used across your projects within this namespace.
'
,
),
link
:
{
text
:
`
${
s__
(
'
UsageQuota|Learn more about usage quotas
'
)}
.`
,
url
:
helpPagePath
(
'
user/usage_quotas
'
),
},
};
},
repositorySizeLimit
()
{
return
Number
(
this
.
rootStorageStatistics
.
actualRepositorySizeLimit
);
excessUsage
()
{
return
{
usage
:
this
.
formatSizeAndSplit
(
this
.
rootStorageStatistics
.
totalRepositorySizeExcess
),
description
:
s__
(
'
UsageQuota|Total excess storage used
'
),
footerNote
:
s__
(
'
UsageQuota|This is the total amount of storage used by projects above the free %{actualRepositorySizeLimit} storage limit.
'
,
),
link
:
{
text
:
s__
(
'
UsageQuota|Learn more about excess storage usage
'
),
url
:
helpPagePath
(
'
user/usage_quotas
'
,
{
anchor
:
'
excess-storage-usage
'
}),
},
};
},
purchasedTotalStorage
()
{
return
Number
(
this
.
rootStorageStatistics
.
additionalPurchasedStorageSize
);
purchasedUsage
()
{
const
{
totalRepositorySizeExcess
,
additionalPurchasedStorageSize
,
}
=
this
.
rootStorageStatistics
;
return
this
.
purchaseStorageUrl
?
{
usage
:
this
.
formatSizeAndSplit
(
Math
.
max
(
0
,
additionalPurchasedStorageSize
-
totalRepositorySizeExcess
),
),
usageTotal
:
this
.
formatSizeAndSplit
(
additionalPurchasedStorageSize
),
description
:
s__
(
'
UsageQuota|Purchased storage available
'
),
link
:
{
text
:
s__
(
'
UsageQuota|Purchase more storage
'
),
url
:
this
.
purchaseStorageUrl
,
target
:
this
.
buyAddonTargetAttr
,
},
}
:
null
;
},
purchasedUsedStorage
()
{
// we don't want to show the used value if there's no purchased storage
return
this
.
rootStorageStatistics
.
additionalPurchasedStorageSize
?
Number
(
this
.
rootStorageStatistics
.
totalRepositorySizeExcess
)
:
0
;
},
methods
:
{
/**
* The formatUsageSize method returns
* value along with the unit. However, the unit
* and the value needs to be separated so that
* they can have different styles. The method
* splits the value into value and unit.
*
* @params {Number} size size in bytes
* @returns {Object} value and unit of formatted size
*/
formatSizeAndSplit
(
size
)
{
const
formattedSize
=
formatUsageSize
(
size
);
return
{
value
:
formattedSize
.
slice
(
0
,
-
3
),
unit
:
formattedSize
.
slice
(
-
3
),
};
},
},
};
</
script
>
<
template
>
<div
class=
"gl-display-flex gl-sm-flex-direction-column gl-py-5"
>
<storage-statistics-card
:used-storage=
"usedStorageAmount"
:total-storage=
"repositorySizeLimit"
data-testid=
"namespace-usage-card"
class=
"gl-w-half gl-md-mr-5"
<div
class=
"gl-display-flex gl-sm-flex-direction-column"
>
<usage-statistics-card
data-testid=
"total-usage"
:usage=
"totalUsage.usage"
:link=
"totalUsage.link"
:description=
"totalUsage.description"
css-class=
"gl-mr-4"
/>
<usage-statistics-card
data-testid=
"excess-usage"
:usage=
"excessUsage.usage"
:link=
"excessUsage.link"
:description=
"excessUsage.description"
css-class=
"gl-mx-4"
/>
<usage-statistics-card
v-if=
"purchasedUsage"
data-testid=
"purchased-usage"
:usage=
"purchasedUsage.usage"
:usage-total=
"purchasedUsage.usageTotal"
:link=
"purchasedUsage.link"
:description=
"purchasedUsage.description"
css-class=
"gl-ml-4"
>
<template
#
description
>
{{
$options
.
i18n
.
totalUsageDescription
}}
<gl-link
:href=
"$options.i18n.usedUsageHelpLink
"
target=
"_blank
"
c
lass=
"gl-ml-2
"
:aria-label=
"$options.i18n.usedUsageHelpText"
<template
#
footer
="
{ link }"
>
<gl-button
:target=
"link.target"
:href=
"link.url"
class=
"mb-0
"
variant=
"confirm
"
c
ategory=
"primary
"
block
>
<gl-icon
name=
"question-o"
/>
</gl-link>
</
template
>
</storage-statistics-card>
<storage-statistics-card
v-if=
"purchaseStorageUrl"
:used-storage=
"purchasedUsedStorage"
:total-storage=
"purchasedTotalStorage"
data-testid=
"purchased-usage-card"
class=
"gl-w-half"
>
<
template
#actions
>
<gl-button
:href=
"purchaseStorageUrl"
target=
"_blank"
category=
"primary"
variant=
"confirm"
>
{{
$options
.
i18n
.
purchaseButtonText
}}
{{
link
.
text
}}
</gl-button>
</
template
>
<
template
#description
>
{{
purchasedUsageDescription
}}
<gl-link
:href=
"$options.purchasedUsageHelpLink"
target=
"_blank"
class=
"gl-ml-2"
:aria-label=
"$options.i18n.purchasedUsageHelpText"
>
<gl-icon
name=
"question-o"
/>
</gl-link>
</
template
>
</storage-statistics-card>
</usage-statistics-card>
</div>
</template>
ee/app/assets/javascripts/usage_quotas/storage/components/usage_statistics_card.vue
0 → 100644
View file @
af16dd47
<
script
>
import
{
GlLink
,
GlIcon
,
GlSprintf
}
from
'
@gitlab/ui
'
;
export
default
{
components
:
{
GlIcon
,
GlLink
,
GlSprintf
,
},
props
:
{
link
:
{
type
:
Object
,
required
:
false
,
default
:
()
=>
({
text
:
''
,
url
:
''
}),
},
description
:
{
type
:
String
,
required
:
true
,
},
usage
:
{
type
:
Object
,
required
:
true
,
},
usageTotal
:
{
type
:
Object
,
required
:
false
,
default
:
null
,
},
cssClass
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
},
};
</
script
>
<
template
>
<div
class=
"gl-p-5 gl-my-5 gl-bg-gray-10 gl-flex-grow-1 gl-white-space-nowrap"
:class=
"cssClass"
>
<p
class=
"mb-2"
>
<gl-sprintf
:message=
"__('%
{size} %{unit}')">
<template
#size
>
<span
class=
"gl-font-size-h-display gl-font-weight-bold"
>
{{
usage
.
value
}}
</span>
</
template
>
<
template
#unit
>
<span
class=
"gl-font-lg gl-font-weight-bold"
>
{{
usage
.
unit
}}
</span>
</
template
>
</gl-sprintf>
<
template
v-if=
"usageTotal"
>
<span
class=
"gl-font-size-h-display gl-font-weight-bold"
>
/
</span>
<gl-sprintf
:message=
"__('%
{size} %{unit}')">
<template
#size
>
<span
data-qa-selector=
"purchased_usage_total"
class=
"gl-font-size-h-display gl-font-weight-bold"
>
{{
usageTotal
.
value
}}
</span
>
</
template
>
<
template
#unit
>
<span
class=
"gl-font-lg gl-font-weight-bold"
>
{{
usageTotal
.
unit
}}
</span>
</
template
>
</gl-sprintf>
</template>
</p>
<p
class=
"gl-border-b-2 gl-border-b-solid gl-border-b-gray-100 gl-font-weight-bold gl-pb-3"
>
{{ description }}
</p>
<p
class=
"gl-mb-0 gl-text-gray-900 gl-font-sm gl-white-space-normal"
data-testid=
"statistics-card-footer"
>
<slot
v-bind=
"{ link }"
name=
"footer"
>
<gl-link
target=
"_blank"
:href=
"link.url"
>
<span
class=
"text-truncate"
>
{{ link.text }}
</span>
<gl-icon
name=
"external-link"
class=
"gl-ml-2 gl-flex-shrink-0 gl-text-black-normal"
/>
</gl-link>
</slot>
</p>
</div>
</template>
ee/app/assets/javascripts/usage_quotas/storage/utils.js
View file @
af16dd47
import
{
numberToHumanSize
,
bytesToKiB
}
from
'
~/lib/utils/number_utils
'
;
import
{
gibibytes
,
kibibytes
}
from
'
~/lib/utils/unit_format
'
;
import
{
kibibytes
}
from
'
~/lib/utils/unit_format
'
;
import
{
PROJECT_STORAGE_TYPES
,
STORAGE_USAGE_THRESHOLDS
}
from
'
./constants
'
;
export
function
usageRatioToThresholdLevel
(
currentUsageRatio
)
{
...
...
@@ -19,12 +19,11 @@ export function usageRatioToThresholdLevel(currentUsageRatio) {
* converting bytesToKiB before passing it to
* `getFormatter`
* @param {Number} size size in bytes
* @returns {String}
* @param sizeInBytes
* @param {String} unitSeparator
*/
export
const
formatUsageSize
=
(
sizeInBytes
,
unitSeparator
=
''
)
=>
{
return
kibibytes
(
bytesToKiB
(
sizeInBytes
),
1
,
{
unitSeparator
}
);
export
const
formatUsageSize
=
(
sizeInBytes
)
=>
{
return
kibibytes
(
bytesToKiB
(
sizeInBytes
),
1
);
};
/**
...
...
@@ -188,27 +187,3 @@ export const parseGetProjectStorageResults = (data, helpLinks) => {
export
function
descendingStorageUsageSort
(
storageUsageKey
)
{
return
(
a
,
b
)
=>
b
[
storageUsageKey
]
-
a
[
storageUsageKey
];
}
/**
* The formatUsageSize method returns
* value along with the unit. However, the unit
* and the value needs to be separated so that
* they can have different styles. The method
* splits the value into value and unit.
*
* @params {Number} size size in bytes
* @returns {Object} value and unit of formatted size
*/
export
function
formatSizeAndSplit
(
sizeInBytes
)
{
if
(
sizeInBytes
===
null
)
{
return
null
;
}
/**
* we're using a special separator to help us split the formatted value properly,
* the separator won't be shown in the output
*/
const
unitSeparator
=
'
@
'
;
const
format
=
sizeInBytes
===
0
?
gibibytes
:
kibibytes
;
const
[
value
,
unit
]
=
format
(
bytesToKiB
(
sizeInBytes
),
1
,
{
unitSeparator
}).
split
(
unitSeparator
);
return
{
value
,
unit
};
}
ee/spec/frontend/usage_quotas/components/statistics_card_spec.js
View file @
af16dd47
...
...
@@ -30,6 +30,12 @@ describe('StatisticsCard', () => {
const
findHelpLink
=
()
=>
wrapper
.
findComponent
(
GlLink
);
const
findProgressBar
=
()
=>
wrapper
.
findComponent
(
GlProgressBar
);
it
(
'
passes cssClass to container div
'
,
()
=>
{
const
cssClass
=
'
awesome-css-class
'
;
createComponent
({
cssClass
});
expect
(
wrapper
.
find
(
'
[data-testid="container"]
'
).
classes
()).
toContain
(
cssClass
);
});
describe
(
'
denominator block
'
,
()
=>
{
it
(
'
renders denominator block with all elements when all props are passed
'
,
()
=>
{
createComponent
(
defaultProps
);
...
...
ee/spec/frontend/usage_quotas/components/storage_statistics_card_spec.js
deleted
100644 → 0
View file @
238e5184
import
{
GlProgressBar
}
from
'
@gitlab/ui
'
;
import
{
shallowMountExtended
}
from
'
helpers/vue_test_utils_helper
'
;
import
StorageStatisticsCard
from
'
ee/usage_quotas/components/storage_statistics_card.vue
'
;
describe
(
'
StorageStatisticsCard
'
,
()
=>
{
let
wrapper
;
const
defaultProps
=
{
totalStorage
:
100
*
1024
,
usedStorage
:
50
*
1024
,
};
const
createComponent
=
(
props
=
{})
=>
{
wrapper
=
shallowMountExtended
(
StorageStatisticsCard
,
{
propsData
:
{
...
defaultProps
,
...
props
},
slots
:
{
description
:
'
storage-statistics-card description slot
'
,
actions
:
'
storage-statistics-card actions slot
'
,
},
});
};
const
findDenominatorBlock
=
()
=>
wrapper
.
findByTestId
(
'
denominator
'
);
const
findTotalBlock
=
()
=>
wrapper
.
findByTestId
(
'
denominator-total
'
);
const
findDescriptionBlock
=
()
=>
wrapper
.
findByTestId
(
'
description
'
);
const
findActionsBlock
=
()
=>
wrapper
.
findByTestId
(
'
actions
'
);
const
findProgressBar
=
()
=>
wrapper
.
findComponent
(
GlProgressBar
);
describe
(
'
denominator block
'
,
()
=>
{
it
(
'
renders denominator block with all elements when all props are passed
'
,
()
=>
{
createComponent
();
expect
(
findDenominatorBlock
().
text
()).
toMatchInterpolatedText
(
'
50.0 KiB / 100.0 KiB
'
);
});
it
(
'
does not render total block if totalStorage and usedStorage are not passed
'
,
()
=>
{
createComponent
({
usedStorage
:
null
,
totalStorage
:
null
,
});
expect
(
findTotalBlock
().
exists
()).
toBe
(
false
);
});
it
(
'
renders the denominator block as 0 GiB if totalStorage and usedStorage are passed as 0
'
,
()
=>
{
createComponent
({
usedStorage
:
0
,
totalStorage
:
0
,
});
expect
(
findDenominatorBlock
().
text
()).
toMatchInterpolatedText
(
'
0 GiB
'
);
});
});
describe
(
'
slots
'
,
()
=>
{
it
(
'
renders description slot
'
,
()
=>
{
createComponent
();
expect
(
findDescriptionBlock
().
text
()).
toBe
(
'
storage-statistics-card description slot
'
);
});
it
(
'
renders actions slot
'
,
()
=>
{
createComponent
();
expect
(
findActionsBlock
().
text
()).
toBe
(
'
storage-statistics-card actions slot
'
);
});
});
describe
(
'
progress bar
'
,
()
=>
{
it
(
'
does not render progress bar if there is no totalStorage
'
,
()
=>
{
createComponent
({
totalStorage
:
null
});
expect
(
wrapper
.
findComponent
(
GlProgressBar
).
exists
()).
toBe
(
false
);
});
it
(
'
renders progress bar if percentage is greater than 0
'
,
()
=>
{
createComponent
({
totalStorage
:
10
,
usedStorage
:
5
});
expect
(
findProgressBar
().
exists
()).
toBe
(
true
);
expect
(
findProgressBar
().
attributes
(
'
value
'
)).
toBe
(
String
(
50
));
});
it
(
'
renders the progress bar if percentage is 0
'
,
()
=>
{
createComponent
({
totalStorage
:
10
,
usedStorage
:
0
});
expect
(
findProgressBar
().
exists
()).
toBe
(
true
);
expect
(
findProgressBar
().
attributes
(
'
value
'
)).
toBe
(
String
(
0
));
});
});
});
ee/spec/frontend/usage_quotas/storage/components/usage_statistics_spec.js
View file @
af16dd47
import
{
GlLink
,
GlSprintf
,
GlProgressBar
,
GlButton
}
from
'
@gitlab/ui
'
;
import
{
shallowMountExtended
}
from
'
helpers/vue_test_utils_helper
'
;
import
StorageStatisticsCard
from
'
ee/usage_quotas/components/storage_statistics_card.vue
'
;
import
{
GlButton
,
GlLink
,
GlSprintf
}
from
'
@gitlab/ui
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
UsageStatistics
from
'
ee/usage_quotas/storage/components/usage_statistics.vue
'
;
import
UsageStatisticsCard
from
'
ee/usage_quotas/storage/components/usage_statistics_card.vue
'
;
import
{
withRootStorageStatistics
}
from
'
../mock_data
'
;
describe
(
'
UsageStatistics
'
,
()
=>
{
let
wrapper
;
const
createComponent
=
({
props
=
{},
provide
=
{}
}
=
{})
=>
{
wrapper
=
shallowMount
Extended
(
UsageStatistics
,
{
wrapper
=
shallowMount
(
UsageStatistics
,
{
propsData
:
{
rootStorageStatistics
:
{
totalRepositorySize
:
withRootStorageStatistics
.
totalRepositorySize
,
...
...
@@ -19,15 +19,12 @@ describe('UsageStatistics', () => {
...
props
,
},
provide
:
{
purchaseStorageUrl
:
'
some-fancy-url
'
,
buyAddonTargetAttr
:
'
_self
'
,
...
provide
,
},
stubs
:
{
Stor
ageStatisticsCard
,
Us
ageStatisticsCard
,
GlSprintf
,
GlLink
,
GlProgressBar
,
},
});
};
...
...
@@ -36,124 +33,79 @@ describe('UsageStatistics', () => {
wrapper
.
destroy
();
});
const
findAllStorageStatisticsCards
=
()
=>
wrapper
.
findAllComponents
(
StorageStatisticsCard
);
const
findNamespaceStorageCard
=
()
=>
wrapper
.
findByTestId
(
'
namespace-usage-card
'
);
const
findPurchasedStorageCard
=
()
=>
wrapper
.
findByTestId
(
'
purchased-usage-card
'
);
const
getStatisticsCards
=
()
=>
wrapper
.
findAllComponents
(
UsageStatisticsCard
);
const
getStatisticsCard
=
(
testId
)
=>
wrapper
.
find
(
`[data-testid="
${
testId
}
"]`
);
const
findGlLinkInCard
=
(
cardName
)
=>
getStatisticsCard
(
cardName
)
.
find
(
'
[data-testid="statistics-card-footer"]
'
)
.
findComponent
(
GlLink
);
const
findPurchasedUsageButton
=
()
=>
getStatisticsCard
(
'
purchased-usage
'
).
findComponent
(
GlButton
);
describe
(
'
with purchaseStorageUrl passed
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
();
});
it
(
'
renders two statistics cards
'
,
()
=>
{
expect
(
findAllStorageStatisticsCards
()).
toHaveLength
(
2
);
});
});
describe
(
'
with no purchaseStorageUrl
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
provide
:
{
purchaseStorageUrl
:
null
,
purchaseStorageUrl
:
'
some-fancy-url
'
,
buyAddonTargetAttr
:
'
_self
'
,
},
});
});
it
(
'
renders
on
e statistics cards
'
,
()
=>
{
expect
(
findAllStorageStatisticsCards
()).
toHaveLength
(
1
);
it
(
'
renders
thre
e statistics cards
'
,
()
=>
{
expect
(
getStatisticsCards
()).
toHaveLength
(
3
);
});
});
describe
(
'
namespace storage used
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
();
});
it
(
'
renders URL in total usage card footer
'
,
()
=>
{
const
url
=
findGlLinkInCard
(
'
total-usage
'
);
it
(
'
renders progress bar with correct percentage
'
,
()
=>
{
expect
(
findNamespaceStorageCard
().
findComponent
(
GlProgressBar
).
attributes
(
'
value
'
)).
toBe
(
'
100
'
,
);
expect
(
url
.
attributes
(
'
href
'
)).
toBe
(
'
/help/user/usage_quotas
'
);
});
});
describe
(
'
purchase storage used
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
();
});
afterEach
(()
=>
{
wrapper
.
destroy
();
});
it
(
'
renders the denominator and units correctly
'
,
()
=>
{
expect
(
findPurchasedStorageCard
().
text
().
replace
(
/
\s
+/g
,
'
'
)).
toContain
(
'
2.3 KiB / 0.3 KiB
'
);
});
it
(
'
renders URL in excess usage card footer
'
,
()
=>
{
const
url
=
findGlLinkInCard
(
'
excess-usage
'
);
it
(
'
renders purchase more storage button
'
,
()
=>
{
const
purchaseButton
=
findPurchasedStorageCard
().
findComponent
(
GlButton
);
expect
(
purchaseButton
.
exists
()).
toBe
(
true
);
expect
(
purchaseButton
.
attributes
(
'
href
'
)).
toBe
(
'
some-fancy-url
'
);
expect
(
url
.
attributes
(
'
href
'
)).
toBe
(
'
/help/user/usage_quotas#excess-storage-usage
'
);
});
it
(
'
renders the percentage bar
'
,
()
=>
{
expect
(
findPurchasedStorageCard
().
findComponent
(
GlProgressBar
).
attributes
(
'
value
'
)).
toBe
(
'
100
'
,
);
it
(
'
renders button in purchased usage card footer with correct link
'
,
()
=>
{
expect
(
findPurchasedUsageButton
().
attributes
()).
toMatchObject
({
href
:
'
some-fancy-url
'
,
target
:
'
_self
'
,
});
});
});
describe
(
'
when limit is exceeded
'
,
()
=>
{
describe
(
'
with purchased storage
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
props
:
{
rootStorageStatistics
:
{
totalRepositorySize
:
60
*
1024
,
actualRepositorySizeLimit
:
50
*
1024
,
totalRepositorySizeExcess
:
1024
,
additionalPurchasedStorageSize
:
10
*
1024
,
},
},
});
});
it
(
'
shows only the limit in the namespace storage card
'
,
()
=>
{
expect
(
findNamespaceStorageCard
().
text
().
replace
(
/
\s
+/g
,
'
'
)).
toContain
(
'
50.0 KiB / 50.0 KiB
'
,
);
});
it
(
'
shows the excess amount in the purchased storage card
'
,
()
=>
{
expect
(
findPurchasedStorageCard
().
text
().
replace
(
/
\s
+/g
,
'
'
)).
toContain
(
'
1.0 KiB / 10.0 KiB
'
,
);
describe
(
'
with buyAddonTargetAttr passed as _blank
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
provide
:
{
purchaseStorageUrl
:
'
some-fancy-url
'
,
buyAddonTargetAttr
:
'
_blank
'
,
},
});
});
describe
(
'
without purchased storage
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
props
:
{
rootStorageStatistics
:
{
totalRepositorySize
:
502642
,
actualRepositorySizeLimit
:
500321
,
totalRepositorySizeExcess
:
2321
,
additionalPurchasedStorageSize
:
0
,
},
},
});
it
(
'
renders button in purchased usage card footer with correct target
'
,
()
=>
{
expect
(
findPurchasedUsageButton
().
attributes
()).
toMatchObject
({
href
:
'
some-fancy-url
'
,
target
:
'
_blank
'
,
});
});
});
it
(
'
shows the total of limit and excess in the namespace storage card
'
,
()
=>
{
expect
(
findNamespaceStorageCard
().
text
().
replace
(
/
\s
+/g
,
'
'
)).
toContain
(
'
490.9 KiB / 488.6 KiB
'
,
);
describe
(
'
with no purchaseStorageUrl
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
provide
:
{
purchaseStorageUrl
:
null
,
buyAddonTargetAttr
:
'
_self
'
,
},
});
});
it
(
'
shows 0 GiB in the purchased storage card
'
,
()
=>
{
expect
(
findPurchasedStorageCard
().
text
().
replace
(
/
\s
+/g
,
'
'
)).
toContain
(
'
0 GiB
'
);
});
it
(
'
does not render purchased usage card if purchaseStorageUrl is not provided
'
,
()
=>
{
expect
(
getStatisticsCard
(
'
purchased-usage
'
).
exists
()).
toBe
(
false
);
});
});
});
ee/spec/frontend/usage_quotas/storage/utils_spec.js
View file @
af16dd47
...
...
@@ -5,7 +5,6 @@ import {
calculateUsedAndRemStorage
,
parseGetProjectStorageResults
,
descendingStorageUsageSort
,
formatSizeAndSplit
,
}
from
'
ee/usage_quotas/storage/utils
'
;
import
{
projectData
,
...
...
@@ -79,11 +78,6 @@ describe('formatUsageSize', () => {
`
(
'
returns $expected from $input
'
,
({
input
,
expected
})
=>
{
expect
(
formatUsageSize
(
input
)).
toBe
(
expected
);
});
it
(
'
render the output with unit separator when unitSeparator param is passed
'
,
()
=>
{
expect
(
formatUsageSize
(
1000
,
'
-
'
)).
toBe
(
'
1.0-KiB
'
);
expect
(
formatUsageSize
(
1000
,
'
'
)).
toBe
(
'
1.0 KiB
'
);
});
});
describe
(
'
calculateUsedAndRemStorage
'
,
()
=>
{
...
...
@@ -138,13 +132,3 @@ describe('descendingStorageUsageSort', () => {
expect
(
sorted
).
toEqual
(
expectedSorted
);
});
});
describe
(
'
formatSizeAndSplit
'
,
()
=>
{
it
(
'
returns null if passed parameter is null
'
,
()
=>
{
expect
(
formatSizeAndSplit
(
null
)).
toBe
(
null
);
});
it
(
'
returns formatted size as object { value, unit }
'
,
()
=>
{
expect
(
formatSizeAndSplit
(
1000
)).
toEqual
({
value
:
'
1.0
'
,
unit
:
'
KiB
'
});
});
});
locale/gitlab.pot
View file @
af16dd47
...
...
@@ -969,6 +969,9 @@ msgstr[1] ""
msgid "%{service_ping_link_start}What information is shared with GitLab Inc.?%{service_ping_link_end}"
msgstr ""
msgid "%{size} %{unit}"
msgstr ""
msgid "%{size} GiB"
msgstr ""
...
...
@@ -40507,9 +40510,6 @@ msgstr ""
msgid "UsageQuota|Buy additional minutes"
msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
msgid "UsageQuota|CI minutes usage by month"
msgstr ""
...
...
@@ -40540,10 +40540,10 @@ msgstr ""
msgid "UsageQuota|LFS storage"
msgstr ""
msgid "UsageQuota|Learn more about
usage quotas.
"
msgid "UsageQuota|Learn more about
excess storage usage
"
msgstr ""
msgid "UsageQuota|
Namespace storage used
"
msgid "UsageQuota|
Learn more about usage quotas
"
msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
...
...
@@ -40564,10 +40564,7 @@ msgstr ""
msgid "UsageQuota|Purchase more storage"
msgstr ""
msgid "UsageQuota|Purchased storage"
msgstr ""
msgid "UsageQuota|Purchased storage used"
msgid "UsageQuota|Purchased storage available"
msgstr ""
msgid "UsageQuota|Repository"
...
...
@@ -40594,12 +40591,24 @@ msgstr ""
msgid "UsageQuota|Storage used"
msgstr ""
msgid "UsageQuota|This is the total amount of storage used across your projects within this namespace."
msgstr ""
msgid "UsageQuota|This is the total amount of storage used by projects above the free %{actualRepositorySizeLimit} storage limit."
msgstr ""
msgid "UsageQuota|This namespace contains locked projects"
msgstr ""
msgid "UsageQuota|This namespace has no projects which use shared runners"
msgstr ""
msgid "UsageQuota|Total excess storage used"
msgstr ""
msgid "UsageQuota|Total namespace storage used"
msgstr ""
msgid "UsageQuota|Unlimited"
msgstr ""
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment