mirror of
https://github.com/quay/quay.git
synced 2026-01-26 06:21:37 +03:00
[redhat-3.16] fix(ui): display quota consumed for organizations and user namespaces (PROJQUAY-9641) (#4437)
fix(ui): display quota consumed for organizations and user namespaces (PROJQUAY-9641) superusers can now see quota consumed data in the organizations list for both organizations and user namespaces. the fix preserves quota_report data from the /api/v1/superuser/organizations/ endpoint instead of discarding it. Signed-off-by: Brady Pratt <bpratt@redhat.com> Co-authored-by: Brady Pratt <bpratt@redhat.com> Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
committed by
GitHub
parent
6285f01d5a
commit
d13b11796a
@@ -135,4 +135,111 @@ describe('Org List Page', () => {
|
||||
cy.get('td[data-label="Name"]').should('have.length', 20);
|
||||
cy.contains('1 - 20 of 30').should('exist');
|
||||
});
|
||||
|
||||
it('Superuser displays quota consumed column (PROJQUAY-9641)', () => {
|
||||
// This test verifies that superusers can see quota consumed data
|
||||
// for organizations and user namespaces in the organizations list
|
||||
|
||||
// Mock config with quota features enabled
|
||||
cy.fixture('config.json').then((config) => {
|
||||
config.features.QUOTA_MANAGEMENT = true;
|
||||
config.features.EDIT_QUOTA = true;
|
||||
config.features.SUPER_USERS = true;
|
||||
config.features.SUPERUSERS_FULL_ACCESS = true;
|
||||
cy.intercept('GET', '/config', config).as('getConfig');
|
||||
});
|
||||
|
||||
// Mock superuser
|
||||
cy.fixture('superuser.json').then((user) => {
|
||||
cy.intercept('GET', '/api/v1/user/', user).as('getSuperUser');
|
||||
});
|
||||
|
||||
// Mock superuser organizations with quota_report data
|
||||
cy.fixture('superuser-organizations.json').then((orgsData) => {
|
||||
// Add quota_report to organizations
|
||||
orgsData.organizations[0].quota_report = {
|
||||
quota_bytes: 10737418240,
|
||||
configured_quota: 53687091200,
|
||||
};
|
||||
orgsData.organizations[1].quota_report = {
|
||||
quota_bytes: 5368709120,
|
||||
configured_quota: 21474836480,
|
||||
};
|
||||
cy.intercept('GET', '/api/v1/superuser/organizations/', orgsData).as(
|
||||
'getSuperuserOrganizations',
|
||||
);
|
||||
});
|
||||
|
||||
// Mock superuser users with quota_report data
|
||||
cy.fixture('superuser-users.json').then((usersData) => {
|
||||
// Add quota_report to users
|
||||
usersData.users[0].quota_report = {
|
||||
quota_bytes: 2147483648,
|
||||
configured_quota: 10737418240,
|
||||
};
|
||||
cy.intercept('GET', '/api/v1/superuser/users/', usersData).as(
|
||||
'getSuperuserUsers',
|
||||
);
|
||||
});
|
||||
|
||||
// Mock organization details
|
||||
cy.intercept('GET', '/api/v1/organization/testorg', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
name: 'testorg',
|
||||
email: 'testorg@example.com',
|
||||
teams: {owners: 'admin'},
|
||||
},
|
||||
});
|
||||
|
||||
cy.intercept('GET', '/api/v1/organization/projectquay', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
name: 'projectquay',
|
||||
email: 'projectquay@example.com',
|
||||
teams: {},
|
||||
},
|
||||
});
|
||||
|
||||
cy.intercept('GET', '/api/v1/organization/coreos', {
|
||||
statusCode: 200,
|
||||
body: {
|
||||
name: 'coreos',
|
||||
email: 'coreos@example.com',
|
||||
teams: {owners: 'admin'},
|
||||
},
|
||||
});
|
||||
|
||||
// Mock robots/members/repositories for all organizations
|
||||
cy.intercept('GET', '/api/v1/organization/*/robots', {
|
||||
statusCode: 200,
|
||||
body: {robots: []},
|
||||
});
|
||||
|
||||
cy.intercept('GET', '/api/v1/organization/*/members', {
|
||||
statusCode: 200,
|
||||
body: {members: []},
|
||||
});
|
||||
|
||||
cy.intercept('GET', '/api/v1/repository?namespace=*', {
|
||||
statusCode: 200,
|
||||
body: {repositories: []},
|
||||
});
|
||||
|
||||
cy.visit('/organization');
|
||||
cy.wait('@getConfig');
|
||||
cy.wait('@getSuperUser');
|
||||
cy.wait('@getSuperuserOrganizations');
|
||||
cy.wait('@getSuperuserUsers');
|
||||
|
||||
// Verify the Size column header exists for superusers
|
||||
cy.contains('th', 'Size').should('exist');
|
||||
|
||||
// Verify quota data cells are visible and contain actual data
|
||||
cy.get('td[data-label="Size"]').should('exist');
|
||||
|
||||
// Verify at least one organization shows quota consumed data (not "—")
|
||||
// The quota should be displayed as "10.0 GiB / 50.0 GiB" format
|
||||
cy.get('td[data-label="Size"]').first().should('not.contain.text', '—');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
searchOrgsState,
|
||||
} from 'src/atoms/OrganizationListState';
|
||||
import {SearchState} from 'src/components/toolbar/SearchTypes';
|
||||
import {IQuotaReport} from 'src/libs/quotaUtils';
|
||||
import {
|
||||
bulkDeleteOrganizations,
|
||||
createOrg,
|
||||
@@ -19,6 +20,7 @@ export type OrganizationDetail = {
|
||||
isUser: boolean;
|
||||
userEnabled?: boolean;
|
||||
userSuperuser?: boolean;
|
||||
quota_report?: IQuotaReport;
|
||||
};
|
||||
|
||||
export function useOrganizations() {
|
||||
@@ -68,19 +70,25 @@ export function useOrganizations() {
|
||||
|
||||
const organizationsTableDetails = [] as OrganizationDetail[];
|
||||
for (const orgname of orgnames) {
|
||||
// Find the organization object to get quota_report
|
||||
const orgObj = (superUserOrganizations || []).find(
|
||||
(o) => o.name === orgname,
|
||||
);
|
||||
organizationsTableDetails.push({
|
||||
name: orgname,
|
||||
isUser: false,
|
||||
quota_report: orgObj?.quota_report,
|
||||
});
|
||||
}
|
||||
for (const username of usernames) {
|
||||
// Find the user's enabled status from superUserUsers
|
||||
// Find the user's enabled status and quota_report from superUserUsers
|
||||
const userObj = (superUserUsers || []).find((u) => u.username === username);
|
||||
organizationsTableDetails.push({
|
||||
name: username,
|
||||
isUser: true,
|
||||
userEnabled: userObj?.enabled,
|
||||
userSuperuser: userObj?.super_user,
|
||||
quota_report: userObj?.quota_report,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -480,6 +480,7 @@ export default function OrganizationsList() {
|
||||
userEnabled={org.userEnabled}
|
||||
userSuperuser={org.userSuperuser}
|
||||
userEmail={org.isUser ? userEmailMap[org.name] : undefined}
|
||||
quota_report={org.quota_report}
|
||||
></OrgTableData>
|
||||
</Tr>
|
||||
))}
|
||||
|
||||
@@ -43,6 +43,7 @@ function RepoLastModifiedDate(props: RepoLastModifiedDateProps) {
|
||||
|
||||
interface OrgTableDataProps extends OrganizationsTableItem {
|
||||
userEmail?: string;
|
||||
quota_report?: import('src/libs/quotaUtils').IQuotaReport;
|
||||
}
|
||||
|
||||
// Get and assemble data from multiple endpoints to show in Org table
|
||||
@@ -182,13 +183,24 @@ export default function OrgTableData(props: OrgTableDataProps) {
|
||||
config?.features?.EDIT_QUOTA && (
|
||||
<Td dataLabel={ColumnNames.size}>
|
||||
{props.isUser ? (
|
||||
<span style={{color: '#888'}}>—</span>
|
||||
props.quota_report ? (
|
||||
renderQuotaConsumed(props.quota_report, {
|
||||
showPercentage: true,
|
||||
showTotal: true,
|
||||
showBackfill: true,
|
||||
})
|
||||
) : (
|
||||
<span style={{color: '#888'}}>—</span>
|
||||
)
|
||||
) : (
|
||||
renderQuotaConsumed(organization?.quota_report, {
|
||||
showPercentage: true,
|
||||
showTotal: true,
|
||||
showBackfill: true,
|
||||
})
|
||||
renderQuotaConsumed(
|
||||
props.quota_report || organization?.quota_report,
|
||||
{
|
||||
showPercentage: true,
|
||||
showTotal: true,
|
||||
showBackfill: true,
|
||||
},
|
||||
)
|
||||
)}
|
||||
</Td>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user