Extend attachment-formattable to other work package fields

pull/5771/head
Oliver Günther 7 years ago
parent 668306b12f
commit fffcab7f2b
No known key found for this signature in database
GPG Key ID: 88872239EB414F99
  1. 3
      app/assets/stylesheets/content/work_packages/single_view/_single_view.sass
  2. 1
      frontend/app/components/api/api-v3/hal-resources/work-package-resource.service.ts
  3. 4
      frontend/app/components/work-packages/work-package-cache.service.ts
  4. 34
      frontend/app/components/work-packages/wp-attachments-formattable-field/models/field-model.ts
  5. 48
      frontend/app/components/work-packages/wp-attachments-formattable-field/models/work-package-field-model.ts
  6. 39
      frontend/app/components/work-packages/wp-attachments-formattable-field/wp-attachments-formattable.directive.ts
  7. 12
      frontend/app/components/work-packages/wp-single-view/wp-single-view.directive.html
  8. 2
      frontend/app/components/work-packages/wp-single-view/wp-single-view.directive.ts
  9. 2
      frontend/app/components/wp-display/field-types/wp-display-formattable-field.module.ts
  10. 2
      frontend/app/components/wp-display/wp-display-field/wp-display-field.module.ts
  11. 2
      frontend/app/components/wp-edit/field-types/wp-edit-wiki-textarea-field.directive.html
  12. 4
      frontend/app/components/wp-edit/field-types/wp-edit-wiki-textarea-field.module.ts
  13. 19
      frontend/app/components/wp-edit/wp-edit-field/wp-edit-field-group.directive.ts
  14. 7
      frontend/app/components/wp-edit/wp-edit-field/wp-edit-field.directive.ts
  15. 3
      frontend/app/ui_components/upload-progress-directive.js

@ -63,6 +63,8 @@
.work-package--single-view
// Make elements in split and full view span the entire width
// Style the edit field element when the full width is required
.wp-edit-formattable-field,
.wp-edit-field
width: 100%
@ -160,7 +162,6 @@ i
padding: 0
margin: 0
// Implement two column layout for WP full screen view
@media screen and (min-width: 90rem)
.action-show .attributes-group,

@ -435,6 +435,7 @@ export class WorkPackageResource extends HalResource {
delete this.$pristine[key];
});
wpCacheService.updateWorkPackage(this as any);
deferred.resolve(this);
});
})

