Skip to content

Commit

Permalink
Merge pull request #6766 from jeff-phillips-18/list-view-app-badges
Browse files Browse the repository at this point in the history
Bug 1878676: Add resource badges to application groups in topology list view
  • Loading branch information
openshift-merge-robot committed Sep 30, 2020
2 parents 453662e + c9d4d91 commit e56a5b0
Show file tree
Hide file tree
Showing 16 changed files with 110 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Feature: Knative Eventing Broker Support
User should be able to experience the Knative Eventing Broker and associated features


Background:
Background:
Given user has installed the OpenShift Serverless Operator
And user has created knative serving
And user has create knative eventing
Expand All @@ -21,7 +21,7 @@ Scenario: Create default Broker
@regression
Scenario: Sink event source to Broker
Given user is at Developer Perspective
And user has created the Broker
And user has created the Broker
When user goes to +Add page
And user clicks on the Event Source card
And user selects Ping Source card
Expand Down Expand Up @@ -75,13 +75,13 @@ Scenario: Edit Application Groupings action on Broker


@regression
Scenario: Edit Application Groupings to unassigned action on Broker
Scenario: Edit Application Groupings to no application group action on Broker
Given user is at Developer Perspective
And user is having a Broker inside an applicaiton group on the Topology page
When user right clicks on the Broker to open the context menu
And user clicks on the Edit Application Groupings
And user will click on the Application dropdown on the modal
And user selects the unassigned item
And user selects the no application group item
And user clicks on Save button
Then user will see that Broker is without an application group

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Feature: Knative Eventing Channel Support
User should be able to experience the Knative Eventing Channel and associated features


Background:
Background:
Given user has installed the OpenShift Serverless Operator
And user has created knative serving
And user has create knative eventing
Expand Down Expand Up @@ -30,7 +30,7 @@ Scenario: Create InMemoryChannel
@regression
Scenario: Sink event source to Channel
Given user is at Developer Perspective
When user creates the channel
When user creates the channel
And user goes to +Add page
And user clicks on the Event Source card
And user selects Ping Source card
Expand Down Expand Up @@ -84,13 +84,13 @@ Scenario: Edit Application Groupings action on Channel


@regression
Scenario: Edit Application Groupings to unassigned action on Channel
Scenario: Edit Application Groupings to no application group action on Channel
Given user is at Developer Perspective
And user is having a Channel inside an applicaiton group on the Topology page
When user right clicks on the Channel to open the context menu
And user clicks on the Edit Application Groupings
And user will click on the Application dropdown on the modal
And user selects the unassigned item
And user selects the no application group item
And user clicks on Save button
Then user will see that Channel is without an application group

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Feature: Perform Actions on created VM
As a user, I should be able to perform Actions on imported VM


Background:
Background:
Given user is at developer perspecitve
And user has selected namespace "aut-vm-actions"
And user has created VM
Expand All @@ -28,13 +28,13 @@ Scenario: Edit Application Groupings action on VM: VM-04-TC02


@regression
Scenario: Edit Application Groupings to unassigned action on VM: VM-04-TC02
Scenario: Edit Application Groupings to no application group on VM: VM-04-TC02
When user right clicks on the VM to open the context menu
And user clicks on the Edit Application Groupings
And user will click on the Application dropdown on the modal
And user selects the unassigned item
And user selects the no application group item
And user clicks on Save button
Then user will see that VM is unassigned
Then user will see that VM does not belong to an application group


@regression
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import { setActiveApplication } from '@console/internal/actions/ui';
import { RootState } from '@console/internal/redux';
import { getActiveNamespace, getActiveApplication } from '@console/internal/reducers/ui';
import { UNASSIGNED_LABEL } from '../../const';
import ApplicationDropdown from './ApplicationDropdown';

