diff --git a/components/ListView/BlueprintsDataList.js b/components/ListView/BlueprintsDataList.js index c9b930520..7c3a516f3 100644 --- a/components/ListView/BlueprintsDataList.js +++ b/components/ListView/BlueprintsDataList.js @@ -4,7 +4,7 @@ import PropTypes from "prop-types"; import { DataList, DataListItem, DataListItemRow, DataListCell, DataListItemCells } from "@patternfly/react-core"; import { PficonTemplateIcon } from "@patternfly/react-icons"; import Link from "../Link/Link"; -import CreateImage from "../Modal/CreateImage"; +import CreateImageUpload from "../Modal/CreateImageUpload"; import DeleteBlueprint from "../Modal/DeleteBlueprint"; import ExportBlueprint from "../Modal/ExportBlueprint"; @@ -46,7 +46,7 @@ class BlueprintsDataList extends React.PureComponent { - +
- -
- - {(warningUnsaved && this.state.imageType !== "" && ( - - )) || - (this.state.imageType !== "" && ( - - ))} - {this.state.imageType === "" && ( - - )} - - - ); - } -} - -CreateImageModal.propTypes = { - blueprint: PropTypes.shape({ - changed: PropTypes.bool, - description: PropTypes.string, - groups: PropTypes.array, - id: PropTypes.string, - localPendingChanges: PropTypes.array, - modules: PropTypes.array, - name: PropTypes.string, - packages: PropTypes.arrayOf(PropTypes.object), - version: PropTypes.string, - workspacePendingChanges: PropTypes.arrayOf(PropTypes.object) - }).isRequired, - composeQueue: PropTypes.arrayOf(PropTypes.object).isRequired, - composeQueueFetched: PropTypes.bool.isRequired, - fetchingQueue: PropTypes.func.isRequired, - clearQueue: PropTypes.func.isRequired, - imageTypes: PropTypes.arrayOf(PropTypes.object).isRequired, - fetchingComposeTypes: PropTypes.func.isRequired, - setBlueprint: PropTypes.func.isRequired, - intl: intlShape.isRequired, - startCompose: PropTypes.func.isRequired, - layout: PropTypes.shape({ - setNotifications: PropTypes.func - }).isRequired, - close: PropTypes.func.isRequired -}; - -class CreateImage extends React.Component { - constructor() { - super(); - this.state = { showModal: false }; - this.open = this.open.bind(this); - this.close = this.close.bind(this); - } - - open() { - this.setState({ showModal: true }); - } - - close() { - this.setState({ showModal: false }); - } - - render() { - return ( - - - {this.state.showModal && ( - - )} - - ); - } -} - -CreateImage.propTypes = { - blueprint: PropTypes.shape({ - changed: PropTypes.bool, - description: PropTypes.string, - groups: PropTypes.array, - id: PropTypes.string, - localPendingChanges: PropTypes.array, - modules: PropTypes.array, - name: PropTypes.string, - packages: PropTypes.arrayOf(PropTypes.object), - version: PropTypes.string, - workspacePendingChanges: PropTypes.arrayOf(PropTypes.object) - }), - composeQueue: PropTypes.arrayOf(PropTypes.object), - composeQueueFetched: PropTypes.bool, - fetchingQueue: PropTypes.func, - clearQueue: PropTypes.func, - imageTypes: PropTypes.arrayOf(PropTypes.object), - fetchingComposeTypes: PropTypes.func, - setBlueprint: PropTypes.func, - intl: intlShape.isRequired, - startCompose: PropTypes.func, - layout: PropTypes.shape({ - setNotifications: PropTypes.func - }) -}; - -CreateImage.defaultProps = { - blueprint: {}, - composeQueue: [], - composeQueueFetched: true, - fetchingQueue: function() {}, - clearQueue: function() {}, - imageTypes: [], - fetchingComposeTypes: function() {}, - setBlueprint: function() {}, - startCompose: function() {}, - layout: {} -}; - -const mapStateToProps = state => ({ - composeQueue: state.composes.queue, - composeQueueFetched: state.composes.queueFetched, - imageTypes: state.composes.composeTypes -}); - -const mapDispatchToProps = dispatch => ({ - setBlueprint: blueprint => { - dispatch(setBlueprint(blueprint)); - }, - fetchingComposeTypes: () => { - dispatch(fetchingComposeTypes()); - }, - fetchingQueue: () => { - dispatch(fetchingQueue()); - }, - clearQueue: () => { - dispatch(clearQueue()); - }, - startCompose: (blueprintName, composeType) => { - dispatch(startCompose(blueprintName, composeType)); - } -}); - -export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(CreateImage)); diff --git a/components/Modal/CreateImageUpload.js b/components/Modal/CreateImageUpload.js new file mode 100644 index 000000000..fe7ebac3b --- /dev/null +++ b/components/Modal/CreateImageUpload.js @@ -0,0 +1,630 @@ +import React from "react"; +import { + Alert, + Button, + Form, + FormGroup, + FormSelect, + FormSelectOption, + Checkbox, + Popover, + TextContent, + Text, + TextInput, + TextList, + TextListVariants, + TextListItem, + TextListItemVariants, + Title, + Wizard, + WizardContextConsumer, + WizardFooter +} from "@patternfly/react-core"; +import { OutlinedQuestionCircleIcon } from "@patternfly/react-icons"; +import { defineMessages, FormattedMessage, injectIntl, intlShape } from "react-intl"; +import PropTypes from "prop-types"; +import { connect } from "react-redux"; +import NotificationsApi from "../../data/NotificationsApi"; +import BlueprintApi from "../../data/BlueprintApi"; +import { setBlueprint } from "../../core/actions/blueprints"; +import { fetchingQueue, clearQueue, startCompose, fetchingComposeTypes } from "../../core/actions/composes"; +import { fetchingUploadProviders } from "../../core/actions/uploads"; + +const messages = defineMessages({ + infotip: { + defaultMessage: "This process can take a while. " + "Images are built in the order they are started." + }, + warningUnsaved: { + defaultMessage: + "This blueprint has changes that are not committed. " + + "These changes will be committed before the image is created." + }, + warningEmptyBlueprint: { + id: "empty-blueprint-alert", + defaultMessage: "This blueprint is empty." + }, + warningMissingFields: { + defaultMessage: "Required information is missing." + }, + selectOne: { + defaultMessage: "Select one" + }, + title: { + defaultMessage: "Create image" + }, + review: { + defaultMessage: + "Review the information below and click Finish to create the image and complete the tasks that were selected. " + } +}); + +class CreateImageUpload extends React.Component { + constructor(props) { + super(props); + this.state = { + isOpen: false + }; + this.open = this.open.bind(this); + this.close = this.close.bind(this); + } + + open() { + this.setState({ isOpen: true }); + } + + close() { + this.setState({ isOpen: false }); + } + + render() { + return ( + + + {this.state.isOpen && } + + ); + } +} + +class CreateImageUploadModal extends React.Component { + constructor(props) { + super(props); + this.state = { + imageType: "", + imageName: "", + showUploadAwsStep: false, + showReviewStep: false, + uploadService: "", + uploadSettings: {} + }; + this.isPendingChange = this.isPendingChange.bind(this); + this.missingRequiredFields = this.missingRequiredFields.bind(this); + this.setNotifications = this.setNotifications.bind(this); + this.setImageType = this.setImageType.bind(this); + this.setUploadSettings = this.setUploadSettings.bind(this); + this.handleUploadService = this.handleUploadService.bind(this); + this.handleCreateImage = this.handleCreateImage.bind(this); + this.handleCommit = this.handleCommit.bind(this); + this.handleStartCompose = this.handleStartCompose.bind(this); + this.handleNextStep = this.handleNextStep.bind(this); + } + + componentWillMount() { + this.props.fetchingUploadProviders(); + if (this.props.imageTypes.length === 0) { + this.props.fetchingComposeTypes(); + } + if (this.props.composeQueueFetched === false) { + this.props.fetchingQueue(); + } + } + + componentWillUnmount() { + this.props.clearQueue(); + } + + setNotifications() { + this.props.layout.setNotifications(); + } + + setUploadSettings(value, event) { + const key = event.target.id; + this.setState(prevState => ({ uploadSettings: Object.assign({}, prevState.uploadSettings, { [key]: value }) })); + } + + setImageType(imageType) { + this.setState({ + imageType, + imageName: "", + uploadService: "", + uploadSettings: {}, + showUploadAwsStep: false, + showReviewStep: false + }); + } + + isPendingChange() { + return ( + this.props.blueprint.workspacePendingChanges.length > 0 || this.props.blueprint.localPendingChanges.length > 0 + ); + } + + missingRequiredFields() { + if (this.state.uploadService.length == 0) return true; + if (this.state.imageName.length == 0) return true; + const settingsLength = + Object.keys(this.props.providerSettings[this.state.uploadService].auth).length + + Object.keys(this.props.providerSettings[this.state.uploadService].settings).length; + if (Object.keys(this.state.uploadSettings).length != settingsLength) return true; + for (const setting in this.state.uploadSettings) { + if (this.state.uploadSettings[setting].length == 0) return true; + } + return false; + } + + handleUploadService(_, event) { + const uploadService = event.target.value; + if (this.state.uploadService === uploadService) { + this.setState({ + uploadService: "", + showUploadAwsStep: true, + showReviewStep: false + }); + } else { + switch (uploadService) { + case "aws": + this.setState({ + uploadService: uploadService, + showUploadAwsStep: true, + showReviewStep: true + }); + break; + default: + break; + } + } + } + + handleCommit() { + // clear existing notifications + NotificationsApi.closeNotification(undefined, "committed"); + NotificationsApi.closeNotification(undefined, "committing"); + // display the committing notification + NotificationsApi.displayNotification(this.props.blueprint.name, "committing"); + this.setNotifications(); + // post blueprint (includes 'committed' notification) + Promise.all([BlueprintApi.handleCommitBlueprint(this.props.blueprint)]) + .then(() => { + // then after blueprint is posted, reload blueprint details + // to get details that were updated during commit (i.e. version) + // and call create image + Promise.all([BlueprintApi.reloadBlueprintDetails(this.props.blueprint)]) + .then(data => { + const blueprintToSet = Object.assign({}, this.props.blueprint, { + version: data[0].version + }); + this.props.setBlueprint(blueprintToSet); + this.handleCreateImage(); + }) + .catch(e => console.log(`Error in reload blueprint details: ${e}`)); + }) + .catch(e => console.log(`Error in blueprint commit: ${e}`)); + } + + handleCreateImage() { + NotificationsApi.displayNotification(this.props.blueprint.name, "imageWaiting"); + if (this.setNotifications) this.setNotifications(); + if (this.handleStartCompose) + this.handleStartCompose( + this.props.blueprint.name, + this.state.imageType, + this.state.imageName, + this.state.uploadService, + this.state.uploadSettings + ); + this.props.close(); + } + + handleStartCompose(blueprintName, composeType, imageName, uploadService, uploadSettings) { + const upload = { + image_name: imageName, + provider: uploadService, + settings: uploadSettings + }; + if (uploadService == "") { + this.props.startCompose(blueprintName, composeType); + } else { + this.props.startCompose(blueprintName, composeType, upload); + } + } + + handleNextStep(activeStep, toNextStep) { + if (activeStep.name === "Review" || (activeStep.name === "Image type" && this.state.uploadService.length === 0)) { + if (this.isPendingChange()) this.handleCommit(); + else this.handleCreateImage(); + } else toNextStep(); + } + + render() { + const { formatMessage } = this.props.intl; + const { blueprint, imageTypes, providerSettings } = this.props; + const { showUploadAwsStep, showReviewStep, imageName, imageType, uploadService } = this.state; + + const providerCheckbox = (provider, displayName) => ( + + + + ); + + const imageStep = { + name: "Image type", + component: ( + + {this.isPendingChange() && ( + + )} + {blueprint.packages.length == 0 && ( + + )} +
+
+ +
+ {blueprint.name} + + + +
+
+ + + + {imageTypes.map(type => ( + + ))} + + + {imageType === "ami" && providerCheckbox("aws", "AWS")} +
+
+ ) + }; + + const uploadAuth = provider => ({ + name: "Authentication", + component: ( + + + + + {providerSettings[provider] !== undefined && ( +
+ {Object.keys(providerSettings[provider].auth).map(key => ( + + + + ))} +
+ )} +
+ ) + }); + + const uploadSettings = provider => ({ + name: "File upload", + component: ( + + + + + {providerSettings[provider] !== undefined && ( +
+ + this.setState({ imageName: event.target.value })} + isRequired + /> + + {Object.keys(providerSettings[provider].settings).map(key => ( + + + + ))} +
+ )} +
+ ) + }); + + const uploadStep = (provider, displayName) => ({ + name: `Upload to ${displayName}`, + steps: [uploadAuth(provider), uploadSettings(provider)] + }); + + const reviewStep = { + name: "Review", + component: ( + + {this.missingRequiredFields() && ( + + )} + + + <FormattedMessage defaultMessage="Create and upload image" /> + <Popover bodyContent={formatMessage(messages.infotip)} aria-label="process length popover"> + <OutlinedQuestionCircleIcon /> + </Popover> + + {formatMessage(messages.review)} + {providerSettings[uploadService] !== undefined && ( + + {Object.keys(providerSettings[uploadService].auth).map(key => ( + + + {formatMessage({ + id: "review-settings", + defaultMessage: providerSettings[uploadService].auth[key].displayText + })} + + + {providerSettings[uploadService].auth[key].isPassword && + this.state.uploadSettings[key] != undefined + ? "*".repeat(this.state.uploadSettings[key].length) + : this.state.uploadSettings[key]} + + + ))} + + + + {imageName} + {Object.keys(providerSettings[uploadService].settings).map(key => ( + + + {formatMessage({ + id: "review-settings", + defaultMessage: providerSettings[uploadService].settings[key].displayText + })} + + + {providerSettings[uploadService].settings[key].isPassword && + this.state.uploadSettings[key] != undefined + ? "*".repeat(this.state.uploadSettings[key].length) + : this.state.uploadSettings[key]} + + + ))} + + )} + + + ) + }; + + const steps = [ + imageStep, + ...(showUploadAwsStep ? [uploadStep("aws", "AWS")] : []), + ...(showReviewStep ? [reviewStep] : []) + ]; + + const createImageUploadFooter = ( + + + {({ activeStep, onNext, onBack, onClose }) => { + return ( + + + + + + ); + }} + + + ); + + return ( + + + + ); + } +} + +CreateImageUpload.propTypes = { + blueprint: PropTypes.shape({ + changed: PropTypes.bool, + description: PropTypes.string, + groups: PropTypes.array, + id: PropTypes.string, + localPendingChanges: PropTypes.array, + modules: PropTypes.array, + name: PropTypes.string, + packages: PropTypes.arrayOf(PropTypes.object), + version: PropTypes.string, + workspacePendingChanges: PropTypes.arrayOf(PropTypes.object) + }), + intl: intlShape.isRequired, + layout: PropTypes.shape({ + setNotifications: PropTypes.func + }) +}; + +CreateImageUpload.defaultProps = { + blueprint: {}, + layout: {} +}; + +CreateImageUploadModal.propTypes = { + blueprint: PropTypes.shape({ + changed: PropTypes.bool, + description: PropTypes.string, + groups: PropTypes.array, + id: PropTypes.string, + localPendingChanges: PropTypes.array, + modules: PropTypes.array, + name: PropTypes.string, + packages: PropTypes.arrayOf(PropTypes.object), + version: PropTypes.string, + workspacePendingChanges: PropTypes.arrayOf(PropTypes.object) + }), + composeQueueFetched: PropTypes.bool, + fetchingQueue: PropTypes.func, + clearQueue: PropTypes.func, + imageTypes: PropTypes.arrayOf(PropTypes.object), + fetchingComposeTypes: PropTypes.func, + providerSettings: PropTypes.objectOf(PropTypes.object), + fetchingUploadProviders: PropTypes.func, + setBlueprint: PropTypes.func, + intl: intlShape.isRequired, + startCompose: PropTypes.func, + layout: PropTypes.shape({ + setNotifications: PropTypes.func + }), + close: PropTypes.func.isRequired, + isOpen: PropTypes.bool +}; + +CreateImageUploadModal.defaultProps = { + blueprint: {}, + composeQueueFetched: true, + fetchingQueue: function() {}, + clearQueue: function() {}, + imageTypes: [], + providerSettings: {}, + fetchingComposeTypes: function() {}, + fetchingUploadProviders: function() {}, + setBlueprint: function() {}, + startCompose: function() {}, + layout: {}, + isOpen: false +}; + +const mapStateToProps = state => ({ + composeQueue: state.composes.queue, + composeQueueFetched: state.composes.queueFetched, + imageTypes: state.composes.composeTypes, + providerSettings: state.uploads.providerSettings +}); + +const mapDispatchToProps = dispatch => ({ + setBlueprint: blueprint => { + dispatch(setBlueprint(blueprint)); + }, + fetchingComposeTypes: () => { + dispatch(fetchingComposeTypes()); + }, + fetchingUploadProviders: () => { + dispatch(fetchingUploadProviders()); + }, + fetchingQueue: () => { + dispatch(fetchingQueue()); + }, + clearQueue: () => { + dispatch(clearQueue()); + }, + startCompose: (blueprintName, composeType, upload) => { + dispatch(startCompose(blueprintName, composeType, upload)); + } +}); + +export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(CreateImageUpload)); diff --git a/pages/blueprint/index.js b/pages/blueprint/index.js index d161237cd..fcc97521c 100644 --- a/pages/blueprint/index.js +++ b/pages/blueprint/index.js @@ -11,8 +11,8 @@ import Layout from "../../components/Layout/Layout"; import BlueprintContents from "../../components/ListView/BlueprintContents"; import ComponentDetailsView from "../../components/ListView/ComponentDetailsView"; import UserAccount from "../../components/Modal/UserAccount"; -import CreateImage from "../../components/Modal/CreateImage"; import EditDescription from "../../components/Modal/EditDescription"; +import CreateImageUpload from "../../components/Modal/CreateImageUpload"; import ExportBlueprint from "../../components/Modal/ExportBlueprint"; import StopBuild from "../../components/Modal/StopBuild"; import DeleteImage from "../../components/Modal/DeleteImage"; @@ -331,7 +331,7 @@ class BlueprintPage extends React.Component {
  • - +
  • @@ -555,7 +555,7 @@ class BlueprintPage extends React.Component { title={formatMessage(messages.noImagesTitle)} message={formatMessage(messages.noImagesMessage)} > - + )) || ( @@ -655,7 +655,7 @@ BlueprintPage.propTypes = { composeId: PropTypes.string, visible: PropTypes.bool }), - createImage: PropTypes.shape({ + CreateImageUpload: PropTypes.shape({ blueprint: PropTypes.object, visible: PropTypes.bool }), @@ -714,7 +714,7 @@ BlueprintPage.defaultProps = { setBlueprintHostname: function() {}, stopBuild: {}, deleteImage: {}, - createImage: {}, + CreateImageUpload: {}, userAccount: {}, dependenciesSortSetValue: function() {}, componentsSortSetValue: function() {}, @@ -764,7 +764,6 @@ const makeMapStateToProps = () => { state.inputs.selectedInput.component.dependencies, fetchedBlueprint.present.components ), - createImage: state.modals.createImage, userAccount: state.modals.userAccount, stopBuild: state.modals.stopBuild, deleteImage: state.modals.deleteImage, @@ -783,7 +782,6 @@ const makeMapStateToProps = () => { composeList: [], composesLoading: state.composes.fetchingComposes, blueprintPage: state.blueprintPage, - createImage: state.modals.createImage, userAccount: state.modals.userAccount, stopBuild: state.modals.stopBuild, deleteImage: state.modals.deleteImage, diff --git a/pages/blueprintEdit/index.js b/pages/blueprintEdit/index.js index a19924ba7..adb05e74a 100644 --- a/pages/blueprintEdit/index.js +++ b/pages/blueprintEdit/index.js @@ -9,7 +9,7 @@ import Layout from "../../components/Layout/Layout"; import BlueprintContents from "../../components/ListView/BlueprintContents"; import ComponentInputs from "../../components/ListView/ComponentInputs"; import ComponentDetailsView from "../../components/ListView/ComponentDetailsView"; -import CreateImage from "../../components/Modal/CreateImage"; +import CreateImageUpload from "../../components/Modal/CreateImageUpload"; import ExportBlueprint from "../../components/Modal/ExportBlueprint"; import PendingChanges from "../../components/Modal/PendingChanges"; import EmptyState from "../../components/EmptyState/EmptyState"; @@ -469,7 +469,7 @@ class EditBlueprintPage extends React.Component {
  • )}
  • - +
  • diff --git a/public/custom.css b/public/custom.css index b63ccd17d..94934fde3 100644 --- a/public/custom.css +++ b/public/custom.css @@ -65,7 +65,7 @@ position: -webkit-sticky; position: sticky; top: 0; - z-index: 1000; + z-index: 1; padding: 0; } .cmpsr-panel__body .toolbar-pf .btn-link { @@ -808,4 +808,36 @@ body { font-style: normal; font-weight: 700; text-rendering: optimizeLegibility; +} + +/* form group checkbox alignment fix */ +.pf-c-form__horizontal-group .pf-c-check, +.cc-c-form__static-text { + padding-top: var(--pf-global--spacer--form-element); + padding-bottom: var(--pf-global--spacer--form-element); +} + +.pf-c-form__horizontal-group .pf-c-check input[type=checkbox], +.cc-c-form__static-text input[type=checkbox] { + margin-top: 0px; +} + +.pf-c-form__horizontal-group .pf-c-check__label { + line-height: var(--pf-global--LineHeight--md); +} + +/* spacing below warning alert in wizard */ +.pf-c-wizard__main-body .pf-c-alert, +.cc-c-alert__warning { + margin-bottom: var(--pf-global--gutter); +} + +/* horizontal group with popover justification fix*/ +.cc-c-popover__horizontal-group { + display: flex; + justify-content: space-between; +} + +.cc-c-form__required-text { + margin-bottom: var(--pf-global--gutter); } \ No newline at end of file diff --git a/test/end-to-end/components/Blueprint.component.js b/test/end-to-end/components/Blueprint.component.js index af622e5d8..79323b4de 100644 --- a/test/end-to-end/components/Blueprint.component.js +++ b/test/end-to-end/components/Blueprint.component.js @@ -21,7 +21,7 @@ class Blueprint { } get createImageButton() { - return $(`${this.containerSelector} button[class="btn btn-default"]`).element(); + return $(`${this.containerSelector} button[id="create-image-button"]`).element(); } get moreDropdownMenu() { diff --git a/test/end-to-end/pages/EditPackages.page.js b/test/end-to-end/pages/EditPackages.page.js index cf2b5f564..6cd5a193d 100644 --- a/test/end-to-end/pages/EditPackages.page.js +++ b/test/end-to-end/pages/EditPackages.page.js @@ -28,7 +28,7 @@ class EditPackagesPage { } get createImageButton() { - return $("span=Create Image").element(); + return $(`button[id="create-image-button"]`).element(); } get moreButton() { diff --git a/test/end-to-end/pages/ViewBlueprint.page.js b/test/end-to-end/pages/ViewBlueprint.page.js index 547c946d7..38bf26497 100644 --- a/test/end-to-end/pages/ViewBlueprint.page.js +++ b/test/end-to-end/pages/ViewBlueprint.page.js @@ -23,7 +23,7 @@ class ViewBlueprintPage { get createImageButton() { // cannot use 'span=Create Image' because there're two Create Image buttons // another one is under Image tab - return $('.cmpsr-header__actions [id="cmpsr-btn-crt-image"] span').element(); + return $('.cmpsr-header__actions button[id="create-image-button"]').element(); } get moreButton() { diff --git a/test/end-to-end/pages/createImage.page.js b/test/end-to-end/pages/createImage.page.js index 6b1136f62..77fda6354 100644 --- a/test/end-to-end/pages/createImage.page.js +++ b/test/end-to-end/pages/createImage.page.js @@ -1,7 +1,7 @@ // Create Image Page class CreateImagePage { constructor() { - this.containerSelector = '[id="cmpsr-modal-crt-image"]'; + this.containerSelector = '[id="create-image-upload-wizard"]'; } loading() { @@ -9,31 +9,31 @@ class CreateImagePage { } get alertMessage() { - return $(`${this.containerSelector} .alert-warning`).element(); + return $(`${this.containerSelector} [id="pending-changes-alert"]`).element(); } get blueprintNameLabel() { - return $(`${this.containerSelector} .form-control-static`).element(); + return $(`${this.containerSelector} [id="blueprint-name"]`).element(); } get selectOption() { - return $$(`${this.containerSelector} select[id="textInput-modal-markup"] option`); + return $$(`${this.containerSelector} select[id="image-type"] option`); } get imageTypeSelect() { - return $('select[id="textInput-modal-markup"]').element(); + return $('select[id="image-type"]').element(); } get helpButton() { - return $(`${this.containerSelector} .pficon-help`).element(); + return $(`${this.containerSelector} [id="popover-icon"]`).element(); } get helpMessage() { - return $('[id="CreateImageInfotip"] .popover-content').element(); + return $(`[id="popover-help"]`).element(); } get createButton() { - return $(`${this.containerSelector} .btn-primary`); + return $(`${this.containerSelector} [id="continue-button"]`); } get commitAndCreateButton() { @@ -48,7 +48,7 @@ class CreateImagePage { get cancelButton() { return $(this.containerSelector) - .$("span=Cancel") + .$(`button[id="cancel-button"]`) .element(); } } diff --git a/test/end-to-end/specs/editPackages2.test.js b/test/end-to-end/specs/editPackages2.test.js index b980a8235..c4d3141f6 100644 --- a/test/end-to-end/specs/editPackages2.test.js +++ b/test/end-to-end/specs/editPackages2.test.js @@ -295,7 +295,8 @@ describe("Edit Blueprint Page", function() { it("should show a correct alert message in Create Image dialog", function() { expect(createImagePage.alertMessage.getText().trim()).to.equal( - "This blueprint has changes that are not committed. These changes will be committed before the image is created." + "Warning alert:\n" + + "This blueprint has changes that are not committed. These changes will be committed before the image is created." ); }); });