@ -67,7 +67,7 @@ export class WorkPackageCacheService extends StateCacheService<WorkPackageResour
updateWorkPackageList(list:WorkPackageResourceInterface[]) {
for (var wp of list) {
const workPackageId = getWorkPackageId(wp.id);
const wpState = this.states.workPackages.get(workPackageId);
const wpState = this.multiState.get(workPackageId);
const lastValue = wpState.value;
const wpForPublish = lastValue && lastValue.dirty
? lastValue // dirty, use current wp
@ -146,7 +146,7 @@ export class WorkPackageCacheService extends StateCacheService<WorkPackageResour
this.apiWorkPackages.loadWorkPackageById(id, true)
.then((workPackage:WorkPackageResourceInterface) => {
this.schemaCacheService.ensureLoaded(workPackage).then(() => {
this.updateValue(id, workPackage);
this.multiState.get(id).putValue(workPackage);
resolve(workPackage);
}, reject);
}, reject);

@ -1,34 +0,0 @@
import {InsertMode} from '../wp-attachments-formattable.enums';
import {IApplyAttachmentMarkup} from '../wp-attachments-formattable.interfaces';
import {WorkPackageResourceInterface} from '../../../api/api-v3/hal-resources/work-package-resource.service';
import {MarkupModel} from './markup-model';
import IAugmentedJQuery = angular.IAugmentedJQuery;
export class FieldModel implements IApplyAttachmentMarkup {
public contentToInsert:string;
constructor(protected workPackage:WorkPackageResourceInterface, protected markupModel:MarkupModel) {
this.contentToInsert = workPackage.description.raw || '';
}
private addInitialLineBreak():string {
return (this.contentToInsert.length > 0) ? '\r\n' : '';
}
public insertAttachmentLink(url:string, insertMode:InsertMode, addLineBreak?:boolean):void {
this.contentToInsert += this.addInitialLineBreak() + this.markupModel.createMarkup(url,
insertMode,
false);
}
public insertWebLink(url:string, insertMode:InsertMode):void {
this.contentToInsert += this.addInitialLineBreak() + this.markupModel.createMarkup(url,
insertMode,
false);
}
public save():void {
this.workPackage.description.raw = this.contentToInsert;
this.workPackage.save();
}
}

@ -0,0 +1,48 @@
import {InsertMode} from '../wp-attachments-formattable.enums';
import {IApplyAttachmentMarkup} from '../wp-attachments-formattable.interfaces';
import {WorkPackageResourceInterface} from '../../../api/api-v3/hal-resources/work-package-resource.service';
import {MarkupModel} from './markup-model';
import {WorkPackageCacheService} from '../../work-package-cache.service';
import {$injectFields} from '../../../angular/angular-injector-bridge.functions';
export class WorkPackageFieldModel implements IApplyAttachmentMarkup {
public wpCacheService:WorkPackageCacheService;
public contentToInsert:string;
constructor(protected workPackage:WorkPackageResourceInterface, protected attribute:string, protected markupModel:MarkupModel) {
$injectFields(this, 'wpCacheService');
const formattable = workPackage[attribute];
this.contentToInsert = _.get(formattable, 'raw') as string || '';
}
private addInitialLineBreak():string {
return (this.contentToInsert.length > 0) ? '\r\n' : '';
}
public insertAttachmentLink(url:string, insertMode:InsertMode, addLineBreak?:boolean):void {
this.contentToInsert += this.addInitialLineBreak() + this.markupModel.createMarkup(url,
insertMode,
false);
}
public insertWebLink(url:string, insertMode:InsertMode):void {
this.contentToInsert += this.addInitialLineBreak() + this.markupModel.createMarkup(url,
insertMode,
false);
}
public save():void {
let value = this.workPackage[this.attribute] || { raw: '', html: '' };
value.raw = this.contentToInsert;
this.workPackage[this.attribute] = value;
this.workPackage
.save()
.then((wp) => {
// Refresh the work package some time later as there is no way to tell
// whether the attachment was uploaded successfully AND the field was updated.
setTimeout(() => this.wpCacheService.require(wp.id, true), 150);
});
}
}

@ -1,16 +1,15 @@
import {InsertMode, ViewMode} from './wp-attachments-formattable.enums';
import {WorkPackageResourceInterface} from '../../api/api-v3/hal-resources/work-package-resource.service';
import {WorkPackageSingleViewController} from '../wp-single-view/wp-single-view.directive';
import {KeepTabService} from '../../wp-panels/keep-tab/keep-tab.service';
import {openprojectModule} from '../../../angular-modules';
import {WorkPackageCacheService} from '../work-package-cache.service';
import {MarkupModel} from './models/markup-model';
import {EditorModel} from './models/editor-model';
import {PasteModel} from './models/paste-model';
import {FieldModel} from './models/field-model';
import {WorkPackageFieldModel} from './models/work-package-field-model';
import {DropModel} from './models/drop-model';
import {SingleAttachmentModel} from './models/single-attachment';
import {WorkPackageEditingService} from '../../wp-edit-form/work-package-editing-service';
import {WorkPackageSingleViewController} from '../wp-single-view/wp-single-view.directive';
export class WpAttachmentsFormattableController {
constructor(protected $scope:ng.IScope,
@ -18,7 +17,6 @@ export class WpAttachmentsFormattableController {
protected $rootScope:ng.IRootScopeService,
protected $location:ng.ILocationService,
protected wpCacheService:WorkPackageCacheService,
protected wpEditing:WorkPackageEditingService,
protected $timeout:ng.ITimeoutService,
protected $q:ng.IQService,
protected $state:ng.ui.IStateService,
@ -43,7 +41,7 @@ export class WpAttachmentsFormattableController {
const [, editor] = this.getEditor();
const originalEvent = (evt.originalEvent as DragEvent);
const workPackage:WorkPackageResourceInterface = (this.$scope as any).workPackage;
const workPackage:WorkPackageResourceInterface = this.$scope.workPackage;
const dropData:DropModel = new DropModel(this.$location,
originalEvent.dataTransfer,
workPackage);
@ -87,7 +85,7 @@ export class WpAttachmentsFormattableController {
* Get the editor model for the current view mode.
* This is either the editing model (open textarea field), or the closed field model.
*/
protected getEditor():[ViewMode, EditorModel | FieldModel] {
protected getEditor():[ViewMode, EditorModel | WorkPackageFieldModel] {
const textarea:ng.IAugmentedJQuery = this.$element.find('textarea');
let viewMode;
@ -98,20 +96,19 @@ export class WpAttachmentsFormattableController {
model = new EditorModel(textarea, new MarkupModel());
} else {
viewMode = ViewMode.SHOW;
model = new FieldModel(this.$scope.workPackage, new MarkupModel());
model = new WorkPackageFieldModel(this.$scope.workPackage, this.$scope.attribute, new MarkupModel());
}
return [viewMode, model];
}
protected uploadAndInsert(files:File[], model:EditorModel | FieldModel) {
const workPackage:WorkPackageResourceInterface = this.$scope.workPackage;
if (workPackage.isNew) {
return this.insertDelayedAttachments(files, model, workPackage);
protected uploadAndInsert(files:File[], model:EditorModel | WorkPackageFieldModel) {
const wp = this.$scope.workPackage as WorkPackageResourceInterface;
if (wp.isNew) {
return this.insertDelayedAttachments(files, model, wp);
}
workPackage
wp
.uploadAttachments(files)
.then(attachments => attachments.elements)
.then((updatedAttachments:any) => {
@ -206,28 +203,18 @@ export class WpAttachmentsFormattableController {
};
}
interface IAttachmentScope extends ng.IScope {
workPackage:WorkPackageResourceInterface;
}
function wpAttachmentsFormattable() {
return {
bindToController: true,
controller: WpAttachmentsFormattableController,
link: (scope:IAttachmentScope,
link: (scope:ng.IScope,
element:ng.IAugmentedJQuery,
attrs:ng.IAttributes,
controllers:[WorkPackageSingleViewController]) => {
// right now the attachments directive will only work in combination with either
// the wpSingleView or the wpEditForm directive
// else the drop handler will fail because of a missing reference to the current wp
if (angular.isUndefined(controllers[0])) {
return;
}
scope.workPackage = controllers[0].workPackage;
scope.attribute = scope.$eval(attrs.fieldName);
},
require: ['?^wpSingleView', '?^wpEditForm'],
require: ['^wpSingleView'],
restrict: 'A'
};
}

@ -73,7 +73,17 @@
</div>
<div ng-if="!descriptor.multiple"
class="attributes-key-value--value-container">
<wp-edit-field work-package-id="$ctrl.workPackage.id" field-name="descriptor.name"></wp-edit-field>
<wp-edit-field ng-if="descriptor.field.isFormattable"
class="wp-edit-formattable-field"
work-package-id="$ctrl.workPackage.id"
field-name="descriptor.name"
wp-attachments-formattable>
</wp-edit-field>
<wp-edit-field ng-if="!descriptor.field.isFormattable"
work-package-id="$ctrl.workPackage.id"
field-name="descriptor.name">
</wp-edit-field>
</div>
<div
class="attributes-key-value--key"

@ -173,7 +173,7 @@ export class WorkPackageSingleViewController {
name: fieldName,
label: field.label,
multiple: false,
spanAll: field.isLargeField,
spanAll: field.isFormattable,
field: field
});
});

@ -52,7 +52,7 @@ export class FormattableDisplayField extends DisplayField {
element.appendChild(span);
}
public get isLargeField():boolean {
public get isFormattable():boolean {
return true;
}

@ -35,7 +35,7 @@ export class DisplayField extends Field {
public I18n: op.I18n;
public mode:string|null = null;
public get isLargeField():boolean {
public get isFormattable():boolean {
return false;
}

@ -15,7 +15,7 @@
<div class="inplace-edit--preview" ng-show="vm.field.isPreview && !vm.field.isBusy">
<span bind-unescaped-html="vm.field.previewHtml"></span>
</div>
<div ng-if="vm.field.supportsAttachments && !vm.field.isPreview"
<div ng-if="vm.field.isFormattable && !vm.field.isPreview"
class="wp-edit-field-attachment-label">
<span ng-bind="vm.field.text.attachmentLabel"></span>
</div>

@ -65,8 +65,8 @@ export class WikiTextareaEditField extends EditField {
};
}
public get supportsAttachments() {
return this.name === 'description';
public get isFormattable() {
return true;
}
public isEmpty(): boolean {

@ -33,6 +33,8 @@ import {WorkPackageEditingService} from '../../wp-edit-form/work-package-editing
import {WorkPackageEditForm} from '../../wp-edit-form/work-package-edit-form';
import {SingleViewEditContext} from '../../wp-edit-form/single-view-edit-context';
import {input} from 'reactivestates';
import {scopeDestroyed$} from '../../../helpers/angular-rx-utils';
import {WorkPackageResourceInterface} from '../../api/api-v3/hal-resources/work-package-resource.service';
export class WorkPackageEditFieldGroupController {
public workPackageId:string;
@ -65,6 +67,13 @@ export class WorkPackageEditFieldGroupController {
}
public $onInit() {
this.states.workPackages.get(this.workPackageId)
.values$()
.takeUntil(scopeDestroyed$(this.$scope))
.subscribe((wp) => {
_.each(this.fields, (ctrl) => this.update(ctrl, wp));
});
if (this.inEditMode) {
this.start();
}
@ -82,6 +91,11 @@ export class WorkPackageEditFieldGroupController {
if (form && form.editMode) {
field.activateOnForm(form, true);
} else {
this.states.workPackages
.get(this.workPackageId)
.valuesPromise()
.then(wp => this.update(field, wp!));
}
}
@ -103,6 +117,11 @@ export class WorkPackageEditFieldGroupController {
this.wpEditing.stopEditing(this.workPackageId);
}
private update(field:WorkPackageEditFieldController, wp:WorkPackageResourceInterface) {
field.workPackage = wp;
field.render();
}
private get editContext() {
return new SingleViewEditContext(this);
}

@ -70,13 +70,6 @@ export class WorkPackageEditFieldController {
public $onInit() {
this.wpEditFieldGroup.register(this);
this.states.workPackages.get(this.workPackageId)
.values$()
.takeUntil(scopeDestroyed$(this.$scope))
.subscribe((wp) => {
this.workPackage = wp;
this.render();
});
}
public render() {

@ -31,7 +31,8 @@ module.exports = function() {
var uploadProgressController = function(scope) {
scope.upload.progress(function(details) {
scope.file = details.config.file.name;
const file = details.config.file || details.config.data.file;
scope.file = _.get(file, 'name', '');
if (details.lengthComputable) {
scope.value = Math.round(details.loaded / details.total * 100);
} else {

Loading…
Cancel
Save