mirror of
https://github.com/ansible/awx.git
synced 2026-01-11 01:57:35 -03:30
Enhanced detail component (#12432)
* Enhanced detail component to handle cases with no values, and refactored components that use detail component. * Add optional chaining operators where necessary to pass test cases * add test cases to test suites of modified files Co-authored-by: Veda Periwal <vperiwal@vperiwal-mac.attlocal.net>
This commit is contained in:
parent
54057f1c80
commit
71925de902
@ -41,6 +41,7 @@ const Detail = ({
|
||||
className,
|
||||
dataCy,
|
||||
alwaysVisible,
|
||||
isEmpty,
|
||||
helpText,
|
||||
isEncrypted,
|
||||
isNotConfigured,
|
||||
@ -49,6 +50,10 @@ const Detail = ({
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isEmpty && !alwaysVisible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const labelCy = dataCy ? `${dataCy}-label` : null;
|
||||
const valueCy = dataCy ? `${dataCy}-value` : null;
|
||||
|
||||
|
||||
@ -163,16 +163,16 @@ function JobListItem({
|
||||
<Td colSpan={showTypeColumn ? 6 : 5}>
|
||||
<ExpandableRowContent>
|
||||
<DetailList>
|
||||
{job.type === 'inventory_update' &&
|
||||
inventorySourceLabels.length > 0 && (
|
||||
<Detail
|
||||
dataCy="job-inventory-source-type"
|
||||
label={t`Source`}
|
||||
value={inventorySourceLabels.map(([string, label]) =>
|
||||
string === job.source ? label : null
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{job.type === 'inventory_update' && (
|
||||
<Detail
|
||||
dataCy="job-inventory-source-type"
|
||||
label={t`Source`}
|
||||
value={inventorySourceLabels?.map(([string, label]) =>
|
||||
string === job.source ? label : null
|
||||
)}
|
||||
isEmpty={inventorySourceLabels?.length === 0}
|
||||
/>
|
||||
)}
|
||||
<LaunchedByDetail job={job} />
|
||||
{job.launch_type === 'scheduled' &&
|
||||
(schedule ? (
|
||||
@ -254,7 +254,7 @@ function JobListItem({
|
||||
dataCy={`execution-environment-detail-${job.id}`}
|
||||
/>
|
||||
)}
|
||||
{credentials && credentials.length > 0 && (
|
||||
{credentials && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Credentials`}
|
||||
@ -275,6 +275,7 @@ function JobListItem({
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={credentials.length === 0}
|
||||
/>
|
||||
)}
|
||||
{labels && labels.count > 0 && (
|
||||
|
||||
@ -203,6 +203,49 @@ describe('<JobListItem />', () => {
|
||||
wrapper.find('Detail[label="Execution Environment"] dd').text()
|
||||
).toBe('Missing resource');
|
||||
});
|
||||
|
||||
test('should not load Source', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<table>
|
||||
<tbody>
|
||||
<JobListItem
|
||||
inventorySourceLabels={[]}
|
||||
job={{
|
||||
...mockJob,
|
||||
type: 'inventory_update',
|
||||
summary_fields: {
|
||||
user_capabilities: {},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
const source_detail = wrapper.find(`Detail[label="Source"]`).at(0);
|
||||
expect(source_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should not load Credentials', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<table>
|
||||
<tbody>
|
||||
<JobListItem
|
||||
job={{
|
||||
...mockJob,
|
||||
type: 'inventory_update',
|
||||
summary_fields: {
|
||||
credentials: [],
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
const credentials_detail = wrapper
|
||||
.find(`Detail[label="Credentials"]`)
|
||||
.at(0);
|
||||
expect(credentials_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('<JobListItem with failed job />', () => {
|
||||
|
||||
@ -113,15 +113,14 @@ function PromptInventorySourceDetail({ resource }) {
|
||||
label={t`Cache Timeout`}
|
||||
value={`${update_cache_timeout} ${t`Seconds`}`}
|
||||
/>
|
||||
{summary_fields?.credentials?.length > 0 && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Credential`}
|
||||
value={summary_fields.credentials.map((cred) => (
|
||||
<CredentialChip key={cred?.id} credential={cred} isReadOnly />
|
||||
))}
|
||||
/>
|
||||
)}
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Credential`}
|
||||
value={summary_fields?.credentials?.map((cred) => (
|
||||
<CredentialChip key={cred?.id} credential={cred} isReadOnly />
|
||||
))}
|
||||
isEmpty={summary_fields?.credentials?.length === 0}
|
||||
/>
|
||||
{source_regions && (
|
||||
<Detail
|
||||
fullWidth
|
||||
|
||||
@ -79,4 +79,19 @@ describe('PromptInventorySourceDetail', () => {
|
||||
);
|
||||
assertDetail(wrapper, 'Organization', 'Deleted');
|
||||
});
|
||||
|
||||
test('should not load Credentials', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<PromptInventorySourceDetail
|
||||
resource={{
|
||||
...mockInvSource,
|
||||
summary_fields: {
|
||||
credentials: [],
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
const credentials_detail = wrapper.find(`Detail[label="Credential"]`).at(0);
|
||||
expect(credentials_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
@ -26,7 +26,7 @@ function PromptJobTemplateDetail({ resource }) {
|
||||
extra_vars,
|
||||
forks,
|
||||
host_config_key,
|
||||
instance_groups,
|
||||
instance_groups = [],
|
||||
job_slice_count,
|
||||
job_tags,
|
||||
job_type,
|
||||
@ -94,9 +94,11 @@ function PromptJobTemplateDetail({ resource }) {
|
||||
|
||||
return (
|
||||
<>
|
||||
{summary_fields.recent_jobs?.length > 0 && (
|
||||
<Detail value={<Sparkline jobs={recentJobs} />} label={t`Activity`} />
|
||||
)}
|
||||
<Detail
|
||||
label={t`Activity`}
|
||||
value={<Sparkline jobs={recentJobs} />}
|
||||
isEmpty={summary_fields.recent_jobs?.length === 0}
|
||||
/>
|
||||
<Detail label={t`Job Type`} value={toTitleCase(job_type)} />
|
||||
{summary_fields?.organization ? (
|
||||
<Detail
|
||||
@ -180,7 +182,7 @@ function PromptJobTemplateDetail({ resource }) {
|
||||
/>
|
||||
)}
|
||||
{optionsList && <Detail label={t`Enabled Options`} value={optionsList} />}
|
||||
{summary_fields?.credentials?.length > 0 && (
|
||||
{summary_fields?.credentials && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Credentials`}
|
||||
@ -195,9 +197,10 @@ function PromptJobTemplateDetail({ resource }) {
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={summary_fields?.credentials?.length === 0}
|
||||
/>
|
||||
)}
|
||||
{summary_fields?.labels?.results?.length > 0 && (
|
||||
{summary_fields?.labels?.results && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Labels`}
|
||||
@ -214,28 +217,28 @@ function PromptJobTemplateDetail({ resource }) {
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={summary_fields?.labels?.results?.length === 0}
|
||||
/>
|
||||
)}
|
||||
{instance_groups?.length > 0 && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Instance Groups`}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={5}
|
||||
totalChips={instance_groups.length}
|
||||
ouiaId="prompt-jt-instance-group-chips"
|
||||
>
|
||||
{instance_groups.map((ig) => (
|
||||
<Chip key={ig.id} isReadOnly>
|
||||
{ig.name}
|
||||
</Chip>
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{job_tags?.length > 0 && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Instance Groups`}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={5}
|
||||
totalChips={instance_groups?.length}
|
||||
ouiaId="prompt-jt-instance-group-chips"
|
||||
>
|
||||
{instance_groups?.map((ig) => (
|
||||
<Chip key={ig.id} isReadOnly>
|
||||
{ig.name}
|
||||
</Chip>
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={instance_groups?.length === 0}
|
||||
/>
|
||||
{job_tags && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Job Tags`}
|
||||
@ -252,9 +255,10 @@ function PromptJobTemplateDetail({ resource }) {
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={job_tags?.length === 0}
|
||||
/>
|
||||
)}
|
||||
{skip_tags?.length > 0 && (
|
||||
{skip_tags && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Skip Tags`}
|
||||
@ -271,6 +275,7 @@ function PromptJobTemplateDetail({ resource }) {
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={skip_tags?.length === 0}
|
||||
/>
|
||||
)}
|
||||
{extra_vars && (
|
||||
|
||||
@ -125,4 +125,92 @@ describe('PromptJobTemplateDetail', () => {
|
||||
assertDetail(wrapper, 'Organization', 'Deleted');
|
||||
assertDetail(wrapper, 'Project', 'Deleted');
|
||||
});
|
||||
|
||||
test('should not load Activity', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<PromptJobTemplateDetail
|
||||
resource={{
|
||||
...mockJT,
|
||||
summary_fields: {
|
||||
recent_jobs: [],
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
const activity_detail = wrapper.find(`Detail[label="Activity"]`).at(0);
|
||||
expect(activity_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should not load Credentials', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<PromptJobTemplateDetail
|
||||
resource={{
|
||||
...mockJT,
|
||||
summary_fields: {
|
||||
credentials: [],
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
const credentials_detail = wrapper
|
||||
.find(`Detail[label="Credentials"]`)
|
||||
.at(0);
|
||||
expect(credentials_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should not load Labels', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<PromptJobTemplateDetail
|
||||
resource={{
|
||||
...mockJT,
|
||||
summary_fields: {
|
||||
labels: {
|
||||
results: [],
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
const labels_detail = wrapper.find(`Detail[label="Labels"]`).at(0);
|
||||
expect(labels_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should not load Instance Groups', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<PromptJobTemplateDetail
|
||||
resource={{
|
||||
...mockJT,
|
||||
instance_groups: [],
|
||||
}}
|
||||
/>
|
||||
);
|
||||
const instance_groups_detail = wrapper
|
||||
.find(`Detail[label="Instance Groups"]`)
|
||||
.at(0);
|
||||
expect(instance_groups_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should not load Job Tags', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<PromptJobTemplateDetail
|
||||
resource={{
|
||||
...mockJT,
|
||||
job_tags: '',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('Detail[label="Job Tags"]').length).toBe(0);
|
||||
});
|
||||
|
||||
test('should not load Skip Tags', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<PromptJobTemplateDetail
|
||||
resource={{
|
||||
...mockJT,
|
||||
skip_tags: '',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('Detail[label="Skip Tags"]').length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@ -57,9 +57,11 @@ function PromptWFJobTemplateDetail({ resource }) {
|
||||
|
||||
return (
|
||||
<>
|
||||
{summary_fields?.recent_jobs?.length > 0 && (
|
||||
<Detail value={<Sparkline jobs={recentJobs} />} label={t`Activity`} />
|
||||
)}
|
||||
<Detail
|
||||
label={t`Activity`}
|
||||
value={<Sparkline jobs={recentJobs} />}
|
||||
isEmpty={summary_fields?.recent_jobs?.length === 0}
|
||||
/>
|
||||
{summary_fields?.organization && (
|
||||
<Detail
|
||||
label={t`Organization`}
|
||||
@ -108,7 +110,7 @@ function PromptWFJobTemplateDetail({ resource }) {
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{summary_fields?.labels?.results?.length > 0 && (
|
||||
{summary_fields?.labels?.results && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Labels`}
|
||||
@ -125,6 +127,7 @@ function PromptWFJobTemplateDetail({ resource }) {
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={summary_fields?.labels?.results?.length === 0}
|
||||
/>
|
||||
)}
|
||||
{extra_vars && (
|
||||
|
||||
@ -62,4 +62,36 @@ describe('PromptWFJobTemplateDetail', () => {
|
||||
'---\nmock: data'
|
||||
);
|
||||
});
|
||||
|
||||
test('should not load Activity', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<PromptWFJobTemplateDetail
|
||||
resource={{
|
||||
...mockWF,
|
||||
summary_fields: {
|
||||
recent_jobs: [],
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
const activity_detail = wrapper.find(`Detail[label="Activity"]`).at(0);
|
||||
expect(activity_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should not load Labels', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<PromptWFJobTemplateDetail
|
||||
resource={{
|
||||
...mockWF,
|
||||
summary_fields: {
|
||||
labels: {
|
||||
results: [],
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
const labels_detail = wrapper.find(`Detail[label="Labels"]`).at(0);
|
||||
expect(labels_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
@ -68,34 +68,32 @@ function ResourceAccessListItem({ accessRecord, onRoleDelete }) {
|
||||
<Td dataLabel={t`Last name`}>{accessRecord.last_name}</Td>
|
||||
<Td dataLabel={t`Roles`}>
|
||||
<DetailList stacked>
|
||||
{userRoles.length > 0 && (
|
||||
<Detail
|
||||
label={t`User Roles`}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={5}
|
||||
totalChips={userRoles.length}
|
||||
ouiaId="user-role-chips"
|
||||
>
|
||||
{userRoles.map(renderChip)}
|
||||
</ChipGroup>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{teamRoles.length > 0 && (
|
||||
<Detail
|
||||
label={t`Team Roles`}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={5}
|
||||
totalChips={teamRoles.length}
|
||||
ouiaId="team-role-chips"
|
||||
>
|
||||
{teamRoles.map(renderChip)}
|
||||
</ChipGroup>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Detail
|
||||
label={t`User Roles`}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={5}
|
||||
totalChips={userRoles.length}
|
||||
ouiaId="user-role-chips"
|
||||
>
|
||||
{userRoles.map(renderChip)}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={userRoles.length === 0}
|
||||
/>
|
||||
<Detail
|
||||
label={t`Team Roles`}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={5}
|
||||
totalChips={teamRoles.length}
|
||||
ouiaId="team-role-chips"
|
||||
>
|
||||
{teamRoles.map(renderChip)}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={teamRoles.length === 0}
|
||||
/>
|
||||
</DetailList>
|
||||
</Td>
|
||||
</Tr>
|
||||
|
||||
@ -53,5 +53,41 @@ describe('<ResourceAccessListItem />', () => {
|
||||
|
||||
expect(wrapper.find('Td[dataLabel="First name"]').text()).toBe('jane');
|
||||
expect(wrapper.find('Td[dataLabel="Last name"]').text()).toBe('brown');
|
||||
|
||||
const user_roles_detail = wrapper.find(`Detail[label="User Roles"]`).at(0);
|
||||
expect(user_roles_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should not load team roles', async () => {
|
||||
let wrapper;
|
||||
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<table>
|
||||
<tbody>
|
||||
<ResourceAccessListItem
|
||||
accessRecord={{
|
||||
...accessRecord,
|
||||
summary_fields: {
|
||||
direct_access: [
|
||||
{
|
||||
role: {
|
||||
id: 3,
|
||||
name: 'Member',
|
||||
user_capabilities: { unattach: true },
|
||||
},
|
||||
},
|
||||
],
|
||||
indirect_access: [],
|
||||
},
|
||||
}}
|
||||
onRoleDelete={() => {}}
|
||||
/>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
});
|
||||
const team_roles_detail = wrapper.find(`Detail[label="Team Roles"]`).at(0);
|
||||
expect(team_roles_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
@ -272,11 +272,12 @@ function TemplateListItem({
|
||||
value={template.description}
|
||||
dataCy={`template-${template.id}-description`}
|
||||
/>
|
||||
{summaryFields.recent_jobs && summaryFields.recent_jobs.length ? (
|
||||
{summaryFields.recent_jobs ? (
|
||||
<Detail
|
||||
label={t`Activity`}
|
||||
value={<Sparkline jobs={summaryFields.recent_jobs} />}
|
||||
dataCy={`template-${template.id}-activity`}
|
||||
isEmpty={summaryFields.recent_jobs.length === 0}
|
||||
/>
|
||||
) : null}
|
||||
{summaryFields.inventory ? (
|
||||
@ -316,7 +317,7 @@ function TemplateListItem({
|
||||
value={formatDateString(template.modified)}
|
||||
dataCy={`template-${template.id}-last-modified`}
|
||||
/>
|
||||
{summaryFields.credentials && summaryFields.credentials.length ? (
|
||||
{summaryFields.credentials ? (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Credentials`}
|
||||
@ -337,9 +338,10 @@ function TemplateListItem({
|
||||
</ChipGroup>
|
||||
}
|
||||
dataCy={`template-${template.id}-credentials`}
|
||||
isEmpty={summaryFields.credentials.length === 0}
|
||||
/>
|
||||
) : null}
|
||||
{summaryFields.labels && summaryFields.labels.results.length > 0 && (
|
||||
{summaryFields.labels && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Labels`}
|
||||
@ -361,6 +363,7 @@ function TemplateListItem({
|
||||
</ChipGroup>
|
||||
}
|
||||
dataCy={`template-${template.id}-labels`}
|
||||
isEmpty={summaryFields.labels.results.length === 0}
|
||||
/>
|
||||
)}
|
||||
</DetailList>
|
||||
|
||||
@ -465,4 +465,68 @@ describe('<TemplateListItem />', () => {
|
||||
).toEqual(true);
|
||||
expect(wrapper.find(`Detail[label="Activity"] Sparkline`)).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('should not load Activity', async () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<table>
|
||||
<tbody>
|
||||
<TemplateListItem
|
||||
template={{
|
||||
...mockJobTemplateData,
|
||||
summary_fields: {
|
||||
user_capabilities: {},
|
||||
recent_jobs: [],
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
const activity_detail = wrapper.find(`Detail[label="Activity"]`).at(0);
|
||||
expect(activity_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should not load Credentials', async () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<table>
|
||||
<tbody>
|
||||
<TemplateListItem
|
||||
template={{
|
||||
...mockJobTemplateData,
|
||||
summary_fields: {
|
||||
user_capabilities: {},
|
||||
credentials: [],
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
const credentials_detail = wrapper
|
||||
.find(`Detail[label="Credentials"]`)
|
||||
.at(0);
|
||||
expect(credentials_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should not load Labels', async () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<table>
|
||||
<tbody>
|
||||
<TemplateListItem
|
||||
template={{
|
||||
...mockJobTemplateData,
|
||||
summary_fields: {
|
||||
user_capabilities: {},
|
||||
labels: {
|
||||
results: [],
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
const labels_detail = wrapper.find(`Detail[label="Labels"]`).at(0);
|
||||
expect(labels_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
@ -264,20 +264,19 @@ function CredentialDetail({ credential }) {
|
||||
date={modified}
|
||||
user={modified_by}
|
||||
/>
|
||||
{enabledBooleanFields.length > 0 && (
|
||||
<Detail
|
||||
label={t`Enabled Options`}
|
||||
value={
|
||||
<TextList component={TextListVariants.ul}>
|
||||
{enabledBooleanFields.map(({ id, label }) => (
|
||||
<TextListItem key={id} component={TextListItemVariants.li}>
|
||||
{label}
|
||||
</TextListItem>
|
||||
))}
|
||||
</TextList>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Detail
|
||||
label={t`Enabled Options`}
|
||||
value={
|
||||
<TextList component={TextListVariants.ul}>
|
||||
{enabledBooleanFields.map(({ id, label }) => (
|
||||
<TextListItem key={id} component={TextListItemVariants.li}>
|
||||
{label}
|
||||
</TextListItem>
|
||||
))}
|
||||
</TextList>
|
||||
}
|
||||
isEmpty={enabledBooleanFields.length === 0}
|
||||
/>
|
||||
</DetailList>
|
||||
{Object.keys(inputSources).length > 0 && (
|
||||
<PluginFieldText>
|
||||
|
||||
@ -149,4 +149,23 @@ describe('<CredentialDetail />', () => {
|
||||
wrapper.find('ModalBoxCloseButton').invoke('onClose')();
|
||||
});
|
||||
});
|
||||
|
||||
test('should not load enabled options', async () => {
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<CredentialDetail
|
||||
credential={{
|
||||
...mockCredential,
|
||||
results: {
|
||||
inputs: null,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
const enabled_options_detail = wrapper
|
||||
.find(`Detail[label="Enabled Options"]`)
|
||||
.at(0);
|
||||
expect(enabled_options_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
@ -67,9 +67,11 @@ function HostDetail({ host }) {
|
||||
<HostToggle host={host} css="padding-bottom: 40px" />
|
||||
<DetailList gutter="sm">
|
||||
<Detail label={t`Name`} value={name} dataCy="host-name" />
|
||||
{recentJobs?.length > 0 && (
|
||||
<Detail label={t`Activity`} value={<Sparkline jobs={recentJobs} />} />
|
||||
)}
|
||||
<Detail
|
||||
label={t`Activity`}
|
||||
value={<Sparkline jobs={recentJobs} />}
|
||||
isEmpty={recentJobs?.length === 0}
|
||||
/>
|
||||
<Detail label={t`Description`} value={description} />
|
||||
<Detail
|
||||
label={t`Inventory`}
|
||||
|
||||
@ -81,6 +81,8 @@ describe('<HostDetail />', () => {
|
||||
expect(wrapper.find(`Detail[label="Activity"] Sparkline`)).toHaveLength(
|
||||
0
|
||||
);
|
||||
const activity_detail = wrapper.find(`Detail[label="Activity"]`).at(0);
|
||||
expect(activity_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should hide edit button for users without edit permission', async () => {
|
||||
|
||||
@ -79,17 +79,17 @@ function InventoryDetail({ inventory }) {
|
||||
}
|
||||
/>
|
||||
<Detail label={t`Total hosts`} value={inventory.total_hosts} />
|
||||
{instanceGroups && instanceGroups.length > 0 && (
|
||||
{instanceGroups && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Instance Groups`}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={5}
|
||||
totalChips={instanceGroups.length}
|
||||
totalChips={instanceGroups?.length}
|
||||
ouiaId="instance-group-chips"
|
||||
>
|
||||
{instanceGroups.map((ig) => (
|
||||
{instanceGroups?.map((ig) => (
|
||||
<Chip
|
||||
key={ig.id}
|
||||
isReadOnly
|
||||
@ -100,28 +100,29 @@ function InventoryDetail({ inventory }) {
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={instanceGroups.length === 0}
|
||||
/>
|
||||
)}
|
||||
{inventory.summary_fields.labels && (
|
||||
<Detail
|
||||
fullWidth
|
||||
helpText={helpText.labels}
|
||||
label={t`Labels`}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={5}
|
||||
totalChips={inventory.summary_fields.labels?.results?.length}
|
||||
>
|
||||
{inventory.summary_fields.labels?.results?.map((l) => (
|
||||
<Chip key={l.id} isReadOnly>
|
||||
{l.name}
|
||||
</Chip>
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={inventory.summary_fields.labels?.results?.length === 0}
|
||||
/>
|
||||
)}
|
||||
{inventory.summary_fields.labels &&
|
||||
inventory.summary_fields.labels?.results?.length > 0 && (
|
||||
<Detail
|
||||
fullWidth
|
||||
helpText={helpText.labels}
|
||||
label={t`Labels`}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={5}
|
||||
totalChips={inventory.summary_fields.labels.results.length}
|
||||
>
|
||||
{inventory.summary_fields.labels.results.map((l) => (
|
||||
<Chip key={l.id} isReadOnly>
|
||||
{l.name}
|
||||
</Chip>
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<VariablesDetail
|
||||
label={t`Variables`}
|
||||
helpText={helpText.variables()}
|
||||
|
||||
@ -153,6 +153,9 @@ describe('<InventoryDetail />', () => {
|
||||
expect(InventoriesAPI.readInstanceGroups).toHaveBeenCalledWith(
|
||||
mockInventory.id
|
||||
);
|
||||
expect(wrapper.find(`Detail[label="Instance Groups"]`)).toHaveLength(0);
|
||||
const instance_groups_detail = wrapper
|
||||
.find(`Detail[label="Instance Groups"]`)
|
||||
.at(0);
|
||||
expect(instance_groups_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
@ -72,12 +72,11 @@ function InventoryHostDetail({ host }) {
|
||||
<HostToggle host={host} css="padding-bottom: 40px" />
|
||||
<DetailList gutter="sm">
|
||||
<Detail label={t`Name`} value={name} />
|
||||
{recentPlaybookJobs?.length > 0 && (
|
||||
<Detail
|
||||
label={t`Activity`}
|
||||
value={<Sparkline jobs={recentPlaybookJobs} />}
|
||||
/>
|
||||
)}
|
||||
<Detail
|
||||
label={t`Activity`}
|
||||
value={<Sparkline jobs={recentPlaybookJobs} />}
|
||||
isEmpty={recentPlaybookJobs?.length === 0}
|
||||
/>
|
||||
<Detail label={t`Description`} value={description} />
|
||||
<UserDateDetail date={created} label={t`Created`} user={created_by} />
|
||||
<UserDateDetail
|
||||
|
||||
@ -91,6 +91,8 @@ describe('<InventoryHostDetail />', () => {
|
||||
expect(wrapper.find(`Detail[label="Activity"] Sparkline`)).toHaveLength(
|
||||
0
|
||||
);
|
||||
const activity_detail = wrapper.find(`Detail[label="Activity"]`).at(0);
|
||||
expect(activity_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should hide edit button for users without edit permission', async () => {
|
||||
|
||||
@ -268,15 +268,14 @@ function InventorySourceDetail({ inventorySource }) {
|
||||
helpText={helpText.enabledValue}
|
||||
value={enabled_value}
|
||||
/>
|
||||
{credentials?.length > 0 && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Credential`}
|
||||
value={credentials.map((cred) => (
|
||||
<CredentialChip key={cred?.id} credential={cred} isReadOnly />
|
||||
))}
|
||||
/>
|
||||
)}
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Credential`}
|
||||
value={credentials?.map((cred) => (
|
||||
<CredentialChip key={cred?.id} credential={cred} isReadOnly />
|
||||
))}
|
||||
isEmpty={credentials?.length === 0}
|
||||
/>
|
||||
{optionsList && (
|
||||
<Detail fullWidth label={t`Enabled Options`} value={optionsList} />
|
||||
)}
|
||||
|
||||
@ -237,4 +237,21 @@ describe('InventorySourceDetail', () => {
|
||||
(el) => el.length === 0
|
||||
);
|
||||
});
|
||||
|
||||
test('should not load Credentials', async () => {
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<InventorySourceDetail
|
||||
inventorySource={{
|
||||
...mockInvSource,
|
||||
summary_fields: {
|
||||
credentials: [],
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
const credentials_detail = wrapper.find(`Detail[label="Credential"]`).at(0);
|
||||
expect(credentials_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
@ -96,12 +96,11 @@ function SmartInventoryDetail({ inventory }) {
|
||||
<CardBody>
|
||||
<DetailList>
|
||||
<Detail label={t`Name`} value={name} />
|
||||
{recentJobs.length > 0 && (
|
||||
<Detail
|
||||
label={t`Activity`}
|
||||
value={<Sparkline jobs={recentJobs} />}
|
||||
/>
|
||||
)}
|
||||
<Detail
|
||||
label={t`Activity`}
|
||||
value={<Sparkline jobs={recentJobs} />}
|
||||
isEmpty={recentJobs.length === 0}
|
||||
/>
|
||||
<Detail label={t`Description`} value={description} />
|
||||
<Detail label={t`Type`} value={t`Smart inventory`} />
|
||||
<Detail
|
||||
@ -118,29 +117,28 @@ function SmartInventoryDetail({ inventory }) {
|
||||
value={<Label variant="outline">{host_filter}</Label>}
|
||||
/>
|
||||
<Detail label={t`Total hosts`} value={total_hosts} />
|
||||
{instanceGroups.length > 0 && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Instance groups`}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={5}
|
||||
totalChips={instanceGroups.length}
|
||||
ouiaId="instance-group-chips"
|
||||
>
|
||||
{instanceGroups.map((ig) => (
|
||||
<Chip
|
||||
key={ig.id}
|
||||
isReadOnly
|
||||
ouiaId={`instance-group-${ig.id}-chip`}
|
||||
>
|
||||
{ig.name}
|
||||
</Chip>
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Instance groups`}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={5}
|
||||
totalChips={instanceGroups.length}
|
||||
ouiaId="instance-group-chips"
|
||||
>
|
||||
{instanceGroups.map((ig) => (
|
||||
<Chip
|
||||
key={ig.id}
|
||||
isReadOnly
|
||||
ouiaId={`instance-group-${ig.id}-chip`}
|
||||
>
|
||||
{ig.name}
|
||||
</Chip>
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={instanceGroups.length === 0}
|
||||
/>
|
||||
<VariablesDetail
|
||||
label={t`Variables`}
|
||||
value={variables}
|
||||
|
||||
@ -112,6 +112,41 @@ describe('<SmartInventoryDetail />', () => {
|
||||
(el) => el.length === 0
|
||||
);
|
||||
});
|
||||
|
||||
test('should not load Activity', async () => {
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<SmartInventoryDetail
|
||||
inventory={{
|
||||
...mockSmartInventory,
|
||||
recent_jobs: [],
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
const activity_detail = wrapper.find(`Detail[label="Activity"]`).at(0);
|
||||
expect(activity_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should not load Instance Groups', async () => {
|
||||
InventoriesAPI.readInstanceGroups.mockResolvedValue({
|
||||
data: {
|
||||
results: [],
|
||||
},
|
||||
});
|
||||
|
||||
let wrapper;
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<SmartInventoryDetail inventory={mockSmartInventory} />
|
||||
);
|
||||
});
|
||||
wrapper.update();
|
||||
const instance_groups_detail = wrapper
|
||||
.find(`Detail[label="Instance groups"]`)
|
||||
.at(0);
|
||||
expect(instance_groups_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('User has read-only permissions', () => {
|
||||
|
||||
@ -28,12 +28,11 @@ function SmartInventoryHostDetail({ host }) {
|
||||
<CardBody>
|
||||
<DetailList gutter="sm">
|
||||
<Detail label={t`Name`} value={name} />
|
||||
{recentPlaybookJobs?.length > 0 && (
|
||||
<Detail
|
||||
label={t`Activity`}
|
||||
value={<Sparkline jobs={recentPlaybookJobs} />}
|
||||
/>
|
||||
)}
|
||||
<Detail
|
||||
label={t`Activity`}
|
||||
value={<Sparkline jobs={recentPlaybookJobs} />}
|
||||
isEmpty={recentPlaybookJobs?.length === 0}
|
||||
/>
|
||||
<Detail label={t`Description`} value={description} />
|
||||
<Detail
|
||||
label={t`Inventory`}
|
||||
|
||||
@ -27,4 +27,19 @@ describe('<SmartInventoryHostDetail />', () => {
|
||||
expect(wrapper.find('Detail[label="Activity"] Sparkline')).toHaveLength(1);
|
||||
expect(wrapper.find('VariablesDetail')).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('should not load Activity', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<SmartInventoryHostDetail
|
||||
host={{
|
||||
...mockHost,
|
||||
summary_fields: {
|
||||
recent_jobs: [],
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
const activity_detail = wrapper.find(`Detail[label="Activity"]`).at(0);
|
||||
expect(activity_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
@ -268,15 +268,14 @@ function JobDetail({ job, inventorySourceLabels }) {
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
{inventorySourceLabels.length > 0 && (
|
||||
<Detail
|
||||
dataCy="job-inventory-source-type"
|
||||
label={t`Source`}
|
||||
value={inventorySourceLabels.map(([string, label]) =>
|
||||
string === job.source ? label : null
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<Detail
|
||||
dataCy="job-inventory-source-type"
|
||||
label={t`Source`}
|
||||
value={inventorySourceLabels.map(([string, label]) =>
|
||||
string === job.source ? label : null
|
||||
)}
|
||||
isEmpty={inventorySourceLabels.length === 0}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{inventory_source && inventory_source.source === 'scm' && (
|
||||
@ -406,7 +405,7 @@ function JobDetail({ job, inventorySourceLabels }) {
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{credentials && credentials.length > 0 && (
|
||||
{credentials && (
|
||||
<Detail
|
||||
dataCy="job-credentials"
|
||||
fullWidth
|
||||
@ -428,6 +427,7 @@ function JobDetail({ job, inventorySourceLabels }) {
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={credentials.length === 0}
|
||||
/>
|
||||
)}
|
||||
{labels && labels.count > 0 && (
|
||||
@ -451,7 +451,7 @@ function JobDetail({ job, inventorySourceLabels }) {
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{job.job_tags && job.job_tags.length > 0 && (
|
||||
{job.job_tags && (
|
||||
<Detail
|
||||
dataCy="job-tags"
|
||||
fullWidth
|
||||
@ -474,9 +474,10 @@ function JobDetail({ job, inventorySourceLabels }) {
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={job.job_tags.length === 0}
|
||||
/>
|
||||
)}
|
||||
{job.skip_tags && job.skip_tags.length > 0 && (
|
||||
{job.skip_tags && (
|
||||
<Detail
|
||||
dataCy="job-skip-tags"
|
||||
fullWidth
|
||||
@ -499,6 +500,7 @@ function JobDetail({ job, inventorySourceLabels }) {
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={job.skip_tags.length === 0}
|
||||
/>
|
||||
)}
|
||||
<Detail
|
||||
|
||||
@ -548,4 +548,64 @@ describe('<JobDetail />', () => {
|
||||
assertDetail('Inventory', 'Demo Inventory');
|
||||
assertDetail('Job Slice Parent', 'True');
|
||||
});
|
||||
|
||||
test('should not load Source', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<JobDetail
|
||||
job={{
|
||||
...mockJobData,
|
||||
summary_fields: {
|
||||
inventory_source: {},
|
||||
user_capabilities: {},
|
||||
inventory: { id: 1 },
|
||||
},
|
||||
}}
|
||||
inventorySourceLabels={[]}
|
||||
/>
|
||||
);
|
||||
const source_detail = wrapper.find(`Detail[label="Source"]`).at(0);
|
||||
expect(source_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should not load Credentials', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<JobDetail
|
||||
job={{
|
||||
...mockJobData,
|
||||
summary_fields: {
|
||||
user_capabilities: {},
|
||||
credentials: [],
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
const credentials_detail = wrapper
|
||||
.find(`Detail[label="Credentials"]`)
|
||||
.at(0);
|
||||
expect(credentials_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should not load Job Tags', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<JobDetail
|
||||
job={{
|
||||
...mockJobData,
|
||||
job_tags: '',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('Detail[label="Job Tags"]').length).toBe(0);
|
||||
});
|
||||
|
||||
test('should not load Skip Tags', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<JobDetail
|
||||
job={{
|
||||
...mockJobData,
|
||||
skip_tags: '',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('Detail[label="Skip Tags"]').length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@ -30,7 +30,7 @@ function OrganizationDetail({ organization }) {
|
||||
created,
|
||||
modified,
|
||||
summary_fields,
|
||||
galaxy_credentials,
|
||||
galaxy_credentials = [],
|
||||
} = organization;
|
||||
const [contentError, setContentError] = useState(null);
|
||||
const [hasContentLoading, setHasContentLoading] = useState(true);
|
||||
@ -121,7 +121,7 @@ function OrganizationDetail({ organization }) {
|
||||
date={modified}
|
||||
user={summary_fields.modified_by}
|
||||
/>
|
||||
{instanceGroups && instanceGroups.length > 0 && (
|
||||
{instanceGroups && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Instance Groups`}
|
||||
@ -145,35 +145,35 @@ function OrganizationDetail({ organization }) {
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={instanceGroups.length === 0}
|
||||
/>
|
||||
)}
|
||||
{galaxy_credentials && galaxy_credentials.length > 0 && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Galaxy Credentials`}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={5}
|
||||
totalChips={galaxy_credentials.length}
|
||||
ouiaId="galaxy-credential-chips"
|
||||
>
|
||||
{galaxy_credentials.map((credential) => (
|
||||
<Link
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Galaxy Credentials`}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={5}
|
||||
totalChips={galaxy_credentials?.length}
|
||||
ouiaId="galaxy-credential-chips"
|
||||
>
|
||||
{galaxy_credentials?.map((credential) => (
|
||||
<Link
|
||||
key={credential.id}
|
||||
to={`/credentials/${credential.id}/details`}
|
||||
>
|
||||
<CredentialChip
|
||||
credential={credential}
|
||||
key={credential.id}
|
||||
to={`/credentials/${credential.id}/details`}
|
||||
>
|
||||
<CredentialChip
|
||||
credential={credential}
|
||||
key={credential.id}
|
||||
isReadOnly
|
||||
ouiaId={`galaxy-credential-${credential.id}-chip`}
|
||||
/>
|
||||
</Link>
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
isReadOnly
|
||||
ouiaId={`galaxy-credential-${credential.id}-chip`}
|
||||
/>
|
||||
</Link>
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={galaxy_credentials?.length === 0}
|
||||
/>
|
||||
</DetailList>
|
||||
<CardActionsRow>
|
||||
{summary_fields.user_capabilities.edit && (
|
||||
|
||||
@ -216,4 +216,44 @@ describe('<OrganizationDetail />', () => {
|
||||
(el) => el.length === 0
|
||||
);
|
||||
});
|
||||
|
||||
test('should not load instance groups', async () => {
|
||||
OrganizationsAPI.readInstanceGroups.mockResolvedValue({
|
||||
data: {
|
||||
results: [],
|
||||
},
|
||||
});
|
||||
|
||||
let wrapper;
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<OrganizationDetail organization={mockOrganization} />
|
||||
);
|
||||
});
|
||||
wrapper.update();
|
||||
const instance_groups_detail = wrapper
|
||||
.find(`Detail[label="Instance Groups"]`)
|
||||
.at(0);
|
||||
expect(instance_groups_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should not load galaxy credentials', async () => {
|
||||
OrganizationsAPI.readInstanceGroups.mockResolvedValue({ data: {} });
|
||||
let wrapper;
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<OrganizationDetail
|
||||
organization={{
|
||||
...mockOrganization,
|
||||
credential: [],
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
wrapper.update();
|
||||
const galaxy_credentials_detail = wrapper
|
||||
.find(`Detail[label="Galaxy Credentials"]`)
|
||||
.at(0);
|
||||
expect(galaxy_credentials_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
@ -354,7 +354,7 @@ function JobTemplateDetail({ template }) {
|
||||
helpText={helpText.enabledOptions}
|
||||
/>
|
||||
)}
|
||||
{summary_fields.credentials && summary_fields.credentials.length > 0 && (
|
||||
{summary_fields.credentials && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Credentials`}
|
||||
@ -378,9 +378,10 @@ function JobTemplateDetail({ template }) {
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={summary_fields.credentials.length === 0}
|
||||
/>
|
||||
)}
|
||||
{summary_fields.labels && summary_fields.labels.results.length > 0 && (
|
||||
{summary_fields.labels && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Labels`}
|
||||
@ -399,36 +400,36 @@ function JobTemplateDetail({ template }) {
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={summary_fields.labels.results.length === 0}
|
||||
/>
|
||||
)}
|
||||
{instanceGroups.length > 0 && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Instance Groups`}
|
||||
dataCy="jt-detail-instance-groups"
|
||||
helpText={helpText.instanceGroups}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={5}
|
||||
totalChips={instanceGroups.length}
|
||||
ouiaId="instance-group-chips"
|
||||
>
|
||||
{instanceGroups.map((ig) => (
|
||||
<Link to={`${buildLinkURL(ig)}${ig.id}/details`} key={ig.id}>
|
||||
<Chip
|
||||
key={ig.id}
|
||||
ouiaId={`instance-group-${ig.id}-chip`}
|
||||
isReadOnly
|
||||
>
|
||||
{ig.name}
|
||||
</Chip>
|
||||
</Link>
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{job_tags && job_tags.length > 0 && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Instance Groups`}
|
||||
dataCy="jt-detail-instance-groups"
|
||||
helpText={helpText.instanceGroups}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={5}
|
||||
totalChips={instanceGroups.length}
|
||||
ouiaId="instance-group-chips"
|
||||
>
|
||||
{instanceGroups.map((ig) => (
|
||||
<Link to={`${buildLinkURL(ig)}${ig.id}/details`} key={ig.id}>
|
||||
<Chip
|
||||
key={ig.id}
|
||||
ouiaId={`instance-group-${ig.id}-chip`}
|
||||
isReadOnly
|
||||
>
|
||||
{ig.name}
|
||||
</Chip>
|
||||
</Link>
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={instanceGroups.length === 0}
|
||||
/>
|
||||
{job_tags && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Job Tags`}
|
||||
@ -451,9 +452,10 @@ function JobTemplateDetail({ template }) {
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={job_tags.length === 0}
|
||||
/>
|
||||
)}
|
||||
{skip_tags && skip_tags.length > 0 && (
|
||||
{skip_tags && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Skip Tags`}
|
||||
@ -476,6 +478,7 @@ function JobTemplateDetail({ template }) {
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={skip_tags.length === 0}
|
||||
/>
|
||||
)}
|
||||
<VariablesDetail
|
||||
|
||||
@ -195,4 +195,94 @@ describe('<JobTemplateDetail />', () => {
|
||||
wrapper.find(`Detail[label="Execution Environment"] dd`).text()
|
||||
).toBe('Default EE');
|
||||
});
|
||||
|
||||
test('should not load credentials', async () => {
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<JobTemplateDetail
|
||||
template={{
|
||||
...mockTemplate,
|
||||
allow_simultaneous: true,
|
||||
ask_inventory_on_launch: true,
|
||||
summary_fields: {
|
||||
credentials: [],
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
const credentials_detail = wrapper
|
||||
.find(`Detail[label="Credentials"]`)
|
||||
.at(0);
|
||||
expect(credentials_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should not load labels', async () => {
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<JobTemplateDetail
|
||||
template={{
|
||||
...mockTemplate,
|
||||
allow_simultaneous: true,
|
||||
ask_inventory_on_launch: true,
|
||||
summary_fields: {
|
||||
labels: {
|
||||
results: [],
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
const labels_detail = wrapper.find(`Detail[label="Labels"]`).at(0);
|
||||
expect(labels_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should not load instance groups', async () => {
|
||||
JobTemplatesAPI.readInstanceGroups.mockResolvedValue({
|
||||
data: {
|
||||
results: [],
|
||||
},
|
||||
});
|
||||
|
||||
let wrapper;
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<JobTemplateDetail template={mockTemplate} />
|
||||
);
|
||||
});
|
||||
wrapper.update();
|
||||
const instance_groups_detail = wrapper
|
||||
.find(`Detail[label="Instance Groups"]`)
|
||||
.at(0);
|
||||
expect(instance_groups_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should not load job tags', async () => {
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<JobTemplateDetail
|
||||
template={{
|
||||
...mockTemplate,
|
||||
job_tags: '',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
expect(wrapper.find('Detail[label="Job Tags"]').length).toBe(0);
|
||||
});
|
||||
|
||||
test('should not load skip tags', async () => {
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<JobTemplateDetail
|
||||
template={{
|
||||
...mockTemplate,
|
||||
skip_tags: '',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
expect(wrapper.find('Detail[label="Skip Tags"]').length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@ -110,12 +110,11 @@ function WorkflowJobTemplateDetail({ template }) {
|
||||
<DetailList gutter="sm">
|
||||
<Detail label={t`Name`} value={name} dataCy="jt-detail-name" />
|
||||
<Detail label={t`Description`} value={description} />
|
||||
{summary_fields.recent_jobs?.length > 0 && (
|
||||
<Detail
|
||||
value={<Sparkline jobs={recentPlaybookJobs} />}
|
||||
label={t`Activity`}
|
||||
/>
|
||||
)}
|
||||
<Detail
|
||||
value={<Sparkline jobs={recentPlaybookJobs} />}
|
||||
label={t`Activity`}
|
||||
isEmpty={summary_fields.recent_jobs?.length === 0}
|
||||
/>
|
||||
{summary_fields.organization && (
|
||||
<Detail
|
||||
label={t`Organization`}
|
||||
@ -202,26 +201,25 @@ function WorkflowJobTemplateDetail({ template }) {
|
||||
helpText={helpText.enabledOptions}
|
||||
/>
|
||||
)}
|
||||
{summary_fields.labels?.results?.length > 0 && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Labels`}
|
||||
helpText={helpText.labels}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={3}
|
||||
totalChips={summary_fields.labels.results.length}
|
||||
ouiaId="workflow-job-template-detail-label-chips"
|
||||
>
|
||||
{summary_fields.labels.results.map((l) => (
|
||||
<Chip key={l.id} ouiaId={`${l.name}-label-chip`} isReadOnly>
|
||||
{l.name}
|
||||
</Chip>
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Labels`}
|
||||
helpText={helpText.labels}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={3}
|
||||
totalChips={summary_fields.labels.results.length}
|
||||
ouiaId="workflow-job-template-detail-label-chips"
|
||||
>
|
||||
{summary_fields.labels.results.map((l) => (
|
||||
<Chip key={l.id} ouiaId={`${l.name}-label-chip`} isReadOnly>
|
||||
{l.name}
|
||||
</Chip>
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={!summary_fields.labels?.results?.length}
|
||||
/>
|
||||
<VariablesDetail
|
||||
dataCy="workflow-job-template-detail-extra-vars"
|
||||
helpText={helpText.variables}
|
||||
|
||||
@ -178,4 +178,46 @@ describe('<WorkflowJobTemplateDetail/>', () => {
|
||||
expect(inventory.prop('to')).toEqual('/inventories/inventory/1/details');
|
||||
expect(organization.prop('to')).toEqual('/organizations/1/details');
|
||||
});
|
||||
|
||||
test('should not load Activity', async () => {
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<WorkflowJobTemplateDetail
|
||||
template={{
|
||||
...template,
|
||||
summary_fields: {
|
||||
...template.summary_fields,
|
||||
recent_jobs: [],
|
||||
},
|
||||
}}
|
||||
hasContentLoading={false}
|
||||
onSetContentLoading={() => {}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
const activity_detail = wrapper.find(`Detail[label="Activity"]`).at(0);
|
||||
expect(activity_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should not load Labels', async () => {
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<WorkflowJobTemplateDetail
|
||||
template={{
|
||||
...template,
|
||||
summary_fields: {
|
||||
...template.summary_fields,
|
||||
labels: {
|
||||
results: [],
|
||||
},
|
||||
},
|
||||
}}
|
||||
hasContentLoading={false}
|
||||
onSetContentLoading={() => {}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
const labels_detail = wrapper.find(`Detail[label="Labels"]`).at(0);
|
||||
expect(labels_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
@ -44,30 +44,28 @@ function TemplatePopoverContent({ template }) {
|
||||
value={template?.playbook}
|
||||
dataCy={`template-${template.id}-playbook`}
|
||||
/>
|
||||
{template.summary_fields?.credentials &&
|
||||
template.summary_fields.credentials.length ? (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Credentials`}
|
||||
dataCy={`template-${template.id}-credentials`}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={5}
|
||||
totalChips={template.summary_fields.credentials.length}
|
||||
ouiaId={`template-${template.id}-credential-chips`}
|
||||
>
|
||||
{template.summary_fields.credentials.map((c) => (
|
||||
<CredentialChip
|
||||
key={c.id}
|
||||
credential={c}
|
||||
isReadOnly
|
||||
ouiaId={`credential-${c.id}-chip`}
|
||||
/>
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Credentials`}
|
||||
dataCy={`template-${template.id}-credentials`}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={5}
|
||||
totalChips={template.summary_fields?.credentials?.length}
|
||||
ouiaId={`template-${template.id}-credential-chips`}
|
||||
>
|
||||
{template.summary_fields?.credentials?.map((c) => (
|
||||
<CredentialChip
|
||||
key={c.id}
|
||||
credential={c}
|
||||
isReadOnly
|
||||
ouiaId={`credential-${c.id}-chip`}
|
||||
/>
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={template.summary_fields?.credentials?.length === 0}
|
||||
/>
|
||||
</DetailList>
|
||||
);
|
||||
}
|
||||
|
||||
@ -309,25 +309,24 @@ function WorkflowApprovalDetail({ workflowApproval }) {
|
||||
dataCy="wa-detail-inventory"
|
||||
/>
|
||||
) : null}
|
||||
{workflowJob?.summary_fields?.labels?.results?.length > 0 && (
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Labels`}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={5}
|
||||
totalChips={workflowJob.summary_fields.labels.results.length}
|
||||
ouiaId="wa-detail-label-chips"
|
||||
>
|
||||
{workflowJob.summary_fields.labels.results.map((label) => (
|
||||
<Chip key={label.id} isReadOnly>
|
||||
{label.name}
|
||||
</Chip>
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Detail
|
||||
fullWidth
|
||||
label={t`Labels`}
|
||||
value={
|
||||
<ChipGroup
|
||||
numChips={5}
|
||||
totalChips={workflowJob.summary_fields.labels.results.length}
|
||||
ouiaId="wa-detail-label-chips"
|
||||
>
|
||||
{workflowJob.summary_fields.labels.results.map((label) => (
|
||||
<Chip key={label.id} isReadOnly>
|
||||
{label.name}
|
||||
</Chip>
|
||||
))}
|
||||
</ChipGroup>
|
||||
}
|
||||
isEmpty={!workflowJob?.summary_fields?.labels?.results?.length}
|
||||
/>
|
||||
{workflowJob?.extra_vars ? (
|
||||
<VariablesDetail
|
||||
dataCy="wa-detail-variables"
|
||||
|
||||
@ -482,6 +482,33 @@ describe('<WorkflowApprovalDetail />', () => {
|
||||
expect(wrapper.find('DeleteButton').length).toBe(1);
|
||||
});
|
||||
|
||||
test('should not load Labels', async () => {
|
||||
WorkflowJobTemplatesAPI.readDetail.mockResolvedValue({
|
||||
data: workflowJobTemplate,
|
||||
});
|
||||
WorkflowJobsAPI.readDetail.mockResolvedValue({
|
||||
data: {
|
||||
...workflowApproval,
|
||||
summary_fields: {
|
||||
...workflowApproval.summary_fields,
|
||||
labels: {
|
||||
results: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
let wrapper;
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<WorkflowApprovalDetail workflowApproval={workflowApproval} />
|
||||
);
|
||||
});
|
||||
waitForElement(wrapper, 'WorkflowApprovalDetail', (el) => el.length > 0);
|
||||
const labels_detail = wrapper.find(`Detail[label="Labels"]`).at(0);
|
||||
expect(labels_detail.prop('isEmpty')).toEqual(true);
|
||||
});
|
||||
|
||||
test('Error dialog shown for failed approval', async () => {
|
||||
WorkflowApprovalsAPI.approve.mockImplementationOnce(() =>
|
||||
Promise.reject(new Error())
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user