From ad1b226932ebd38c60321490b28ce5cad28a0c12 Mon Sep 17 00:00:00 2001 From: Inga Mai Date: Fri, 31 Jan 2020 12:03:03 +0100 Subject: [PATCH 01/48] Build frontend for new admin enterprise page --- app/views/enterprises/_info.html.erb | 71 +++++++----- app/views/enterprises/show.html.erb | 14 +-- config/locales/en.yml | 3 + config/locales/js-en.yml | 9 ++ frontend/src/app/angular4-modules.ts | 3 + .../enterprise-trial.modal.html | 109 ++++++++++++++++++ .../enterprise-trial.modal.ts | 101 ++++++++++++++++ .../enterprise/enterprise.component.html | 5 + .../enterprise/enterprise.component.ts | 72 ++++++++++++ .../common/openproject-common.module.ts | 2 + 10 files changed, 348 insertions(+), 41 deletions(-) create mode 100644 frontend/src/app/components/enterprise/enterprise-modal/enterprise-trial.modal.html create mode 100644 frontend/src/app/components/enterprise/enterprise-modal/enterprise-trial.modal.ts create mode 100644 frontend/src/app/components/enterprise/enterprise.component.html create mode 100644 frontend/src/app/components/enterprise/enterprise.component.ts diff --git a/app/views/enterprises/_info.html.erb b/app/views/enterprises/_info.html.erb index 5533619518..36c98b6d02 100644 --- a/app/views/enterprises/_info.html.erb +++ b/app/views/enterprises/_info.html.erb @@ -1,28 +1,43 @@ -
-
-

<%= t('admin.enterprise.upgrade_to_ee') %>

- <%= image_tag "enterprise_edition.png", class: "widget-box--teaser-image" %> - -

<%= t('homescreen.blocks.upsale.description') %>

- -
    -
  • - <%= t('homescreen.blocks.upsale.additional_features') %> -
  • -
  • - <%= t('homescreen.blocks.upsale.professional_support') %> -
  • -
-

- <%= t('homescreen.blocks.upsale.become_hero') %> <%= t('homescreen.blocks.upsale.you_contribute') %> -

- <%= link_to( "#{OpenProject::Static::Links.links[:upsale][:href]}/?utm_source=unknown&utm_medium=community-edition&utm_campaign=enterprise-admin", - { class: 'button -alt-highlight', - target: '_blank', - aria: {label: t('admin.enterprise.order')}, - title: t('admin.enterprise.order')}) do %> - <%= op_icon('button--icon icon-add') %> - <%= t('admin.enterprise.order') %> - <% end %> -
-
+<%#-- copyright +OpenProject is an open source project management software. +Copyright (C) 2012-2020 the OpenProject GmbH + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License version 3. + +OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +Copyright (C) 2006-2017 Jean-Philippe Lang +Copyright (C) 2010-2013 the ChiliProject Team + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +See docs/COPYRIGHT.rdoc for more details. + +++#%> + +

+ <%= t('homescreen.blocks.upsale.become_hero') %> <%= t('homescreen.blocks.upsale.you_contribute') %> +

