-
+
+ {canListCRQ && (
+
+
+
+ )}
+
+
+
+
+
+
+
{scopes && (
@@ -304,12 +603,27 @@ const Details = ({ obj: rq }) => {
{t('public~Resource type')}
{t('public~Capacity')}
-
{t('public~Used')}
-
{t('public~Max')}
+
+ {t('public~Used')}
+
+ {isACRQ &&
{t('public~Total used')}
}
+
+ {t('public~Max')}
+
{resourceTypes.map((type) => (
-
+
))}
@@ -318,15 +632,20 @@ const Details = ({ obj: rq }) => {
);
};
-const ResourceQuotaTableRow = ({ obj: rq }) => {
+const ResourceQuotaTableRow = ({ obj: rq, customData }) => {
const { t } = useTranslation();
+ const actions = quotaActions(rq, customData);
return (
<>
@@ -340,8 +659,61 @@ const ResourceQuotaTableRow = ({ obj: rq }) => {
t('public~None')
)}
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+const AppliedClusterResourceQuotaTableRow = ({ obj: rq, customData }) => {
+ const actions = quotaActions(rq, customData);
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
>
);
@@ -365,18 +737,83 @@ export const ResourceQuotasList = (props) => {
id: 'namespace',
},
{
- title: '',
+ title: t('public~Label selector'),
+ sortField: 'spec.selector.labels.matchLabels',
+ transforms: [sortable],
props: { className: tableColumnClasses[2] },
},
+ {
+ title: t('public~Project annotations'),
+ sortField: 'spec.selector.annotations',
+ transforms: [sortable],
+ props: { className: tableColumnClasses[3] },
+ },
+ {
+ title: t('public~Created'),
+ sortField: 'metadata.creationTimestamp',
+ transforms: [sortable],
+ props: { className: tableColumnClasses[4] },
+ },
+ {
+ title: '',
+ props: { className: tableColumnClasses[5] },
+ },
];
};
return (
+ );
+};
+
+export const AppliedClusterResourceQuotasList = (props) => {
+ const { t } = useTranslation();
+ const AppliedClusterResourceQuotaTableHeader = () => {
+ return [
+ {
+ title: t('public~Name'),
+ sortField: 'metadata.name',
+ transforms: [sortable],
+ props: { className: acrqTableColumnClasses[0] },
+ },
+ {
+ title: t('public~Label selector'),
+ sortField: 'spec.selector.labels.matchLabels',
+ transforms: [sortable],
+ props: { className: acrqTableColumnClasses[1] },
+ },
+ {
+ title: t('public~Project annotations'),
+ sortField: 'spec.selector.annotations',
+ transforms: [sortable],
+ props: { className: acrqTableColumnClasses[2] },
+ },
+ {
+ title: t('public~Created'),
+ sortField: 'metadata.creationTimestamp',
+ transforms: [sortable],
+ props: { className: acrqTableColumnClasses[3] },
+ },
+ {
+ title: '',
+ props: { className: acrqTableColumnClasses[4] },
+ },
+ ];
+ };
+ return (
+
);
};
@@ -401,11 +838,21 @@ export const ResourceQuotasPage = connectToFlags(FLAGS.OPENSHIFT)(
return ;
}
if (flags[FLAGS.OPENSHIFT]) {
- resources.push({
- kind: referenceForModel(ClusterResourceQuotaModel),
- namespaced: false,
- optional: true,
- });
+ if (!namespace) {
+ resources.push({
+ kind: referenceForModel(ClusterResourceQuotaModel),
+ namespaced: false,
+ optional: true,
+ });
+ } else {
+ resources.push({
+ kind: referenceForModel(AppliedClusterResourceQuotaModel),
+ namespaced: true,
+ namespace,
+ optional: true,
+ });
+ }
+
rowFilters = [
{
filterGroupName: t('public~Role'),
@@ -415,13 +862,13 @@ export const ResourceQuotasPage = connectToFlags(FLAGS.OPENSHIFT)(
{
id: 'cluster',
title: t('public~Cluster-wide {{resource}}', {
- resource: ResourceQuotaModel.labelPlural,
+ resource: t(ResourceQuotaModel.labelPluralKey),
}),
},
{
id: 'namespace',
title: t('public~Namespace {{resource}}', {
- resource: ResourceQuotaModel.labelPlural,
+ resource: t(ResourceQuotaModel.labelPluralKey),
}),
},
],
@@ -453,10 +900,49 @@ export const ResourceQuotasPage = connectToFlags(FLAGS.OPENSHIFT)(
},
);
-export const ResourceQuotasDetailsPage = (props) => (
-
-);
+export const AppliedClusterResourceQuotasPage = ({ namespace, mock, showTitle }) => {
+ const { t } = useTranslation();
+ const resources = [
+ {
+ kind: referenceForModel(AppliedClusterResourceQuotaModel),
+ namespaced: true,
+ namespace,
+ optional: true,
+ },
+ ];
+
+ return (
+
+ );
+};
+
+export const ResourceQuotasDetailsPage = (props) => {
+ return (
+
+ );
+};
+
+export const AppliedClusterResourceQuotasDetailsPage = (props) => {
+ const { match } = props;
+ const actions = appliedClusterResourceQuotaMenuActions(match?.params?.ns);
+ return (
+
+ );
+};
diff --git a/frontend/public/locales/en/public.json b/frontend/public/locales/en/public.json
index 9faa87808c1..c2e12e0da30 100644
--- a/frontend/public/locales/en/public.json
+++ b/frontend/public/locales/en/public.json
@@ -399,6 +399,7 @@
"Inventory": "Inventory",
"Launcher": "Launcher",
"ResourceQuotas": "ResourceQuotas",
+ "No AppliedClusterResourceQuotas": "No AppliedClusterResourceQuotas",
"Utilization": "Utilization",
"{{kindLabel}} details": "{{kindLabel}} details",
"Start rollout": "Start rollout",
@@ -525,9 +526,10 @@
"Manage columns": "Manage columns",
"Column management": "Column management",
"{{value}} at {{date}}": "{{value}} at {{date}}",
- "Loading": "Loading",
"used": "used",
"No data": "No data",
+ "{{x}}: {{y}}%": "{{x}}: {{y}}%",
+ "Loading": "Loading",
"available": "available",
"No datapoints found.": "No datapoints found.",
"total limit": "total limit",
@@ -1332,22 +1334,32 @@
"{{statusReplicas}} of {{specReplicas}} pods": "{{statusReplicas}} of {{specReplicas}} pods",
"Tech Preview": "Tech Preview",
"Select Resource": "Select Resource",
+ "Edit AppliedClusterResourceQuota": "Edit AppliedClusterResourceQuota",
"No quota": "No quota",
+ "Percentage of CPU used by current namespace vs. other namespaces": "Percentage of CPU used by current namespace vs. other namespaces",
"CPU request": "CPU request",
+ "Percentage of CPU limit used by current namespace vs. other namespaces": "Percentage of CPU limit used by current namespace vs. other namespaces",
"CPU limit": "CPU limit",
+ "Percentage of memory requests used by current namespace vs. other namespaces": "Percentage of memory requests used by current namespace vs. other namespaces",
"Memory request": "Memory request",
+ "Percentage of memory limits used by current namespace vs. other namespaces": "Percentage of memory limits used by current namespace vs. other namespaces",
"Memory limit": "Memory limit",
"Affects pods that have an active deadline. These pods usually include builds, deployers, and jobs.": "Affects pods that have an active deadline. These pods usually include builds, deployers, and jobs.",
"Affects pods that do not have an active deadline. These pods usually include your applications.": "Affects pods that do not have an active deadline. These pods usually include your applications.",
"Affects pods that do not have resource limits set. These pods have a best effort quality of service.": "Affects pods that do not have resource limits set. These pods have a best effort quality of service.",
"Affects pods that have at least one resource limit set. These pods do not have a best effort quality of service.": "Affects pods that have at least one resource limit set. These pods do not have a best effort quality of service.",
+ "AppliedClusterResourceQuota details": "AppliedClusterResourceQuota details",
"ClusterResourceQuota details": "ClusterResourceQuota details",
"ResourceQuota details": "ResourceQuota details",
+ "ClusterResourceQuota": "ClusterResourceQuota",
+ "Project annotations": "Project annotations",
"Scopes": "Scopes",
"Requests are the amount of resources you expect to use. These are used when establishing if the cluster can fulfill your Request.": "Requests are the amount of resources you expect to use. These are used when establishing if the cluster can fulfill your Request.",
"Limits are a maximum amount of a resource you can consume. Applications consuming more than the Limit may be terminated.": "Limits are a maximum amount of a resource you can consume. Applications consuming more than the Limit may be terminated.",
"A cluster administrator can establish limits on both the amount you can request and your limits with a ResourceQuota.": "A cluster administrator can establish limits on both the amount you can request and your limits with a ResourceQuota.",
"Resource type": "Resource type",
+ "Total used": "Total used",
+ "AppliedClusterResourceQuotas": "AppliedClusterResourceQuotas",
"Cluster-wide {{resource}}": "Cluster-wide {{resource}}",
"Namespace {{resource}}": "Namespace {{resource}}",
"Create ResourceQuota": "Create ResourceQuota",
@@ -1730,8 +1742,8 @@
"PersistentVolume": "PersistentVolume",
"StatefulSet": "StatefulSet",
"ResourceQuota": "ResourceQuota",
- "ClusterResourceQuota": "ClusterResourceQuota",
"ClusterResourceQuotas": "ClusterResourceQuotas",
+ "AppliedClusterResourceQuota": "AppliedClusterResourceQuota",
"NetworkPolicy": "NetworkPolicy",
"CustomResourceDefinition": "CustomResourceDefinition",
"CronJob": "CronJob",
diff --git a/frontend/public/models/index.ts b/frontend/public/models/index.ts
index 09fdd3d846d..761876dc1f7 100644
--- a/frontend/public/models/index.ts
+++ b/frontend/public/models/index.ts
@@ -724,6 +724,23 @@ export const ClusterResourceQuotaModel: K8sKind = {
crd: true,
};
+export const AppliedClusterResourceQuotaModel: K8sKind = {
+ label: 'AppliedClusterResourceQuota',
+ // t('public~AppliedClusterResourceQuota')
+ labelKey: 'public~AppliedClusterResourceQuota',
+ apiGroup: 'quota.openshift.io',
+ apiVersion: 'v1',
+ plural: 'appliedclusterresourcequotas',
+ abbr: 'ACRQ',
+ namespaced: true,
+ kind: 'AppliedClusterResourceQuota',
+ id: 'appliedclusterresourcequota',
+ labelPlural: 'AppliedClusterResourceQuotas',
+ // t('public~AppliedClusterResourceQuotas')
+ labelPluralKey: 'public~AppliedClusterResourceQuotas',
+ crd: true,
+};
+
export const NetworkPolicyModel: K8sKind = {
label: 'NetworkPolicy',
// t('public~NetworkPolicy')
diff --git a/frontend/public/module/k8s/types.ts b/frontend/public/module/k8s/types.ts
index 115c1a43820..01c3639ce86 100644
--- a/frontend/public/module/k8s/types.ts
+++ b/frontend/public/module/k8s/types.ts
@@ -62,7 +62,6 @@ export type Toleration = {
// or status, weakening type checking.
export type K8sResourceKind = K8sResourceCommon & {
spec?: {
- selector?: Selector | MatchLabels;
[key: string]: any;
};
status?: { [key: string]: any };
@@ -326,6 +325,29 @@ export type DeploymentKind = {
};
} & K8sResourceCommon;
+export type AppliedClusterResourceQuotaKind = {
+ spec?: {
+ selector?: {
+ labels?: Selector;
+ annotations?: MatchLabels;
+ };
+ quota?: {
+ hard?: { [key: string]: number };
+ scopes?: string[];
+ scopeSelector?: {
+ matchExpressions?: { scopeName: string; operator: string; values?: string[] }[];
+ };
+ };
+ };
+ status?: {
+ namespaces?: {
+ namespace: string;
+ status: { used?: { [key: string]: number }; hard?: { [key: string]: number } };
+ }[];
+ total?: { hard?: { [key: string]: number }; used?: { [key: string]: number } };
+ };
+} & K8sResourceCommon;
+
type CurrentObject = {
averageUtilization?: number;
averageValue?: string;