Convert query saving and sharing modal

pull/6275/head
Oliver Günther 7 years ago
parent bec23c33da
commit 236aa23344
No known key found for this signature in database
GPG Key ID: 88872239EB414F99
  1. 1
      config/locales/js-en.yml
  2. 12
      frontend/app/angular4-modules.ts
  3. 1
      frontend/app/angular4-transition-utils.ts
  4. 2
      frontend/app/components/modals/request-for-confirmation/request-for-confirmation.directive.ts
  5. 79
      frontend/app/components/modals/save-modal/save-modal.controller.ts
  6. 57
      frontend/app/components/modals/save-modal/save-modal.service.html
  7. 40
      frontend/app/components/modals/save-modal/save-modal.service.ts
  8. 56
      frontend/app/components/modals/save-modal/save-query.modal.html
  9. 107
      frontend/app/components/modals/save-modal/save-query.modal.ts
  10. 59
      frontend/app/components/modals/share-modal/query-sharing-form.component.ts
  11. 53
      frontend/app/components/modals/share-modal/query-sharing-form.directive.ts
  12. 16
      frontend/app/components/modals/share-modal/query-sharing-form.html
  13. 36
      frontend/app/components/modals/share-modal/query-sharing.modal.html
  14. 118
      frontend/app/components/modals/share-modal/query-sharing.modal.ts
  15. 96
      frontend/app/components/modals/share-modal/share-modal.controller.ts
  16. 30
      frontend/app/components/modals/share-modal/share-modal.service.html
  17. 40
      frontend/app/components/modals/share-modal/share-modal.service.ts
  18. 18
      frontend/app/components/op-context-menu/handlers/op-settings-dropdown-menu.directive.ts

@ -83,6 +83,7 @@ en:
description_subwork_package: "Child of work package #%{id}" description_subwork_package: "Child of work package #%{id}"
error: error:
internal: "An internal error has occurred." internal: "An internal error has occurred."
query_saving: "The query could not be saved."
filter: filter:
description: description:
text_open_filter: "Open this filter with 'ALT' and arrow keys." text_open_filter: "Open this filter with 'ALT' and arrow keys."