+ + + + diff --git a/app/views/enterprises/show.html.erb b/app/views/enterprises/show.html.erb index 6e90fc535f..60cab9ab87 100644 --- a/app/views/enterprises/show.html.erb +++ b/app/views/enterprises/show.html.erb @@ -1,18 +1,6 @@ <% html_title t(:label_administration), t(:label_enterprise_edition) %> -<%= toolbar title: t(:label_enterprise_edition) do %> - <% if EnterpriseToken.show_banners? %> -
  • - <%= link_to( "#{OpenProject::Static::Links.links[:upsale][:href]}/?utm_source=unknown&utm_medium=community-edition&utm_campaign=enterprise-admin", - { class: 'button -alt-highlight', - target: '_blank', - title: t('admin.enterprise.order')}) do %> - <%= op_icon('button--icon icon-add') %> - <%= t('admin.enterprise.order') %> - <% end %> -
  • - <% end %> -<% end %> +<%= toolbar title: t(:label_enterprise_edition) %> <%= error_messages_for 'token' %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 472acda9e0..f5dbca0048 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -79,6 +79,9 @@ en: paste: "Paste your Enterprise Edition support token" required_for_feature: "This feature is only available with an active Enterprise Edition support token." enterprise_link: "For more information, click here." + start_trial: 'Start free trial' + book_now: 'Book now' + get_quote: 'Get a quote' announcements: show_until: Show until diff --git a/config/locales/js-en.yml b/config/locales/js-en.yml index 8b4904e33f..1a288e8b9a 100644 --- a/config/locales/js-en.yml +++ b/config/locales/js-en.yml @@ -181,6 +181,15 @@ en: edit_query: 'Edit query' new_group: 'New group' reset_to_defaults: 'Reset to defaults' + enterprise: + start_trial: 'Start free trial' + test_ee: 'Test the Enterprise Edition 30 days for free' + label_company: 'Company' + label_first_name: 'First name' + label_last_name: 'Last name' + label_email: 'Email' + label_domain: 'Domain' + next_step: 'In the next step we will send you an email to the email-address provided.' custom_actions: date: diff --git a/frontend/src/app/angular4-modules.ts b/frontend/src/app/angular4-modules.ts index aaf98a17a8..032c8c097d 100644 --- a/frontend/src/app/angular4-modules.ts +++ b/frontend/src/app/angular4-modules.ts @@ -39,6 +39,8 @@ import {ConfirmDialogModal} from "core-components/modals/confirm-dialog/confirm- import {ConfirmDialogService} from "core-components/modals/confirm-dialog/confirm-dialog.service"; import {DynamicContentModal} from "core-components/modals/modal-wrapper/dynamic-content.modal"; import {PasswordConfirmationModal} from "core-components/modals/request-for-confirmation/password-confirmation.modal"; +import {EnterpriseComponent} from "core-components/enterprise/enterprise.component"; +import {EnterpriseTrialModal} from "core-components/enterprise/enterprise-modal/enterprise-trial.modal"; import {OpenprojectFieldsModule} from "core-app/modules/fields/openproject-fields.module"; import {OpenprojectCommonModule} from "core-app/modules/common/openproject-common.module"; import {CommentService} from "core-components/wp-activity/comment-service"; @@ -145,6 +147,7 @@ import {OpenprojectMembersModule} from "core-app/modules/members/members.module" DynamicContentModal, PasswordConfirmationModal, WpPreviewModal, + EnterpriseTrialModal, // Main menu MainMenuResizerComponent, diff --git a/frontend/src/app/components/enterprise/enterprise-modal/enterprise-trial.modal.html b/frontend/src/app/components/enterprise/enterprise-modal/enterprise-trial.modal.html new file mode 100644 index 0000000000..b811bcf40e --- /dev/null +++ b/frontend/src/app/components/enterprise/enterprise-modal/enterprise-trial.modal.html @@ -0,0 +1,109 @@ +
    +
    +
    +

    {{ text.label_test_ee }}

    + + + + +
    + +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    + + +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    +

    text.next_step

    +
    + +
    +
    \ No newline at end of file diff --git a/frontend/src/app/components/enterprise/enterprise-modal/enterprise-trial.modal.ts b/frontend/src/app/components/enterprise/enterprise-modal/enterprise-trial.modal.ts new file mode 100644 index 0000000000..0960c88ab0 --- /dev/null +++ b/frontend/src/app/components/enterprise/enterprise-modal/enterprise-trial.modal.ts @@ -0,0 +1,101 @@ +// -- copyright +// OpenProject is an open source project management software. +// Copyright (C) 2012-2020 the OpenProject GmbH +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License version 3. +// +// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +// Copyright (C) 2006-2013 Jean-Philippe Lang +// Copyright (C) 2010-2013 the ChiliProject Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// See docs/COPYRIGHT.rdoc for more details. +// ++ + +import {OpModalComponent} from "app/components/op-modals/op-modal.component"; +import {OpModalLocalsToken} from "app/components/op-modals/op-modal.service"; +import {ChangeDetectorRef, Component, ElementRef, Inject} from "@angular/core"; +import {OpModalLocalsMap} from "app/components/op-modals/op-modal.types"; +import {I18nService} from "app/modules/common/i18n/i18n.service"; + +export interface EnterpriseTrialOptions { + text:{ + title:string; + text:string; + button_continue?:string; + button_cancel?:string; + }; + closeByEscape?:boolean; + showClose?:boolean; + closeByDocument?:boolean; +} + +@Component({ + templateUrl: './enterprise-trial.modal.html' +}) +export class EnterpriseTrialModal extends OpModalComponent { + + public showClose:boolean; + + public confirmed = false; + + private options:EnterpriseTrialOptions; + + public text:any = { + title: this.I18n.t('js.modals.form_submit.title'), + text: this.I18n.t('js.modals.form_submit.text'), + button_submit: this.I18n.t('js.modals.button_submit'), + button_cancel: this.I18n.t('js.modals.button_cancel'), + close_popup: this.I18n.t('js.close_popup_title'), + label_test_ee: this.I18n.t('js.admin.enterprise.test_ee'), + label_company: this.I18n.t('js.admin.enterprise.label_company'), + label_first_name: this.I18n.t('js.admin.enterprise.label_first_name'), + label_last_name: this.I18n.t('js.admin.enterprise.label_last_name'), + label_email: this.I18n.t('js.admin.enterprise.label_email'), + label_domain: this.I18n.t('js.admin.enterprise.label_domain'), + next_step: this.I18n.t('js.admin.enterprise.next_step') + }; + + constructor(readonly elementRef:ElementRef, + @Inject(OpModalLocalsToken) public locals:OpModalLocalsMap, + readonly cdRef:ChangeDetectorRef, + readonly I18n:I18nService) { + + super(locals, cdRef, elementRef); + + this.options = locals.options || {}; + this.closeOnEscape = _.defaultTo(this.options.closeByEscape, true); + this.closeOnOutsideClick = _.defaultTo(this.options.closeByDocument, true); + this.showClose = _.defaultTo(this.options.showClose, true); + + // override default texts if any + this.text = _.defaults(this.options.text, this.text); + } + + public submit(evt:JQuery.TriggeredEvent) { + // open next window + // this.confirmMailAddress(); + // waiting -> show status and btn "Check status" + // confirmed -> show confirmed, enable btn "Continue" + // onclick of continue: this.closeMe(evt); + } + + public confirmMailAddress() { + this.confirmed = true; + } +} + diff --git a/frontend/src/app/components/enterprise/enterprise.component.html b/frontend/src/app/components/enterprise/enterprise.component.html new file mode 100644 index 0000000000..032a2a9e3d --- /dev/null +++ b/frontend/src/app/components/enterprise/enterprise.component.html @@ -0,0 +1,5 @@ +
    + + + +
    \ No newline at end of file diff --git a/frontend/src/app/components/enterprise/enterprise.component.ts b/frontend/src/app/components/enterprise/enterprise.component.ts new file mode 100644 index 0000000000..c98c966fe8 --- /dev/null +++ b/frontend/src/app/components/enterprise/enterprise.component.ts @@ -0,0 +1,72 @@ +// -- copyright +// OpenProject is a project management system. +// Copyright (C) 2012-2015 the OpenProject Foundation (OPF) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License version 3. +// +// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +// Copyright (C) 2006-2013 Jean-Philippe Lang +// Copyright (C) 2010-2013 the ChiliProject Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// See doc/COPYRIGHT.rdoc for more details. +// ++ + +import {Component, Input} from "@angular/core"; +import {enterpriseEditionUrl} from "core-app/globals/constants.const"; +import {I18nService} from "core-app/modules/common/i18n/i18n.service"; +import {DynamicBootstrapper} from "core-app/globals/dynamic-bootstrapper"; +import {EnterpriseTrialModal} from "core-components/enterprise/enterprise-modal/enterprise-trial.modal"; +import {OpModalService} from "core-components/op-modals/op-modal.service"; +import {Injector} from "@angular/core"; + + +@Component({ + selector: 'enterprise', + templateUrl: '/app/components/enterprise/enterprise.component.html' +}) +export class EnterpriseComponent { + @Input() public leftMargin:boolean = false; + @Input() public textMessage:string; + @Input() public linkMessage:string; + @Input() public opReferrer:string; + + public text:any = { + enterpriseFeature: this.I18n.t('js.upsale.ee_only'), + }; + + constructor(protected I18n:I18nService, + protected opModalService:OpModalService, + readonly injector:Injector) { + } + + public openTrialModal() { + this.opModalService.show(EnterpriseTrialModal, this.injector); + } + + public eeLink() { + if (this.opReferrer) { + return enterpriseEditionUrl + '&op_referrer=' + this.opReferrer; + } else { + return enterpriseEditionUrl; + } + } +} + +DynamicBootstrapper.register({ + selector: 'enterprise', cls: EnterpriseComponent +}); diff --git a/frontend/src/app/modules/common/openproject-common.module.ts b/frontend/src/app/modules/common/openproject-common.module.ts index 6626c1a60a..801c527a01 100644 --- a/frontend/src/app/modules/common/openproject-common.module.ts +++ b/frontend/src/app/modules/common/openproject-common.module.ts @@ -63,6 +63,7 @@ import {ContentTabsComponent} from "core-app/modules/common/tabs/content-tabs/co import {EditableToolbarTitleComponent} from "core-app/modules/common/editable-toolbar-title/editable-toolbar-title.component"; import {UserAvatarComponent} from "core-components/user/user-avatar/user-avatar.component"; import {EnterpriseBannerComponent} from "core-components/enterprise-banner/enterprise-banner.component"; +import {EnterpriseComponent} from "core-components/enterprise/enterprise.component"; import {EnterpriseBannerBootstrapComponent} from "core-components/enterprise-banner/enterprise-banner-bootstrap.component"; import {DynamicModule} from "ng-dynamic-component"; import {VersionAutocompleterComponent} from "core-app/modules/common/autocomplete/version-autocompleter.component"; @@ -264,6 +265,7 @@ export function bootstrapModule(injector:Injector) { // Enterprise Edition EnterpriseBannerComponent, EnterpriseBannerBootstrapComponent, + EnterpriseComponent, // Autocompleter CreateAutocompleterComponent, From 739419799840f9e069615e9abc9b03c065bc6f62 Mon Sep 17 00:00:00 2001 From: Inga Mai Date: Fri, 14 Feb 2020 10:02:53 +0100 Subject: [PATCH 02/48] Successful happy path; WIP: error handling --- .../stylesheets/content/_enterprise.sass | 21 ++ app/helpers/augur_helper.rb | 7 + app/views/enterprises/_info.html.erb | 27 +- config/locales/js-en.yml | 32 ++- frontend/src/app/angular4-modules.ts | 5 +- .../enterprise-trial.modal.html | 236 +++++++++++------- .../enterprise-trial.modal.ts | 170 +++++++++++-- .../enterprise/enterprise.component.html | 6 +- .../enterprise/enterprise.component.sass | 1 + .../enterprise/enterprise.component.ts | 27 +- lib/open_project/configuration.rb | 5 +- 11 files changed, 386 insertions(+), 151 deletions(-) create mode 100644 app/helpers/augur_helper.rb create mode 100644 frontend/src/app/components/enterprise/enterprise.component.sass diff --git a/app/assets/stylesheets/content/_enterprise.sass b/app/assets/stylesheets/content/_enterprise.sass index 8bb30195be..02439a5b04 100644 --- a/app/assets/stylesheets/content/_enterprise.sass +++ b/app/assets/stylesheets/content/_enterprise.sass @@ -14,3 +14,24 @@ .token-form textarea font-family: "Lucida Console", Monaco, monospace max-width: 560px + +.upsale-benefits + list-style: none + display: flex + margin: 0 + li + margin: 15px + +#enterprise-trial-form + .form--field-instructions + color: $content-form-danger-zone-bg-color + margin-left: 0 + +#resend-link + float: right + +.status--confirmed + color: $button--alt-highlight-background-color +.status--waiting + color: orange + diff --git a/app/helpers/augur_helper.rb b/app/helpers/augur_helper.rb new file mode 100644 index 0000000000..12f736eb85 --- /dev/null +++ b/app/helpers/augur_helper.rb @@ -0,0 +1,7 @@ +module AugurHelper + def augur_content_security_policy + controller.append_content_security_policy_directives( + connect_src: %w(augur.openproject-edge.com) + ) + end +end \ No newline at end of file diff --git a/app/views/enterprises/_info.html.erb b/app/views/enterprises/_info.html.erb index 36c98b6d02..02c14281dc 100644 --- a/app/views/enterprises/_info.html.erb +++ b/app/views/enterprises/_info.html.erb @@ -26,18 +26,37 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. See docs/COPYRIGHT.rdoc for more details. ++#%> +

    - <%= t('homescreen.blocks.upsale.become_hero') %> <%= t('homescreen.blocks.upsale.you_contribute') %> + <%= t('js.admin.enterprise.upsale.become_hero') %> <%= t('js.admin.enterprise.upsale.you_contribute') %>

    -


    - <%= t('homescreen.blocks.upsale.become_hero') %> <%= t('homescreen.blocks.upsale.you_contribute') %> + <%= t('js.admin.enterprise.upsale.become_hero') %> <%= t('js.admin.enterprise.upsale.you_contribute') %>

    <%= link_to("#{OpenProject::Static::Links.links[:upsale][:href]}/?utm_source=unknown&utm_medium=community-edition&utm_campaign=form-configuration", { class: 'button -alt-highlight', diff --git a/config/locales/en.yml b/config/locales/en.yml index f5dbca0048..a4f0734ad7 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1182,13 +1182,13 @@ en: blocks: community: "OpenProject community" upsale: - become_hero: "Become a hero!" title: "Upgrade to Enterprise Edition" - description: "What are the benefits?" more_info: "More information" - additional_features: "Additional powerful premium features" - professional_support: "Professional support from the OpenProject experts" - you_contribute: "Developers need to pay their bills, too. With Enterprise Edition you substantially contribute to this Open-Source community effort." + text: > + The OpenProject Enterprise Edition builds on top of the Community Edition. + It includes premium features and professional support mainly aimed at organizations with more 10 users that manage business critical projects with OpenProject. + confidence: > + We deliver the confidence of a tested and supported enterprise-class project management software - with open source and open mind. links: upgrade_enterprise_edition: "Upgrade to Enterprise Edition" postgres_migration: "Migrating your installation to PostgreSQL" diff --git a/frontend/src/app/components/homescreen/blocks/new-features.component.sass b/frontend/src/app/components/homescreen/blocks/new-features.component.sass index 1151077831..99566a6165 100644 --- a/frontend/src/app/components/homescreen/blocks/new-features.component.sass +++ b/frontend/src/app/components/homescreen/blocks/new-features.component.sass @@ -1,6 +1,4 @@ .widget-box--description - display: flex - .widget-box--teaser-image background-image: var(--new-feature-teaser-image) min-width: 170px diff --git a/modules/ldap_groups/app/views/ldap_groups/synchronized_groups/upsale.html.erb b/modules/ldap_groups/app/views/ldap_groups/synchronized_groups/upsale.html.erb index 16d278e182..bc86f28644 100644 --- a/modules/ldap_groups/app/views/ldap_groups/synchronized_groups/upsale.html.erb +++ b/modules/ldap_groups/app/views/ldap_groups/synchronized_groups/upsale.html.erb @@ -6,18 +6,18 @@

    <%= t('admin.enterprise.upgrade_to_ee') %>

    <%= image_tag "enterprise_edition.png", class: "widget-box--teaser-image" %> -

    <%= t('homescreen.blocks.upsale.description') %>

    +

    <%= t('js.admin.enterprise.upsale.benefits.description') %>

    • - <%= t('homescreen.blocks.upsale.additional_features') %> + <%= t('js.admin.enterprise.upsale.benefits.premium_features_text') %>
    • - <%= t('homescreen.blocks.upsale.professional_support') %> + <%= t('js.admin.enterprise.upsale.benefits.professional_support_text') %>

    - <%= t('homescreen.blocks.upsale.become_hero') %> <%= t('homescreen.blocks.upsale.you_contribute') %> + <%= t('js.admin.enterprise.upsale.become_hero') %> <%= t('js.admin.enterprise.upsale.you_contribute') %>

    <%= link_to( "#{OpenProject::Static::Links.links[:upsale][:href]}/?utm_source=unknown&utm_medium=community-edition&utm_campaign=enterprise-ldap-groups", { class: 'button -alt-highlight', diff --git a/modules/openid_connect/app/views/openid_connect/providers/upsale.html.erb b/modules/openid_connect/app/views/openid_connect/providers/upsale.html.erb index f946f8e78a..37046d3d62 100644 --- a/modules/openid_connect/app/views/openid_connect/providers/upsale.html.erb +++ b/modules/openid_connect/app/views/openid_connect/providers/upsale.html.erb @@ -7,18 +7,18 @@

    <%= t('admin.enterprise.upgrade_to_ee') %>

    <%= image_tag "enterprise_edition.png", class: "widget-box--teaser-image" %> -

    <%= t('homescreen.blocks.upsale.description') %>

    +

    <%= t('js.admin.enterprise.upsale.benefits.description') %>

    • - <%= t('homescreen.blocks.upsale.additional_features') %> + <%= t('js.admin.enterprise.upsale.benefits.premium_features_text') %>
    • - <%= t('homescreen.blocks.upsale.professional_support') %> + <%= t('js.admin.enterprise.upsale.benefits.professional_support_text') %>

    - <%= t('homescreen.blocks.upsale.become_hero') %> <%= t('homescreen.blocks.upsale.you_contribute') %> + <%= t('js.admin.enterprise.upsale.become_hero') %> <%= t('js.admin.enterprise.upsale.you_contribute') %>

    <%= link_to( "#{OpenProject::Static::Links.links[:upsale][:href]}/?utm_source=unknown&utm_medium=community-edition&utm_campaign=enterprise-openid-connect", { class: 'button -alt-highlight', diff --git a/vendor/openproject-icon-font/src/external-link.svg b/vendor/openproject-icon-font/src/external-link.svg new file mode 100644 index 0000000000..30f6ea6932 --- /dev/null +++ b/vendor/openproject-icon-font/src/external-link.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file From 8431fb531528fa9fe1283697ba5fd92c29376bfa Mon Sep 17 00:00:00 2001 From: Henriette Dinger Date: Thu, 9 Apr 2020 09:10:24 +0200 Subject: [PATCH 29/48] Avoid double loading of components and remove unnecessary global variables --- app/views/enterprises/_current.html.erb | 8 ++++---- config/locales/js-en.yml | 2 +- .../ee-active-trial.component.ts | 11 ++++------- .../enterprise/enterprise-base.component.ts | 4 ---- .../ee-trial-waiting.component.ts | 2 +- .../components/enterprise/enterprise-trial.service.ts | 9 ++------- frontend/src/app/global-dynamic-components.const.ts | 5 +++++ 7 files changed, 17 insertions(+), 24 deletions(-) diff --git a/app/views/enterprises/_current.html.erb b/app/views/enterprises/_current.html.erb index 53224492a4..5514c2f40d 100644 --- a/app/views/enterprises/_current.html.erb +++ b/app/views/enterprises/_current.html.erb @@ -5,9 +5,9 @@ data-expires-at="<%= (!@current_token.will_expire?) ? t('js.admin.enterprise.upsale.unlimited') : (format_date @current_token.expires_at) %>"> -<%= form_tag({ action: :destroy }, - method: :delete) do %> +<%= form_tag({}, method: :delete) do %> - <%= styled_button_tag t(:button_delete), type: 'submit', class: '-with-icon icon-delete' %> + <%= styled_button_tag t(:button_delete), + method: :delete, + class: '-with-icon icon-delete' %> <% end %> - diff --git a/config/locales/js-en.yml b/config/locales/js-en.yml index 20f86031ad..efb639b474 100644 --- a/config/locales/js-en.yml +++ b/config/locales/js-en.yml @@ -208,7 +208,7 @@ en: resend_link: "Resend" resend_success: "Email has been resent. Please check your emails and click the confirmation link provided." resend_warning: "Could not resend email." - session_timeout: "Your session timed out. Please try to resend email." + session_timeout: "Your session timed out. Please try to reload the page or resend email." status_label: "Status:" status_confirmed: "confirmed" status_waiting: "email sent - waiting for confirmation" diff --git a/frontend/src/app/components/enterprise/enterprise-active-trial/ee-active-trial.component.ts b/frontend/src/app/components/enterprise/enterprise-active-trial/ee-active-trial.component.ts index 129fc962c7..8309c424c9 100644 --- a/frontend/src/app/components/enterprise/enterprise-active-trial/ee-active-trial.component.ts +++ b/frontend/src/app/components/enterprise/enterprise-active-trial/ee-active-trial.component.ts @@ -32,8 +32,10 @@ import {baseUrlAugur, EnterpriseTrialService} from "app/components/enterprise/en import {DynamicBootstrapper} from "core-app/globals/dynamic-bootstrapper"; import {HttpClient, HttpErrorResponse} from "@angular/common/http"; +export const enterpriseActiveTrialSelector = 'enterprise-active-trial'; + @Component({ - selector: 'enterprise-active-trial', + selector: enterpriseActiveTrialSelector, templateUrl: './ee-active-trial.component.html', styleUrls: ['./ee-active-trial.component.sass'] }) @@ -86,7 +88,7 @@ export class EEActiveTrialComponent implements OnInit { .then((userData:any) => { this.subscriber = userData.first_name + ' ' + userData.last_name; this.email = userData.email; - this.eeTrialService.retryConfirmation(this.eeTrialService.delay, this.eeTrialService.retries); + this.eeTrialService.retryConfirmation(); }) .catch((error:HttpErrorResponse) => { this.eeTrialService.cancelled = true; @@ -98,8 +100,3 @@ export class EEActiveTrialComponent implements OnInit { return gon ? gon.ee_trial_key : undefined; } } - -DynamicBootstrapper.register({ - selector: 'enterprise-active-trial', cls: EEActiveTrialComponent -}); - diff --git a/frontend/src/app/components/enterprise/enterprise-base.component.ts b/frontend/src/app/components/enterprise/enterprise-base.component.ts index ec904b9f95..b84f81bfaa 100644 --- a/frontend/src/app/components/enterprise/enterprise-base.component.ts +++ b/frontend/src/app/components/enterprise/enterprise-base.component.ts @@ -69,7 +69,3 @@ export class EnterpriseBaseComponent { return this.eeTrialService.status === undefined; } } - -DynamicBootstrapper.register({ - selector: enterpriseBaseSelector, cls: EnterpriseBaseComponent -}); diff --git a/frontend/src/app/components/enterprise/enterprise-trial-waiting/ee-trial-waiting.component.ts b/frontend/src/app/components/enterprise/enterprise-trial-waiting/ee-trial-waiting.component.ts index d9e7100db2..c22f5302bc 100644 --- a/frontend/src/app/components/enterprise/enterprise-trial-waiting/ee-trial-waiting.component.ts +++ b/frontend/src/app/components/enterprise/enterprise-trial-waiting/ee-trial-waiting.component.ts @@ -64,7 +64,7 @@ export class EETrialWaitingComponent { .toPromise() .then(() => { this.notificationsService.addSuccess(this.text.resend_success); - this.eeTrialService.retryConfirmation(this.eeTrialService.delay, this.eeTrialService.retries); + this.eeTrialService.retryConfirmation(); }) .catch((error:HttpErrorResponse) => { this.notificationsService.addError(this.text.resend_warning); diff --git a/frontend/src/app/components/enterprise/enterprise-trial.service.ts b/frontend/src/app/components/enterprise/enterprise-trial.service.ts index cf0480b933..b475da4db7 100644 --- a/frontend/src/app/components/enterprise/enterprise-trial.service.ts +++ b/frontend/src/app/components/enterprise/enterprise-trial.service.ts @@ -20,10 +20,6 @@ export class EnterpriseTrialService { public status:'mailSubmitted'|'startTrial'|undefined; public errorMsg:string|undefined; - // retry confirmation - public delay = 5000; // wait 5s until next request - public retries = 60; // keep trying for 5 minutes - constructor(readonly I18n:I18nService, protected http:HttpClient, readonly pathHelper:PathHelperService, @@ -46,7 +42,7 @@ export class EnterpriseTrialService { .then((enterpriseTrial:any) => { this.trialLink = enterpriseTrial._links.self.href; - this.retryConfirmation(this.delay, this.retries); + this.retryConfirmation(); }) .catch((error:HttpErrorResponse) => { // mail is invalid or user already created a trial @@ -96,7 +92,6 @@ export class EnterpriseTrialService { } else if (_.get(error, 'error._type') === 'Error') { this.notificationsService.addError(error.error.message); } else { - // backend returned an unsuccessful response code this.notificationsService.addError(error.error || I18n.t('js.error.internal')); } }); @@ -133,7 +128,7 @@ export class EnterpriseTrialService { } // retry request while waiting for mail confirmation - public retryConfirmation(delay:number, retries:number) { + public retryConfirmation(delay:number = 5000, retries:number = 60) { if (this.cancelled || this.confirmed) { return; } else if (retries === 0) { diff --git a/frontend/src/app/global-dynamic-components.const.ts b/frontend/src/app/global-dynamic-components.const.ts index 272652c5a6..449bfba8e1 100644 --- a/frontend/src/app/global-dynamic-components.const.ts +++ b/frontend/src/app/global-dynamic-components.const.ts @@ -130,6 +130,10 @@ import { EnterpriseBaseComponent, enterpriseBaseSelector } from "core-components/enterprise/enterprise-base.component"; +import { + EEActiveTrialComponent, + enterpriseActiveTrialSelector +} from "core-components/enterprise/enterprise-active-trial/ee-active-trial.component"; export const globalDynamicComponents:OptionalBootstrapDefinition[] = [ { selector: appBaseSelector, cls: ApplicationBaseComponent }, @@ -166,6 +170,7 @@ export const globalDynamicComponents:OptionalBootstrapDefinition[] = [ { selector: collapsibleSectionAugmentSelector, cls: CollapsibleSectionComponent }, { selector: enterpriseBannerSelector, cls: EnterpriseBannerBootstrapComponent }, { selector: enterpriseBaseSelector, cls: EnterpriseBaseComponent }, + { selector: enterpriseActiveTrialSelector, cls: EEActiveTrialComponent }, { selector: projectMenuAutocompleteSelector, cls: ProjectMenuAutocompleteComponent }, { selector: remoteFieldUpdaterSelector, cls: RemoteFieldUpdaterComponent }, { selector: wpEmbeddedTableEntrySelector, cls: WorkPackageEmbeddedTableEntryComponent }, From 650b57fd3d7854befaa4fd2659b4607813191966 Mon Sep 17 00:00:00 2001 From: Henriette Dinger Date: Thu, 9 Apr 2020 10:07:36 +0200 Subject: [PATCH 30/48] Handle cases where the user confirmed the mail after the browser stopped checking it. In this case the `/details` url returns an error. Without this additional check, the user is stuck for ever with the waiting screen. --- .../enterprise-active-trial/ee-active-trial.component.ts | 3 ++- .../ee-trial-waiting.component.ts | 9 +++++++-- .../components/enterprise/enterprise-trial.service.ts | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/components/enterprise/enterprise-active-trial/ee-active-trial.component.ts b/frontend/src/app/components/enterprise/enterprise-active-trial/ee-active-trial.component.ts index 8309c424c9..b81a9de6b8 100644 --- a/frontend/src/app/components/enterprise/enterprise-active-trial/ee-active-trial.component.ts +++ b/frontend/src/app/components/enterprise/enterprise-active-trial/ee-active-trial.component.ts @@ -91,7 +91,8 @@ export class EEActiveTrialComponent implements OnInit { this.eeTrialService.retryConfirmation(); }) .catch((error:HttpErrorResponse) => { - this.eeTrialService.cancelled = true; + // Check whether the mail has been confirmed by now + this.eeTrialService.getToken(); }); } diff --git a/frontend/src/app/components/enterprise/enterprise-trial-waiting/ee-trial-waiting.component.ts b/frontend/src/app/components/enterprise/enterprise-trial-waiting/ee-trial-waiting.component.ts index c22f5302bc..92f1f754bc 100644 --- a/frontend/src/app/components/enterprise/enterprise-trial-waiting/ee-trial-waiting.component.ts +++ b/frontend/src/app/components/enterprise/enterprise-trial-waiting/ee-trial-waiting.component.ts @@ -66,8 +66,13 @@ export class EETrialWaitingComponent { this.notificationsService.addSuccess(this.text.resend_success); this.eeTrialService.retryConfirmation(); }) - .catch((error:HttpErrorResponse) => { - this.notificationsService.addError(this.text.resend_warning); + .catch(() => { + if (this.eeTrialService.trialLink) { + // Check whether the mail has been confirmed by now + this.eeTrialService.getToken(); + } else { + this.notificationsService.addError(this.text.resend_warning); + } }); } } diff --git a/frontend/src/app/components/enterprise/enterprise-trial.service.ts b/frontend/src/app/components/enterprise/enterprise-trial.service.ts index b475da4db7..b4ff19a8a5 100644 --- a/frontend/src/app/components/enterprise/enterprise-trial.service.ts +++ b/frontend/src/app/components/enterprise/enterprise-trial.service.ts @@ -55,7 +55,7 @@ export class EnterpriseTrialService { } // get a token from the trial link if user confirmed mail - private getToken() { + public getToken() { // 2) GET /public/v1/trials/:id this.http .get(this.trialLink) From 75c6870d8737a5e67ba10cd9680b61a1492a50a6 Mon Sep 17 00:00:00 2001 From: Henriette Dinger Date: Thu, 9 Apr 2020 10:32:54 +0200 Subject: [PATCH 31/48] Fix specs that broke due to the restructuring of the enterprise page --- spec/controllers/enterprises_controller_spec.rb | 2 +- spec/features/admin/enterprise_spec.rb | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/spec/controllers/enterprises_controller_spec.rb b/spec/controllers/enterprises_controller_spec.rb index e57b1648d7..5f270184cc 100644 --- a/spec/controllers/enterprises_controller_spec.rb +++ b/spec/controllers/enterprises_controller_spec.rb @@ -73,7 +73,7 @@ describe EnterprisesController, type: :controller do it 'still renders #show with form' do expect(response).not_to render_template partial: 'enterprises/_current' - expect(response.body).to have_selector '.upsale-notification' + expect(response.body).to have_selector '.upsale-benefits' end end end diff --git a/spec/features/admin/enterprise_spec.rb b/spec/features/admin/enterprise_spec.rb index 7fcda53c6f..06b69192ab 100644 --- a/spec/features/admin/enterprise_spec.rb +++ b/spec/features/admin/enterprise_spec.rb @@ -52,7 +52,8 @@ describe 'Enterprise token', type: :feature, js: true do end it 'shows a teaser and token form without a token' do - expect(page).to have_selector('.upsale-notification a', text: 'Order Enterprise Edition') + expect(page).to have_selector('.button', text: 'Start free trial') + expect(page).to have_selector('.button', text: 'Book now') expect(textarea.value).to be_empty textarea.set 'foobar' @@ -78,9 +79,9 @@ describe 'Enterprise token', type: :feature, js: true do expect(page).to have_selector('.enterprise--active-token') expect(page.all('.attributes-key-value--key').map(&:text)) - .to eq ['Subscriber', 'Email', 'Valid since'] + .to eq ['Subscriber', 'Email', 'Maximum active users', 'Starts at', 'Expires at'] expect(page.all('.attributes-key-value--value').map(&:text)) - .to eq ['Foobar', 'foo@example.org', format_date(Date.today)] + .to eq ['Foobar', 'foo@example.org', 'Unlimited', format_date(Date.today), 'Unlimited'] expect(page).to have_selector('.button.icon-delete', text: I18n.t(:button_delete)) From 4deeda66f969732718d7eb4ef2847a0c6dd25d82 Mon Sep 17 00:00:00 2001 From: Henriette Dinger Date: Thu, 9 Apr 2020 11:06:20 +0200 Subject: [PATCH 32/48] Replace images of Enterprise tease page --- app/assets/images/installation_alerts.svg | 148 ++++++++++++++++++++++ app/assets/images/premium_features.png | Bin 27351 -> 0 bytes app/assets/images/premium_features.svg | 1 + app/assets/images/security_features.png | Bin 17535 -> 0 bytes app/views/enterprises/_info.html.erb | 4 +- 5 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 app/assets/images/installation_alerts.svg delete mode 100644 app/assets/images/premium_features.png create mode 100644 app/assets/images/premium_features.svg delete mode 100644 app/assets/images/security_features.png diff --git a/app/assets/images/installation_alerts.svg b/app/assets/images/installation_alerts.svg new file mode 100644 index 0000000000..bcd280fda8 --- /dev/null +++ b/app/assets/images/installation_alerts.svg @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/images/premium_features.png b/app/assets/images/premium_features.png deleted file mode 100644 index 292b85457558063cc474b31af11c6c81e575833e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27351 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 diff --git a/app/assets/images/premium_features.svg b/app/assets/images/premium_features.svg new file mode 100644 index 0000000000..cbb04f46a8 --- /dev/null +++ b/app/assets/images/premium_features.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/security_features.png b/app/assets/images/security_features.png deleted file mode 100644 index ddaf2e35b498468f9f3bba0e3ff530ea3501f8ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17535 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 t('js.admin.enterprise.upsale.benefits.description') %>
    - <%= image_tag "security_features.png", + <%= image_tag "installation_alerts.svg", class: "info-boxes--teaser-image", title: t('js.admin.enterprise.upsale.benefits.installation'), alt: t('js.admin.enterprise.upsale.benefits.installation') %> @@ -87,7 +87,7 @@ See docs/COPYRIGHT.rdoc for more details.
    - <%= image_tag "premium_features.png", + <%= image_tag "premium_features.svg", class: "info-boxes--teaser-image", title: t('js.admin.enterprise.upsale.benefits.premium_features'), alt: t('js.admin.enterprise.upsale.benefits.premium_features') %> From af0d32a98c208d00af155d656f2e5610687ded20 Mon Sep 17 00:00:00 2001 From: Henriette Dinger Date: Thu, 9 Apr 2020 11:11:03 +0200 Subject: [PATCH 33/48] Match breadcrumb to page header --- app/controllers/enterprises_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/enterprises_controller.rb b/app/controllers/enterprises_controller.rb index 26e7ec2a3d..13f663f5c2 100644 --- a/app/controllers/enterprises_controller.rb +++ b/app/controllers/enterprises_controller.rb @@ -99,7 +99,7 @@ class EnterprisesController < ApplicationController private def default_breadcrumb - t(:label_enterprise) + t(:label_enterprise_edition) end def show_local_breadcrumb From 4d74b2514190dde9806386757812963130dfaec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20G=C3=BCnther?= Date: Thu, 9 Apr 2020 08:13:31 +0200 Subject: [PATCH 34/48] Add webmock chrome functionality with billy --- .../admin/{ => enterprise}/enterprise_spec.rb | 0 spec/support/browsers/chrome.rb | 25 +++++++++++++++++++ 2 files changed, 25 insertions(+) rename spec/features/admin/{ => enterprise}/enterprise_spec.rb (100%) diff --git a/spec/features/admin/enterprise_spec.rb b/spec/features/admin/enterprise/enterprise_spec.rb similarity index 100% rename from spec/features/admin/enterprise_spec.rb rename to spec/features/admin/enterprise/enterprise_spec.rb diff --git a/spec/support/browsers/chrome.rb b/spec/support/browsers/chrome.rb index 0131eb3518..79a180467e 100644 --- a/spec/support/browsers/chrome.rb +++ b/spec/support/browsers/chrome.rb @@ -68,3 +68,28 @@ end register_chrome_headless 'en' # Register german locale for custom field decimal test register_chrome_headless 'de' + +# Register mocking proxy driver + +Capybara.register_driver :headless_chrome_billy do |app| + capabilities = Selenium::WebDriver::Remote::Capabilities.chrome( + acceptInsecureCerts: true, + loggingPrefs: { browser: 'ALL' } + ) + options = Selenium::WebDriver::Chrome::Options.new + options.add_argument('--window-size=1920,1080') + options.add_argument('--headless') + options.add_argument('--disable-gpu') + options.add_argument("--proxy-server=#{Billy.proxy.host}:#{Billy.proxy.port}") + options.add_argument('--proxy-bypass-list=127.0.0.1;localhost') + + Capybara::Selenium::Driver.new app, + browser: :chrome, + options: options, + desired_capabilities: capabilities, + driver_opts: { + log_path: Rails.root.join('log/chromedriver.log').to_s, + verbose: true, + } +end +Capybara.javascript_driver = :headless_chrome_billy \ No newline at end of file From 5f422e46d9a83de4339abb9ea37d0b2cab2f56eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20G=C3=BCnther?= Date: Thu, 9 Apr 2020 13:03:46 +0200 Subject: [PATCH 35/48] Test augur with puffing-billy to mock browser requests with a proxy --- Gemfile | 5 + Gemfile.lock | 24 ++ .../ee-trial-form.component.html | 29 ++- .../admin/enterprise/enterprise_trial_spec.rb | 217 ++++++++++++++++++ spec/rails_helper.rb | 1 + spec/support/browsers/chrome.rb | 33 +-- spec/support/browsers/firefox.rb | 23 +- spec/support/puffing_billy_proxy.rb | 39 ++++ spec/support/webmock.rb | 12 +- 9 files changed, 343 insertions(+), 40 deletions(-) create mode 100644 spec/features/admin/enterprise/enterprise_trial_spec.rb create mode 100644 spec/support/puffing_billy_proxy.rb diff --git a/Gemfile b/Gemfile index 038c288510..c7642637b8 100644 --- a/Gemfile +++ b/Gemfile @@ -221,8 +221,13 @@ group :test do gem 'fuubar', '~> 2.5.0' gem 'timecop', '~> 0.9.0' + + # Mock backend requests (for ruby tests) gem 'webmock', '~> 3.8.2', require: false + # Mock selenium requests through proxy (for feature tests) + gem 'puffing-billy', '~> 2.3.1' + gem 'equivalent-xml', '~> 0.6' gem 'json_spec', '~> 1.1.4' gem 'shoulda-matchers', '~> 3.1', require: nil diff --git a/Gemfile.lock b/Gemfile.lock index 65505d7ee2..fa55134132 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -358,6 +358,7 @@ GEM compare-xml (0.66) nokogiri (~> 1.8) concurrent-ruby (1.1.6) + cookiejar (0.3.3) cork (0.3.0) colored2 (~> 3.1) crack (0.4.3) @@ -458,6 +459,16 @@ GEM dry-equalizer (~> 0.3) dry-inflector (~> 0.1, >= 0.1.2) dry-logic (~> 1.0, >= 1.0.2) + em-http-request (1.1.5) + addressable (>= 2.3.4) + cookiejar (!= 0.3.1) + em-socksify (>= 0.3) + eventmachine (>= 1.0.3) + http_parser.rb (>= 0.6.0) + em-socksify (0.3.2) + eventmachine (>= 1.0.0.beta.4) + em-synchrony (1.0.6) + eventmachine (>= 1.0.0.beta.1) equivalent-xml (0.6.0) nokogiri (>= 1.4.3) erbse (0.1.4) @@ -465,6 +476,7 @@ GEM erubi (1.9.0) escape_utils (1.2.1) eventmachine (1.2.7) + eventmachine_httpserver (0.2.1) excon (0.72.0) execjs (2.7.0) factory_bot (5.1.1) @@ -533,6 +545,7 @@ GEM http-accept (1.7.0) http-cookie (1.0.3) domain_name (~> 0.5) + http_parser.rb (0.6.0) httpclient (2.8.3) i18n (1.8.2) concurrent-ruby (~> 1.0) @@ -689,6 +702,14 @@ GEM binding_of_caller (>= 0.7) pry (>= 0.9.11) public_suffix (4.0.3) + puffing-billy (2.3.1) + addressable (~> 2.5) + em-http-request (~> 1.1, >= 1.1.0) + em-synchrony + eventmachine (~> 1.2) + eventmachine_httpserver + http_parser.rb (~> 0.6.0) + multi_json puma (4.3.3) nio4r (~> 2.0) rack (2.2.2) @@ -885,6 +906,7 @@ GEM httpclient (>= 2.4) sys-filesystem (1.3.3) ffi + table_print (1.5.6) temple (0.8.2) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) @@ -1056,6 +1078,7 @@ DEPENDENCIES pry-rails (~> 0.3.6) pry-rescue (~> 1.5.0) pry-stack_explorer (~> 0.4.9.2) + puffing-billy (~> 2.3.1) puma (~> 4.3.1) rack-attack (~> 6.2.2) rack-mini-profiler @@ -1100,6 +1123,7 @@ DEPENDENCIES stringex (~> 2.8.5) svg-graph (~> 2.1.0) sys-filesystem (~> 1.3.3) + table_print test-prof (~> 0.11.0) thin (~> 1.7.2) timecop (~> 0.9.0) diff --git a/frontend/src/app/components/enterprise/enterprise-modal/enterprise-trial-form/ee-trial-form.component.html b/frontend/src/app/components/enterprise/enterprise-modal/enterprise-trial-form/ee-trial-form.component.html index 8ea5d736dd..10aea4bbe1 100644 --- a/frontend/src/app/components/enterprise/enterprise-modal/enterprise-trial-form/ee-trial-form.component.html +++ b/frontend/src/app/components/enterprise/enterprise-modal/enterprise-trial-form/ee-trial-form.component.html @@ -1,57 +1,67 @@
    - +
    - +
    - +
    - +
    - +
    {{ eeTrialService.errorMsg }}
    - +
    - +
    -