export interface ApplicationSelectorProps {
Expand All @@ -28,7 +29,7 @@ type Props = ApplicationSelectorProps & StateProps & DispatchProps;

const ApplicationSelector: React.FC<Props> = ({ namespace, application, onChange, disabled }) => {
const allApplicationsTitle = 'all applications';
const noApplicationsTitle = 'unassigned';
const noApplicationsTitle = UNASSIGNED_LABEL;
const dropdownTitle: string =
application === ALL_APPLICATIONS_KEY
? allApplicationsTitle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ALL_APPLICATIONS_KEY } from '@console/shared';
import { useExtensions, Perspective, isPerspective } from '@console/plugin-sdk';
import { NormalizedBuilderImages, normalizeBuilderImages } from '../../utils/imagestream-utils';
import { doContextualBinding, sanitizeApplicationValue } from '../../utils/application-utils';
import { ALLOW_SERVICE_BINDING, UNASSIGNED_KEY } from '../../const';
import { ALLOW_SERVICE_BINDING, UNASSIGNED_KEY, UNASSIGNED_LABEL } from '../../const';
import { GitImportFormData, FirehoseList, ImportData, Resources } from './import-types';
import { createOrUpdateResources, handleRedirect } from './import-submit-utils';
import { validationSchema } from './import-validation-utils';
Expand Down Expand Up @@ -53,7 +53,7 @@ const ImportForm: React.FC<ImportFormProps & StateProps> = ({
application: {
initial: sanitizeApplicationValue(activeApplication),
name: sanitizeApplicationValue(activeApplication),
selectedKey: activeApplication === 'unassigned' ? UNASSIGNED_KEY : activeApplication,
selectedKey: activeApplication === UNASSIGNED_LABEL ? UNASSIGNED_KEY : activeApplication,
isInContext: !!sanitizeApplicationValue(activeApplication),
},
git: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ describe('Deploy Image ValidationUtils', () => {
});
});

it('should not throw an error when unassigned application is chosen', async () => {
it('should not throw an error when no application group is chosen', async () => {
const mockData = cloneDeep(mockDeployImageFormData);
mockData.application.selectedKey = UNASSIGNED_KEY;
mockData.application.name = '';
await deployValidationSchema.isValid(mockData).then((valid) => expect(valid).toEqual(true));
});

it('should not throw an error when allowing either create or unassigned application', async () => {
it('should not throw an error when allowing either create or no application group set', async () => {
const mockData = cloneDeep(mockDeployImageFormData);
mockData.application.selectedKey = '';
mockData.application.name = '';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,14 @@ describe('ValidationUtils', () => {
});
});

it('should not throw an error when unassigned application is chosen', async () => {
it('should not throw an error when no application group is chosen', async () => {
const mockData = cloneDeep(mockFormData);
mockData.application.selectedKey = UNASSIGNED_KEY;
mockData.application.name = '';
await validationSchema.isValid(mockData).then((valid) => expect(valid).toEqual(true));
});

it('should not throw an error when allowing either create or unassigned application', async () => {
it('should not throw an error when allowing either create or remove application', async () => {
const mockData = cloneDeep(mockFormData);
mockData.application.selectedKey = '';
mockData.application.name = '';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import * as _ from 'lodash';
import { useFormikContext, FormikValues, useField } from 'formik';
import { FormGroup, TextInputTypes } from '@patternfly/react-core';
import { InputField, getFieldId, useFormikValidationFix } from '@console/shared';
import { CREATE_APPLICATION_KEY, UNASSIGNED_KEY } from '../../../const';
import {
CREATE_APPLICATION_KEY,
CREATE_APPLICATION_LABEL,
UNASSIGNED_KEY,
UNASSIGNED_LABEL,
} from '../../../const';
import { sanitizeApplicationValue } from '../../../utils/application-utils';
import ApplicationDropdown from '../../dropdown/ApplicationDropdown';

Expand Down Expand Up @@ -45,11 +50,11 @@ const ApplicationSelector: React.FC<ApplicationSelectorProps> = ({

const actionItems = [
{
actionTitle: 'Create Application',
actionTitle: CREATE_APPLICATION_LABEL,
actionKey: CREATE_APPLICATION_KEY,
},
{
actionTitle: 'unassigned',
actionTitle: UNASSIGNED_LABEL,
actionKey: UNASSIGNED_KEY,
},
];
Expand All @@ -62,7 +67,7 @@ const ApplicationSelector: React.FC<ApplicationSelectorProps> = ({
label="Application"
helperTextInvalid={errorMessage}
validated={isValid ? 'default' : 'error'}
helperText="Select an application for your grouping or unassigned to not use an application grouping."
helperText={`Select an application for your grouping or ${UNASSIGNED_LABEL} to not use an application grouping.`}
>
<ApplicationDropdown
dropDownClassName="dropdown--full-width"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@
margin-left: var(--pf-global--spacer--sm);
}
}
&__application-label-cell {
display: inline;
vertical-align: middle;
.odc-topology-list-view__resource-icon__container {
margin-top: 8px;
}
}
&__label-cell {
display: inline-flex;
align-items: start;
Expand Down Expand Up @@ -110,6 +117,10 @@
}
&__application-label {
font-size: var(--pf-global--FontSize--2xl);
margin-left: var(--pf-global--spacer--sm);
}
&__unassigned-label {
font-size: var(--pf-global--FontSize--2xl);
}
&__kind-row, &__item-row {
border-bottom: var(--pf-c-data-list__item--BorderBottomWidth) solid var(--pf-c-data-list__item--BorderBottomColor);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,9 @@ const ConnectedTopologyListView: React.FC<TopologyListViewProps &
aria-label="Topology List View"
className="odc-topology-list-view__data-list"
selectedDataListItemId={selectedId}
onSelectDataListItem={(id) => onSelect(visualization.getElementById(id))}
onSelectDataListItem={(id) =>
onSelect(selectedId === id ? undefined : visualization.getElementById(id))
}
>
{applicationGroups.map((g) => (
<TopologyListViewAppGroup
Expand All @@ -282,6 +284,7 @@ const ConnectedTopologyListView: React.FC<TopologyListViewProps &
{unassignedItems.length > 0 ? (
<TopologyListViewUnassignedGroup
key="unassigned"
showCategory={applicationGroups.length > 0}
items={unassignedItems}
selectedIds={[selectedId]}
onSelect={(ids) => onSelect(ids ? visualization.getElementById(ids[0]) : undefined)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as React from 'react';
import * as classNames from 'classnames';
import {
DataListCell,
DataListContent,
Expand All @@ -7,11 +8,11 @@ import {
DataListItemRow,
} from '@patternfly/react-core';
import { Node, observer } from '@patternfly/react-topology';
import { ResourceIcon } from '@console/internal/components/utils';
import { getChildKinds } from './list-view-utils';
import { TopologyListViewKindGroup } from './TopologyListViewKindGroup';
import { GroupResourcesCell } from './cells/GroupResourcesCell';
import { useSearchFilter } from '../filters';
import * as classNames from 'classnames';
import { showKind, useDisplayFilters, useSearchFilter } from '../filters';

interface TopologyListViewAppGroupProps {
appGroup: Node;
Expand All @@ -25,22 +26,39 @@ const ObservedTopologyListViewAppGroup: React.FC<TopologyListViewAppGroupProps>
onSelect,
}) => {
const [filtered] = useSearchFilter(appGroup.getLabel());
const displayFilters = useDisplayFilters();
const id = appGroup.getId();
const visible = appGroup.isVisible();
const label = appGroup.getLabel();
const collapsed = appGroup.isCollapsed();
const children = appGroup.getChildren();
const { groupResources } = appGroup.getData();

if (!visible || !children?.length) {
if (
!visible ||
(!collapsed && !children?.length) ||
(collapsed &&
!groupResources.find((res) =>
showKind(res.resourceKind || res.resource?.kind, displayFilters),
))
) {
return null;
}

const { kindsMap, kindKeys } = getChildKinds(children);

const cells = [];
cells.push(
<DataListCell key={id} className="odc-topology-list-view__application-label" id={`${id}_label`}>
{label}
<DataListCell
key={id}
className="odc-topology-list-view__application-label-cell"
id={`${id}_label`}
>
<ResourceIcon
className="odc-topology-list-view__resource-icon co-m-resource-icon--lg"
kind="Application"
/>
<span className="odc-topology-list-view__application-label">{label}</span>
</DataListCell>,
);
if (collapsed) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@ import {
DataListItemRow,
} from '@patternfly/react-core';
import { Node, observer } from '@patternfly/react-topology';
import { UNASSIGNED_LABEL } from '../../../const';
import { getChildKinds } from './list-view-utils';
import { TopologyListViewKindGroup } from './TopologyListViewKindGroup';

interface TopologyListViewUnassignedGroupProps {
items: Node[];
showCategory: boolean;
selectedIds: string[];
onSelect: (ids: string[]) => void;
}

const ObservedTopologyListViewUnassignedGroup: React.FC<TopologyListViewUnassignedGroupProps> = ({
items,
showCategory,
selectedIds,
onSelect,
}) => {
Expand All @@ -27,16 +30,35 @@ const ObservedTopologyListViewUnassignedGroup: React.FC<TopologyListViewUnassign

const { kindsMap, kindKeys } = getChildKinds(items);

const unassignedContent = (
<DataListContent aria-label="unassigned items" id="unassigned-items" isHidden={false}>
{kindKeys.map((key) => (
<TopologyListViewKindGroup
key={key}
kind={key}
childElements={kindsMap[key]}
selectedIds={selectedIds}
onSelect={onSelect}
/>
))}
</DataListContent>
);

if (!showCategory) {
return unassignedContent;
}

const cells = [];
cells.push(
<DataListCell
key="label"
className="odc-topology-list-view__application-label"
className="odc-topology-list-view__unassigned-label"
id="unassigned_label"
>
unassigned
{UNASSIGNED_LABEL}
</DataListCell>,
);

return (
<DataListItem
className="odc-topology-list-view__application"
Expand All @@ -47,17 +69,7 @@ const ObservedTopologyListViewUnassignedGroup: React.FC<TopologyListViewUnassign
<DataListItemRow className="odc-topology-list-view__application-row odc-topology-list-view__unassigned-group">
<DataListItemCells dataListCells={cells} />
</DataListItemRow>
<DataListContent aria-label="unassigned items" id="unassigned-items" isHidden={false}>
{kindKeys.map((key) => (
<TopologyListViewKindGroup
key={key}
kind={key}
childElements={kindsMap[key]}
selectedIds={selectedIds}
onSelect={onSelect}
/>
))}
</DataListContent>
{unassignedContent}
</DataListItem>
);
};
Expand Down

0 comments on commit e56a5b0

Please sign in to comment.