@ -75,7 +75,6 @@ import {
I18nToken, I18nToken,
saveModalToken, saveModalToken,
settingsModalToken, settingsModalToken,
shareModalToken,
TextileServiceToken, TextileServiceToken,
upgradeService, upgradeService,
upgradeServiceWithToken, upgradeServiceWithToken,
@ -220,6 +219,9 @@ import {ConfirmDialogModal} from "core-components/modals/confirm-dialog/confirm-
import {ConfirmDialogService} from "core-components/modals/confirm-dialog/confirm-dialog.service"; import {ConfirmDialogService} from "core-components/modals/confirm-dialog/confirm-dialog.service";
import {DynamicContentModal} from "core-components/modals/modal-wrapper/dynamic-content.modal"; import {DynamicContentModal} from "core-components/modals/modal-wrapper/dynamic-content.modal";
import {PasswordConfirmationModal} from "core-components/modals/request-for-confirmation/password-confirmation.modal"; import {PasswordConfirmationModal} from "core-components/modals/request-for-confirmation/password-confirmation.modal";
import {QuerySharingModal} from "core-components/modals/share-modal/query-sharing.modal";
import {SaveQueryModal} from "core-components/modals/save-modal/save-query.modal";
import {QuerySharingForm} from "core-components/modals/share-modal/query-sharing-form.component";
@NgModule({ @NgModule({
imports: [ imports: [
@ -250,10 +252,7 @@ import {PasswordConfirmationModal} from "core-components/modals/request-for-conf
upgradeServiceWithToken('wpMoreMenuService', wpMoreMenuServiceToken), upgradeServiceWithToken('wpMoreMenuService', wpMoreMenuServiceToken),
TimezoneService, TimezoneService,
upgradeServiceWithToken('wpDestroyModal', wpDestroyModalToken), upgradeServiceWithToken('wpDestroyModal', wpDestroyModalToken),
upgradeServiceWithToken('shareModal', shareModalToken),
upgradeServiceWithToken('saveModal', saveModalToken),
upgradeServiceWithToken('settingsModal', settingsModalToken), upgradeServiceWithToken('settingsModal', settingsModalToken),
upgradeServiceWithToken('exportModal', exportModalToken),
upgradeService('wpRelations', WorkPackageRelationsService), upgradeService('wpRelations', WorkPackageRelationsService),
UrlParamsHelperService, UrlParamsHelperService,
WorkPackageCacheService, WorkPackageCacheService,
@ -452,6 +451,9 @@ import {PasswordConfirmationModal} from "core-components/modals/request-for-conf
ConfirmDialogModal, ConfirmDialogModal,
DynamicContentModal, DynamicContentModal,
PasswordConfirmationModal, PasswordConfirmationModal,
QuerySharingModal,
SaveQueryModal,
QuerySharingForm,
// Notifications // Notifications
NotificationsContainerComponent, NotificationsContainerComponent,
@ -518,6 +520,8 @@ import {PasswordConfirmationModal} from "core-components/modals/request-for-conf
DynamicContentModal, DynamicContentModal,
ConfirmDialogModal, ConfirmDialogModal,
PasswordConfirmationModal, PasswordConfirmationModal,
QuerySharingModal,
SaveQueryModal,
// Notifications // Notifications
NotificationsContainerComponent, NotificationsContainerComponent,

@ -38,7 +38,6 @@ export const $stateToken = new InjectionToken<StateService>('$state');
export const $sceToken = new InjectionToken<ng.ISCEService>('$sceToken'); export const $sceToken = new InjectionToken<ng.ISCEService>('$sceToken');
export const I18nToken = new InjectionToken<op.I18n>('I18n'); export const I18nToken = new InjectionToken<op.I18n>('I18n');
export const shareModalToken = new InjectionToken<any>('shareModal');
export const saveModalToken = new InjectionToken<any>('saveModal'); export const saveModalToken = new InjectionToken<any>('saveModal');
export const settingsModalToken = new InjectionToken<any>('settingsModal'); export const settingsModalToken = new InjectionToken<any>('settingsModal');
export const exportModalToken = new InjectionToken<any>(' exportModal'); export const exportModalToken = new InjectionToken<any>(' exportModal');

@ -53,7 +53,7 @@ export class RequestForConfirmationController {
const confirmModal = this.opModalService.show(PasswordConfirmationModal); const confirmModal = this.opModalService.show(PasswordConfirmationModal);
confirmModal.closingEvent.subscribe((modal:PasswordConfirmationModal) => { confirmModal.closingEvent.subscribe((modal:PasswordConfirmationModal) => {
if (modal.confirmed) { if (modal.confirmed) {
this.appendPassword(modal.password_confirmation); this.appendPassword(modal.password_confirmation!);
this.$element.trigger('submit'); this.$element.trigger('submit');
} }
}); });

@ -1,79 +0,0 @@
//-- 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 {wpControllersModule} from '../../../angular-modules';
import {WorkPackagesListService} from '../../wp-list/wp-list.service';
import {States} from '../../states.service';
import {WorkPackageNotificationService} from '../../wp-edit/wp-notification.service';
import {QueryResource} from 'core-app/modules/hal/resources/query-resource';
function SaveModalController(this:any,
$scope:any,
saveModal:any,
states:States,
wpListService:WorkPackagesListService,
wpNotificationsService:WorkPackageNotificationService,
$q:ng.IQService,
NotificationsService:any) {
this.name = 'Save';
this.closeMe = saveModal.deactivate;
$scope.isStarred = false;
$scope.isPublic = false;
$scope.isBusy = false;
$scope.setValues = (isStarred:boolean, isPublic:boolean) => {
$scope.isStarred = isStarred;
$scope.isPublic = isPublic;
};
$scope.saveQueryAs = (name:string) => {
if ($scope.isBusy) {
return console.warn('Skipping additional save ');
}
$scope.isBusy = true;
const query = states.query.resource.value!;
query.public = $scope.isPublic;
wpListService
.create(query, name)
.then(async (savedQuery:QueryResource) => {
if ($scope.isStarred && !savedQuery.starred) {
return wpListService.toggleStarred(savedQuery).then(() => saveModal.deactivate());
}
saveModal.deactivate();
return $q.when(true);
})
.catch((error:any) => wpNotificationsService.handleErrorResponse(error))
.then(() => this.isBusy = false); // Same as .finally()
};
}
wpControllersModule.controller('SaveModalController', SaveModalController);

@ -1,57 +0,0 @@
<div class="op-modal--portal">
<div class="op-modal--modal-container">
<div class="op-modal--modal-header">
<a>
<i
class="icon-close"
ng-click="$ctrl.closeMe()"
title="{{ ::I18n.t('js.close_popup_title') }}">
</i>
</a>
</div>
<form name="modalSaveForm" class="form">
<h3>{{ ::I18n.t('js.label_save_as') }}</h3>
<div class="form--field -required">
<label class="form--label">
{{ ::I18n.t('js.modals.label_name') }}
</label>
<div class="form--field-container">
<div class="form--text-field-container">
<input
class="form--text-field"
type="text"
name="save_query_name"
autofocus
id="save-query-name"
ng-model="queryName" required />
</div>
</div>
</div>
<section class="form--section">
<h3>{{ ::I18n.t('js.label_visibility_settings') }}</h3>
<query-sharing-form
is-save="true"
on-change="setValues(isStarred, isPublic)"
is-starred="isStarred"
is-public="isPublic">
</query-sharing-form>
</section>
<div class="form--space">
<button class="button -highlight -with-icon icon-checkmark"
ng-click="saveQueryAs(queryName)"
ng-disabled="isBusy || modalSaveForm.$invalid">
{{ ::I18n.t('js.modals.button_save') }}
</button>
<button class="button" ng-click="$ctrl.closeMe()">
{{ ::I18n.t('js.modals.button_cancel') }}
</button>
</div>
</form>
</div>
</div>

@ -1,40 +0,0 @@
//-- 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 {wpControllersModule} from '../../../angular-modules';
function saveModalService(btfModal:any) {
return btfModal({
controller: 'SaveModalController',
controllerAs: '$ctrl',
afterFocusOn: '#work-packages-settings-button',
templateUrl: '/components/modals/save-modal/save-modal.service.html'
});
}
wpControllersModule.factory('saveModal', saveModalService);

@ -0,0 +1,56 @@
<div class="op-modal--portal ">
<div class="op-modal--modal-container wp-table--configuration-modal loading-indicator--location"
data-indicator-name="modal"
tabindex="0">
<div class="op-modal--modal-header">
<a class="op-modal--modal-close-button">
<i
class="icon-close"
(click)="closeMe($event)"
[attr.title]="text.closePopup">
</i>
</a>
</div>
<form name="modalSaveForm" class="form">
<h3 [textContent]="text.save_as"></h3>
<div class="form--field -required">
<label class="form--label" for="save-query-name" [textContent]="text.label_name"></label>
<div class="form--field-container">
<div class="form--text-field-container">
<input
class="form--text-field"
type="text"
name="save-query-name"
id="save-query-name"
#queryNameField
[(ngModel)]="queryName"
required/>
</div>
</div>
</div>
<section class="form--section">
<h3 [textContent]="text.label_visibility_settings"></h3>
<query-sharing-form
[isSave]="true"
(onChange)="setValues($event)"
[isStarred]="isStarred"
[isPublic]="isPublic">
</query-sharing-form>
</section>
<div class="form--space">
<button class="button -highlight -with-icon icon-checkmark"
(click)="saveQueryAs($event)"
[textContent]="text.button_save"
[disabled]="isBusy || !queryName">
</button>
<button class="button"
[textContent]="text.button_cancel"
(click)="closeMe($event)">
</button>
</div>
</form>
</div>
</div>

@ -0,0 +1,107 @@
//-- 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 {WorkPackagesListService} from '../../wp-list/wp-list.service';
import {States} from '../../states.service';
import {WorkPackageNotificationService} from '../../wp-edit/wp-notification.service';
import {QueryResource} from 'core-app/modules/hal/resources/query-resource';
import {NotificationsService} from "core-components/common/notifications/notifications.service";
import {OpModalComponent} from "core-components/op-modals/op-modal.component";
import {Component, ElementRef, Inject, ViewChild} from "@angular/core";
import {I18nToken, OpModalLocalsToken} from "core-app/angular4-transition-utils";
import {OpModalLocalsMap} from "core-components/op-modals/op-modal.types";
import {QuerySharingChange} from "core-components/modals/share-modal/query-sharing-form.component";
@Component({
template: require('!!raw-loader!./save-query.modal.html')
})
export class SaveQueryModal extends OpModalComponent {
public queryName:string = '';
public isStarred = false;
public isPublic = false;
public isBusy = false;
@ViewChild('queryNameField') queryNameField:ElementRef;
public text:{ [key:string]:string } = {
title: this.I18n.t('js.modals.form_submit.title'),
text: this.I18n.t('js.modals.form_submit.text'),
save_as: this.I18n.t('js.label_save_as'),
label_name: this.I18n.t('js.modals.label_name'),
label_visibility_settings: this.I18n.t('js.label_visibility_settings'),
button_save: this.I18n.t('js.modals.button_save'),
button_cancel: this.I18n.t('js.button_cancel'),
close_popup: this.I18n.t('js.close_popup_title')
};
constructor(readonly elementRef:ElementRef,
@Inject(OpModalLocalsToken) public locals:OpModalLocalsMap,
@Inject(I18nToken) readonly I18n:op.I18n,
readonly states:States,
readonly wpListService:WorkPackagesListService,
readonly wpNotificationsService:WorkPackageNotificationService,
readonly notificationsService:NotificationsService) {
super(locals, elementRef);
}
public setValues(change:QuerySharingChange) {
this.isStarred = change.isStarred;
this.isPublic = change.isPublic;
}
public onOpen() {
this.queryNameField.nativeElement.focus();
}
public get afterFocusOn() {
return jQuery('#work-packages-settings-button');
}
public saveQueryAs($event:JQueryEventObject) {
if (this.isBusy || !this.queryName) {
return;
}
this.isBusy = true;
const query = this.states.query.resource.value!;
query.public = this.isPublic;
this.wpListService
.create(query, this.queryName)
.then(async (savedQuery:QueryResource) => {
if (this.isStarred && !savedQuery.starred) {
return this.wpListService.toggleStarred(savedQuery).then(() => this.closeMe($event));
}
this.closeMe($event);
return Promise.resolve(true);
})
.catch((error:any) => this.wpNotificationsService.handleErrorResponse(error))
.then(() => this.isBusy = false); // Same as .finally()
}
}

@ -0,0 +1,59 @@
import {wpControllersModule} from '../../../angular-modules';
import {States} from '../../states.service';
import {AuthorisationService} from 'core-components/common/model-auth/model-auth.service';
import {Component, Inject, Input, OnInit, Output} from "@angular/core";
import {I18nToken} from "core-app/angular4-transition-utils";
import {EventEmitter} from "@angular/core";
export interface QuerySharingChange {
isStarred:boolean;
isPublic:boolean;
}
@Component({
selector: 'query-sharing-form',
template: require('!!raw-loader!./query-sharing-form.html')
})
export class QuerySharingForm implements OnInit {
public canPublish:boolean = false;
@Input() public isSave:boolean;
@Input() public isStarred:boolean;
@Input() public isPublic:boolean;
@Output() public onChange = new EventEmitter<QuerySharingChange>();
public text = {
showInMenu: this.I18n.t('js.label_show_in_menu'),
visibleForOthers: this.I18n.t('js.label_visible_for_others')
};
constructor(readonly states:States,
readonly authorisationService:AuthorisationService,
@Inject(I18nToken) readonly I18n:op.I18n) {
}
ngOnInit() {
const form = this.states.query.form.value!;
this.canPublish = form.schema.public.writable;
}
public get canStar() {
return this.isSave ||
this.authorisationService.can('query', 'star') ||
this.authorisationService.can('query', 'unstar');
}
public updateStarred(val:boolean) {
this.isStarred = val;
this.changed();
}
public updatePublic(val:boolean) {
this.isPublic = val;
this.changed();
}
public changed() {
this.onChange.emit({ isStarred: !!this.isStarred, isPublic: !!this.isPublic });
}
}

@ -1,53 +0,0 @@
import {wpControllersModule} from '../../../angular-modules';
import {States} from '../../states.service';
import {AuthorisationService} from 'core-components/common/model-auth/model-auth.service';
export class QuerySharingForm {
public canPublish:boolean = false;
public isSave:boolean;
public isStarred:boolean;
public isPublic:boolean;
public onChange:(args:any) => void;
public text:any;
constructor(public $scope:ng.IScope,
public states:States,
public authorisationService:AuthorisationService,
public I18n:op.I18n) {
const query = this.states.query.resource.value!;
const form = states.query.form.value!;
this.canPublish = form.schema.public.writable;
this.text = {
showInMenu: I18n.t('js.label_show_in_menu'),
visibleForOthers: I18n.t('js.label_visible_for_others')
};
}
public $onInit() {
// Created for interface compliance
}
public get canStar() {
return this.isSave ||
this.authorisationService.can('query', 'star') ||
this.authorisationService.can('query', 'unstar');
}
public changed() {
this.onChange({ isStarred: !!this.isStarred, isPublic: !!this.isPublic });
}
}
wpControllersModule.component('querySharingForm', {
templateUrl: '/components/modals/share-modal/query-sharing-form.html',
controller: QuerySharingForm,
bindings: {
onChange: '&',
isStarred: '<',
isPublic: '<',
isSave: '<?'
}
});

@ -5,24 +5,24 @@
<input type="checkbox" <input type="checkbox"
name="is_public" name="is_public"
id="show-public" id="show-public"
ng-model="$ctrl.isPublic" [ngModel]="isPublic"
ng-change="$ctrl.changed()" (ngModelChange)="updatePublic($event)"
ng-disabled="!$ctrl.canPublish" [disabled]="!canPublish"
class="form--check-box" /> class="form--check-box" />
</div> </div>
{{ ::$ctrl.text.visibleForOthers }} {{ text.visibleForOthers }}
</label> </label>
<label class="form--label-with-check-box"> <label class="form--label-with-check-box">
<div class="form--check-box-container"> <div class="form--check-box-container">
<input type="checkbox" <input type="checkbox"
name="show_in_menu" name="show_in_menu"
id="show-in-menu" id="show-in-menu"
ng-model="$ctrl.isStarred" [ngModel]="isStarred"
ng-change="$ctrl.changed()" (ngModelChange)="updateStarred($event)"
ng-disabled="!$ctrl.canStar" [disabled]="!canStar"
class="form--check-box" /> class="form--check-box" />
</div> </div>
{{ ::$ctrl.text.showInMenu }} {{ text.showInMenu }}
</label> </label>
</div> </div>
</div> </div>

@ -0,0 +1,36 @@
<div class="op-modal--portal ">
<div class="op-modal--modal-container wp-table--configuration-modal loading-indicator--location"
data-indicator-name="modal"
tabindex="0">
<div class="op-modal--modal-header">
<a class="op-modal--modal-close-button">
<i
class="icon-close"
(click)="closeMe($event)"
[attr.title]="text.closePopup">
</i>
</a>
</div>
<h3 [textContent]="text.label_visibility_settings"></h3>
<query-sharing-form
[isSave]="false"
(onChange)="setValues($event)"
[isStarred]="isStarred"
[isPublic]="isPublic">
</query-sharing-form>
<div class="form--space">
<button class="button -highlight -with-icon icon-checkmark"
(click)="saveQuery($event)"
[textContent]="text.button_save">
</button>
<button class="button"
[textContent]="text.button_cancel"
[disabled]="isBusy"
(click)="closeMe($event)">
</button>
</div>
</div>
</div>

@ -0,0 +1,118 @@
//-- 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 {WorkPackagesListService} from '../../wp-list/wp-list.service';
import {States} from '../../states.service';
import {WorkPackageNotificationService} from '../../wp-edit/wp-notification.service';
import {QueryResource} from 'core-app/modules/hal/resources/query-resource';
import {NotificationsService} from "core-components/common/notifications/notifications.service";
import {OpModalComponent} from "core-components/op-modals/op-modal.component";
import {Component, ElementRef, Inject, OnInit, ViewChild} from "@angular/core";
import {I18nToken, OpModalLocalsToken} from "core-app/angular4-transition-utils";
import {OpModalLocalsMap} from "core-components/op-modals/op-modal.types";
import {QuerySharingChange} from "core-components/modals/share-modal/query-sharing-form.component";
@Component({
template: require('!!raw-loader!./query-sharing.modal.html')
})
export class QuerySharingModal extends OpModalComponent implements OnInit {
public query:QueryResource;
public isStarred = false;
public isPublic = false;
public isBusy = false;
public text:{ [key:string]:string } = {
title: this.I18n.t('js.modals.form_submit.title'),
text: this.I18n.t('js.modals.form_submit.text'),
save_as: this.I18n.t('js.label_save_as'),
label_name: this.I18n.t('js.modals.label_name'),
label_visibility_settings: this.I18n.t('js.label_visibility_settings'),
button_save: this.I18n.t('js.modals.button_save'),
button_cancel: this.I18n.t('js.button_cancel'),
close_popup: this.I18n.t('js.close_popup_title')
};
constructor(readonly elementRef:ElementRef,
@Inject(OpModalLocalsToken) public locals:OpModalLocalsMap,
@Inject(I18nToken) readonly I18n:op.I18n,
readonly states:States,
readonly wpListService:WorkPackagesListService,
readonly wpNotificationsService:WorkPackageNotificationService,
readonly notificationsService:NotificationsService) {
super(locals, elementRef);
}
ngOnInit() {
super.ngOnInit();
this.query = this.states.query.resource.value!;
this.isStarred = this.query.starred;
this.isPublic = this.query.public;
}
public setValues(change:QuerySharingChange) {
this.isStarred = change.isStarred;
this.isPublic = change.isPublic;
}
public get afterFocusOn() {
return jQuery('#work-packages-settings-button');
}
public saveQuery($event:JQueryEventObject) {
if (this.isBusy) {
return;
}
this.isBusy = true;
let promises = [];
if (this.query.public !== this.isPublic) {
this.query.public = this.isPublic;
promises.push(this.wpListService.save(this.query));
}
if (this.query.starred !== this.isStarred) {
promises.push(this.wpListService.toggleStarred(this.query));
}
Promise
.all(promises)
.then(() => {
this.closeMe($event);
this.isBusy = false;
})
.catch(() => {
this.notificationsService.addError(this.I18n.t('js.errors.query_saving'));
this.isBusy = false;
});
}
}

@ -1,96 +0,0 @@
//-- 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 {wpControllersModule} from '../../../angular-modules';
import {States} from '../../states.service';
import {WorkPackagesListService} from '../../wp-list/wp-list.service';
import {QueryResource} from 'core-app/modules/hal/resources/query-resource';
export class ShareModalController {
public query:QueryResource;
public name:string = 'Share';
public isBusy:boolean = false;
public isStarred:boolean;
public isPublic:boolean;
constructor(private shareModal:any,
private states:States,
private NotificationsService:any,
private wpListService:WorkPackagesListService,
private $q:ng.IQService) {
this.name = 'Share';
this.query = this.states.query.resource.value!;
this.isStarred = this.query.starred;
this.isPublic = this.query.public;
}
public $onInit() {
// Created for interface compliance
}
public setValues(isStarred:boolean, isPublic:boolean) {
this.isStarred = isStarred;
this.isPublic = isPublic;
}
public closeModal() {
this.shareModal.deactivate();
}
public closeAndReport(message:any) {
this.shareModal.deactivate();
this.NotificationsService.addSuccess(message.text);
}
public saveQuery() {
if (this.isBusy) {
return console.warn('Skipping additional save');
}
this.isBusy = true;
let promises = [];
if (this.query.public !== this.isPublic) {
this.query.public = this.isPublic;
promises.push(this.wpListService.save(this.query));
}
if (this.query.starred !== this.isStarred) {
promises.push(this.wpListService.toggleStarred(this.query));
}
this.$q.all(promises).then(() => {
this.shareModal.deactivate();
}).finally(() => this.isBusy = false);
}
}
wpControllersModule.controller('ShareModalController', ShareModalController);

@ -1,30 +0,0 @@
<div class="op-modal--portal">
<div class="op-modal--modal-container">
<div class="op-modal--modal-header">
<a>
<i
class="icon-close"
ng-click="$ctrl.closeModal()"
title="{{ ::I18n.t('js.close_popup_title') }}">
</i>
</a>
</div>
<h3>{{ ::I18n.t('js.label_visibility_settings') }}</h3>
<query-sharing-form
on-change="$ctrl.setValues(isStarred, isPublic)"
is-starred="$ctrl.isStarred"
is-public="$ctrl.isPublic">
</query-sharing-form>
<button class="button -highlight -with-icon icon-checkmark"
ng-disabled="$ctrl.isBusy"
ng-click="$ctrl.saveQuery()">
{{ ::I18n.t('js.modals.button_save') }}
</button>
<button class="button" ng-click="$ctrl.closeModal()">
{{ ::I18n.t('js.modals.button_cancel') }}
</button>
</div>
</div>

@ -1,40 +0,0 @@
//-- 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 {wpControllersModule} from '../../../angular-modules';
function shareModalService(btfModal:any) {
return btfModal({
controller: 'ShareModalController',
controllerAs: '$ctrl',
afterFocusOn: '#work-packages-settings-button',
templateUrl: '/components/modals/share-modal/share-modal.service.html'
});
}
wpControllersModule.factory('shareModal', shareModalService);

@ -27,13 +27,7 @@
//++ //++
import {Directive, ElementRef, Inject, Input, OnDestroy} from '@angular/core'; import {Directive, ElementRef, Inject, Input, OnDestroy} from '@angular/core';
import { import {I18nToken, settingsModalToken,} from 'core-app/angular4-transition-utils';
exportModalToken,
I18nToken,
saveModalToken,
settingsModalToken,
shareModalToken
} from 'core-app/angular4-transition-utils';
import {AuthorisationService} from 'core-components/common/model-auth/model-auth.service'; import {AuthorisationService} from 'core-components/common/model-auth/model-auth.service';
import {OpContextMenuTrigger} from 'core-components/op-context-menu/handlers/op-context-menu-trigger.directive'; import {OpContextMenuTrigger} from 'core-components/op-context-menu/handlers/op-context-menu-trigger.directive';
import {OPContextMenuService} from 'core-components/op-context-menu/op-context-menu.service'; import {OPContextMenuService} from 'core-components/op-context-menu/op-context-menu.service';
@ -45,6 +39,8 @@ import {QueryFormResource} from 'core-app/modules/hal/resources/query-form-resou
import {QueryResource} from 'core-app/modules/hal/resources/query-resource'; import {QueryResource} from 'core-app/modules/hal/resources/query-resource';
import {OpModalService} from "core-components/op-modals/op-modal.service"; import {OpModalService} from "core-components/op-modals/op-modal.service";
import {WpTableExportModal} from "core-components/modals/export-modal/wp-table-export.modal"; import {WpTableExportModal} from "core-components/modals/export-modal/wp-table-export.modal";
import {SaveQueryModal} from "core-components/modals/save-modal/save-query.modal";
import {QuerySharingModal} from "core-components/modals/share-modal/query-sharing.modal";
@Directive({ @Directive({
selector: '[opSettingsContextMenu]' selector: '[opSettingsContextMenu]'
@ -60,8 +56,6 @@ export class OpSettingsMenuDirective extends OpContextMenuTrigger implements OnD
readonly wpListService:WorkPackagesListService, readonly wpListService:WorkPackagesListService,
readonly authorisationService:AuthorisationService, readonly authorisationService:AuthorisationService,
readonly states:States, readonly states:States,
@Inject(shareModalToken) readonly shareModal:any,
@Inject(saveModalToken) readonly saveModal:any,
@Inject(settingsModalToken) readonly settingsModal:any, @Inject(settingsModalToken) readonly settingsModal:any,
@Inject(I18nToken) readonly I18n:op.I18n) { @Inject(I18nToken) readonly I18n:op.I18n) {
@ -157,7 +151,7 @@ export class OpSettingsMenuDirective extends OpContextMenuTrigger implements OnD
onClick: ($event:JQueryEventObject) => { onClick: ($event:JQueryEventObject) => {
const query = this.query; const query = this.query;
if (!query.id && this.allowQueryAction($event, 'updateImmediately')) { if (!query.id && this.allowQueryAction($event, 'updateImmediately')) {
this.saveModal.activate(); this.opModalService.show(SaveQueryModal);
} else if (query.id && this.allowQueryAction($event, 'updateImmediately')) { } else if (query.id && this.allowQueryAction($event, 'updateImmediately')) {
this.wpListService.save(query); this.wpListService.save(query);
} }
@ -172,7 +166,7 @@ export class OpSettingsMenuDirective extends OpContextMenuTrigger implements OnD
icon: 'icon-save', icon: 'icon-save',
onClick: ($event:JQueryEventObject) => { onClick: ($event:JQueryEventObject) => {
if (this.allowFormAction($event, 'commit')) { if (this.allowFormAction($event, 'commit')) {
this.saveModal.activate(); this.opModalService.show(SaveQueryModal);
} }
return true; return true;
@ -212,7 +206,7 @@ export class OpSettingsMenuDirective extends OpContextMenuTrigger implements OnD
icon: 'icon-publish', icon: 'icon-publish',
onClick: ($event:JQueryEventObject) => { onClick: ($event:JQueryEventObject) => {
if (this.allowQueryAction($event, 'unstar') || this.allowQueryAction($event, 'star')) { if (this.allowQueryAction($event, 'unstar') || this.allowQueryAction($event, 'star')) {
this.shareModal.activate(); this.opModalService.show(QuerySharingModal);
} }
return true; return true;

Loading…
Cancel
Save