Merge pull request #5063 from opf/housekeeping/wp-schemas

Load schemas in separate resource from State
pull/5070/merge
ulferts 8 years ago committed by GitHub
commit bfd4c707fb
  1. 1
      frontend/app/components/api/api-v3/hal-resource-types/hal-resource-types.config.ts
  2. 21
      frontend/app/components/api/api-v3/hal-resources/hal-resource.service.ts
  3. 55
      frontend/app/components/api/api-v3/hal-resources/schema-resource.service.ts
  4. 23
      frontend/app/components/api/api-v3/hal-resources/work-package-resource.service.test.ts
  5. 107
      frontend/app/components/api/api-v3/hal-resources/work-package-resource.service.ts
  6. 2
      frontend/app/components/api/api-work-packages/api-work-packages.service.ts
  7. 10
      frontend/app/components/routing/wp-list/wp-list.controller.test.ts
  8. 3
      frontend/app/components/routing/wp-view-base/wp-view-base.controller.ts
  9. 2
      frontend/app/components/states.service.ts
  10. 57
      frontend/app/components/work-packages/work-package-cache.service.test.ts
  11. 34
      frontend/app/components/work-packages/work-package-cache.service.ts
  12. 3
      frontend/app/components/work-packages/wp-display-attr/wp-display-attr.directive.test.ts
  13. 18
      frontend/app/components/work-packages/wp-display-attr/wp-display-attr.directive.ts
  14. 33
      frontend/app/components/work-packages/wp-single-view/wp-single-view.directive.ts
  15. 3
      frontend/app/components/wp-edit/wp-edit-field/wp-edit-field.directive.html
  16. 57
      frontend/app/components/wp-edit/wp-edit-field/wp-edit-field.directive.ts
  17. 10
      frontend/app/components/wp-edit/wp-edit-form.directive.ts
  18. 1
      frontend/app/typings/open-project.typings.d.ts

@ -55,6 +55,7 @@ function halResourceTypesConfig(halResourceTypes:HalResourceTypesService) {
to: 'WorkPackage'
}
},
Schema: 'SchemaResource',
Error: 'ErrorResource',
User: 'UserResource',
Collection: 'CollectionResource'

@ -29,6 +29,7 @@
import {opApiModule} from '../../../../angular-modules';
import {HalLinkInterface} from '../hal-link/hal-link.service';
import {HalResourceFactoryService} from '../hal-resource-factory/hal-resource-factory.service';
import {State} from './../../../../helpers/reactive-fassade';
const ObservableArray:any = require('observable-array');
@ -100,7 +101,27 @@ export class HalResource {
this.$initialize($source);
}
/**
* Return the associated state to this HAL resource, if any.
*/
public get state():State<HalResource>|null {
return null;
}
public $load(force = false):ng.IPromise<HalResource> {
const state = this.state;
if (!this.state) {
return this.$loadResource(force);
}
if (force) {
state.clear();
}
return <ng.IPromise<HalResource>> state.get();
}
protected $loadResource(force = false):ng.IPromise<HalResource> {
if (!force) {
if (this.$loaded) {
return $q.when(this);

@ -0,0 +1,55 @@
//-- 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 {HalResource} from './hal-resource.service';
import {opApiModule} from '../../../../angular-modules';
import {WorkPackageResource} from './work-package-resource.service';
import {States} from '../../../states.service';
import {State} from './../../../../helpers/reactive-fassade';
var states: States;
export class SchemaResource extends HalResource {
public get state() {
return states.schemas.get(this.href);
}
}
function schemaResource(...args) {
[
states,
] = args;
return SchemaResource;
}
schemaResource.$inject = [
'states',
];
opApiModule.factory('SchemaResource', schemaResource);

@ -172,8 +172,9 @@ describe('WorkPackageResource service', () => {
beforeEach(() => {
source = {
_links: {
attachments: {href: 'attachmentsHref'},
activities: {href: 'activitiesHref'}
schema: { _type: 'Schema', href: 'schema' },
attachments: { href: 'attachmentsHref' },
activities: { href: 'activitiesHref' }
}
};
createWorkPackage();
@ -257,14 +258,11 @@ describe('WorkPackageResource service', () => {
beforeEach(() => {
source = {
_links: {
attachments: {
href: 'attachments'
},
activities: {
href: 'activities'
}
schema: { _type: 'Schema', href: 'schema' },
attachments: { href: 'attachments' },
activities: { href: 'activities' }
},
isNew: false
isNew: true
};
createWorkPackage();
});
@ -319,7 +317,12 @@ describe('WorkPackageResource service', () => {
uploadFilesDeferred.resolve();
removeStub = sinon.stub(NotificationsService, 'remove');
expectUncachedRequests('activities', 'attachments');
expectUncachedRequest('activities');
expectUncachedRequest('attachments');
$httpBackend
.when('GET', 'schema')
.respond(200, {_links: {self: 'schema'}});
$httpBackend.flush();
$rootScope.$apply();
});

@ -36,6 +36,9 @@ import {UploadFile} from '../../op-file-upload/op-file-upload.service';
import IQService = angular.IQService;
import IPromise = angular.IPromise;
import ITimeoutService = angular.ITimeoutService;
import {States} from '../../../states.service';
import {State} from './../../../../helpers/reactive-fassade';
import {SchemaResource} from './schema-resource.service';
interface WorkPackageResourceEmbedded {
activities: CollectionResourceInterface;
@ -50,7 +53,7 @@ interface WorkPackageResourceEmbedded {
project: HalResource|any;
relations: CollectionResourceInterface;
responsible: HalResource|any;
schema: HalResource|any;
schema: SchemaResource;
status: HalResource|any;
timeEntries: HalResource[]|any[];
type: HalResource|any;
@ -80,6 +83,7 @@ var $q: IQService;
var $stateParams: any;
var $timeout: ITimeoutService;
var I18n: op.I18n;
var states: States;
var apiWorkPackages: ApiWorkPackagesService;
var wpCacheService: WorkPackageCacheService;
var NotificationsService: any;
@ -113,7 +117,7 @@ export class WorkPackageResource extends HalResource {
public $embedded: WorkPackageResourceEmbedded;
public $links: WorkPackageResourceLinks;
public id: number|string;
public schema;
public schema: SchemaResource;
public $pristine: { [attribute: string]: any } = {};
public parentId: number;
public subject: string;
@ -146,6 +150,9 @@ export class WorkPackageResource extends HalResource {
return this.modifiedFields.length > 0;
}
/**
* Returns all modified fields by comparing open $pristine fields.
*/
public get modifiedFields(): string[] {
var modified = [];
@ -190,12 +197,8 @@ export class WorkPackageResource extends HalResource {
* be done automatically, but the backend does not provide typed collections yet.
*/
protected $initialize(source) {
const oldSchema = this.schema;
super.$initialize(source);
// Take over previously loaded schema resource
this.setExistingSchema(oldSchema);
var attachments = this.attachments || {$source: void 0, $loaded: void 0};
this.attachments = new AttachmentCollectionResource(
attachments.$source,
@ -259,18 +262,6 @@ export class WorkPackageResource extends HalResource {
});
}
public requiredValueFor(fieldName): boolean {
var fieldSchema = this.schema[fieldName];
// The field schema may be undefined if a custom field
// is used as a column, but not available for this type.
if (angular.isUndefined(fieldSchema)) {
return false;
}
return !this[fieldName] && fieldSchema.writable && fieldSchema.required;
}
public allowedValuesFor(field): ng.IPromise<HalResource[]> {
var deferred = $q.defer();
@ -337,11 +328,11 @@ export class WorkPackageResource extends HalResource {
return deferred.promise;
}
public getSchema() {
public loadFormSchema() {
return this.getForm().then(form => {
const schema = form.$embedded.schema;
this.schema = form.$embedded.schema;
angular.forEach(schema, (field, name) => {
angular.forEach(this.schema, (field, name) => {
// Assign only links from schema when an href is set
// and field is writable.
// (exclude plain properties and null values)
@ -352,11 +343,11 @@ export class WorkPackageResource extends HalResource {
const hasAllowedValues = Array.isArray(field.allowedValues) && field.allowedValues.length > 0;
if (isHalField && hasAllowedValues) {
this[name] = _.find(field.allowedValues, {href: this[name].href});
this[name] = _.find(field.allowedValues, {href: this[name].href}) || this[name];
}
});
return schema;
return this.schema;
});
}
@ -369,27 +360,31 @@ export class WorkPackageResource extends HalResource {
const payload = this.mergeWithForm(form);
const sentValues = Object.keys(this.$pristine);
this.saveResource(payload)
.then(workPackage => {
// Initialize any potentially new HAL values
this.$initialize(workPackage);
this.updateActivities();
this.$links.updateImmediately(payload)
.then((workPackage:WorkPackageResource) => {
// Remove the current form, otherwise old form data
// might still be used for the next edit field to be edited
this.form = null;
if (wasNew) {
this.uploadPendingAttachments();
wpCacheService.newWorkPackageCreated(this);
}
// Ensure the schema is loaded before updating
workPackage.schema.$load().then((schema) => {
// Initialize any potentially new HAL values
this.$initialize(workPackage);
this.schema = schema;
this.updateActivities();
// Remove only those pristine values that were submitted
angular.forEach(sentValues, (key) => {
delete this.$pristine[key];
});
if (wasNew) {
this.uploadPendingAttachments();
wpCacheService.newWorkPackageCreated(this);
}
// Remove the current form, otherwise old form data
// might still be used for the next edit field in #getSchema()
this.form = null;
// Remove only those pristine values that were submitted
angular.forEach(sentValues, (key) => {
delete this.$pristine[key];
});
deferred.resolve(this);
deferred.resolve(this);
});
})
.catch(error => {
deferred.reject(error);
@ -425,13 +420,6 @@ export class WorkPackageResource extends HalResource {
return otherWorkPackage.parent.$links.self.$link.href === this.$links.self.$link.href;
}
protected saveResource(payload): ng.IPromise<any> {
if (this.isNew) {
return apiWorkPackages.createWorkPackage(payload);
}
return this.$links.updateImmediately(payload);
}
private mergeWithForm(form) {
var plainPayload = form.payload.$plain();
var schema = form.$embedded.schema;
@ -464,25 +452,6 @@ export class WorkPackageResource extends HalResource {
});
}
private setExistingSchema(previous) {
// Only when existing schema was loaded
if (!(previous && previous.$loaded)) {
return;
}
// If old schema was a regular schema and both href match
// assume they are matching
if (previous.href === this.schema.href) {
this.schema = previous;
}
// If old schema was embedded into the WP form, decide
// based on its baseSchema href.
if (previous.baseSchema && previous.baseSchema.href === this.schema.href) {
this.schema = previous;
}
}
/**
* Invalidate a set of linked resources of this work package.
* And inform the cache service about the work package update.
@ -543,6 +512,10 @@ export class WorkPackageResource extends HalResource {
// Set update link to form
this['update'] = this.$links.update = form.$links.self;
// Use POST /work_packages for saving link
this['updateImmediately'] = this.$links.updateImmediately = (payload) => {
return apiWorkPackages.createWorkPackage(payload);
};
this.parentId = this.parentId || $stateParams.parent_id;
}
@ -557,6 +530,7 @@ function wpResource(...args) {
$stateParams,
$timeout,
I18n,
states,
apiWorkPackages,
wpCacheService,
NotificationsService,
@ -570,6 +544,7 @@ wpResource.$inject = [
'$stateParams',
'$timeout',
'I18n',
'states',
'apiWorkPackages',
'wpCacheService',
'NotificationsService',

@ -56,7 +56,7 @@ export class ApiWorkPackagesService {
public loadWorkPackageById(id:number, force = false) {
const url = this.v3Path.wp({wp: id});
return <IPromise<WorkPackageResource>> this.halRequest.get(url, null, {
return this.halRequest.get(url, null, {
caching: {
enabled: !force
}

@ -175,6 +175,12 @@ describe('WorkPackagesListController', () => {
}
};
var workPackage = {
schema: {
'$load': () => { return $q.when(true) }
}
}
wpListServiceMock = {
fromQueryParams() {
return $q.when({
@ -186,9 +192,7 @@ describe('WorkPackagesListController', () => {
resource: {
total: 10
},
work_packages: [
{}
]
work_packages: [ workPackage ]
});
}
};

@ -100,9 +100,6 @@ export class WorkPackageViewController {
* Initialize controller after workPackage resource has been loaded.
*/
protected init() {
// Ensure the schema is being loaded as soon as possible
this.workPackage.schema.$load();
// Set elements
this.workPackage.project.$load().then(() => {
this.projectIdentifier = this.workPackage.project.identifier;

@ -1,10 +1,12 @@
import {MultiState, initStates} from "../helpers/reactive-fassade";
import {WorkPackageResource} from "./api/api-v3/hal-resources/work-package-resource.service";
import {opServicesModule} from "../angular-modules";
import {SchemaResource} from './api/api-v3/hal-resources/schema-resource.service';
export class States {
workPackages = new MultiState<WorkPackageResource>();
schemas = new MultiState<SchemaResource>();
constructor() {
initStates(this, function (msg: any) {

@ -31,32 +31,46 @@ import {WorkPackageResource} from "../api/api-v3/hal-resources/work-package-reso
describe('WorkPackageCacheService', () => {
let wpCacheService: WorkPackageCacheService;
let $q: ng.IQService;
let $rootScope: ng.IRootScopeService;
let WorkPackageResource;
let dummyWorkPackages: WorkPackageResource[] = [];
beforeEach(angular.mock.module('openproject'));
beforeEach(angular.mock.inject((_wpCacheService_, _WorkPackageResource_) => {
beforeEach(angular.mock.inject((_$q_, _$rootScope_, _wpCacheService_, _WorkPackageResource_) => {
$rootScope = _$rootScope_;
$q = _$q_;
wpCacheService = _wpCacheService_;
WorkPackageResource = _WorkPackageResource_;
// dummy 1
const workPackage1 = new _WorkPackageResource_({_links: {self: ""}});
const workPackage1 = new _WorkPackageResource_({
_links: {
self: ""
}
});
workPackage1.id = 1;
workPackage1.schema = {
'$load': () => { return $q.when(true) }
};
dummyWorkPackages = [workPackage1];
}));
it('should return a work package after the list has been initialized', () => {
it('should return a work package after the list has been initialized', function(done) {
wpCacheService.updateWorkPackageList(dummyWorkPackages);
let workPackage: WorkPackageResource;
wpCacheService.loadWorkPackage(1).observe(null).subscribe(wp => {
workPackage = wp;
expect(workPackage.id).to.eq(1);
done();
});
expect(workPackage.id).to.eq(1);
$rootScope.$apply();
});
@ -74,27 +88,30 @@ describe('WorkPackageCacheService', () => {
// expect(workPackage.id).to.eq(1);
// });
it('should return/stream a work package every time it gets updated', () => {
let loaded: WorkPackageResource & {dummy: string} = null;
wpCacheService.loadWorkPackage(1).observe(null).subscribe((wp: any) => {
loaded = wp;
});
it('should return/stream a work package every time it gets updated', (done) => {
let expected = 0;
let workPackage: any = new WorkPackageResource({_links: {self: ""}});
workPackage.id = 1;
workPackage.dummy = "a";
workPackage.dummy = 0;
workPackage.schema = {
'$load': () => { return $q.when(true) }
};
wpCacheService.updateWorkPackageList([workPackage]);
expect(loaded.id).to.eq(1);
expect(loaded.dummy).to.eq("a");
$rootScope.$apply();
workPackage = new WorkPackageResource({_links: {self: ""}});
workPackage.id = 1;
workPackage.dummy = "b";
wpCacheService.loadWorkPackage(1).observe(null).subscribe((wp: any) => {
expect(wp.id).to.eq(1);
expect(wp.dummy).to.eq(expected);
expected += 1;
if (expected == 2) {
done();
}
});
workPackage.dummy = 1;
wpCacheService.updateWorkPackageList([workPackage]);
expect(loaded.id).to.eq(1);
expect(loaded.dummy).to.eq("b");
$rootScope.$apply();
});
});

@ -1,3 +1,4 @@
import {WorkPackagesListService} from './../wp-list/wp-list.service';
// -- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
@ -29,6 +30,7 @@
import {opWorkPackagesModule} from "../../angular-modules";
import {WorkPackageResource} from "../api/api-v3/hal-resources/work-package-resource.service";
import {SchemaResource} from './../api/api-v3/hal-resources/schema-resource.service';
import {ApiWorkPackagesService} from "../api/api-work-packages/api-work-packages.service";
import {State} from "../../helpers/reactive-fassade";
import IScope = angular.IScope;
@ -45,6 +47,7 @@ export class WorkPackageCacheService {
/*@ngInject*/
constructor(private states: States,
private $q: ng.IQService,
private apiWorkPackages: ApiWorkPackagesService) {
}
@ -64,7 +67,15 @@ export class WorkPackageCacheService {
? wpState.getCurrentValue() // dirty, use current wp
: wp; // not dirty or unknown, use new wp
this.states.workPackages.put(workPackageId, wpForPublish);
// Ensure the schema is loaded
// so that no consumer needs to call schema#$load manually
if (wpForPublish.schema.$loaded) {
return wpState.put(wpForPublish);
}
wpState.putFromPromise(wpForPublish.schema.$load().then(() => {
return wpForPublish;
}));
}
}
@ -74,8 +85,25 @@ export class WorkPackageCacheService {
state.clear();
}
state.putFromPromiseIfPristine(
() => this.apiWorkPackages.loadWorkPackageById(workPackageId, forceUpdate));
// Several services involved in the creation of work packages
// use this method to resolve the latest created work package,
// so let them just subscribe.
if (workPackageId.toString() === 'new') {
return state;
}
state.putFromPromiseIfPristine(() => {
const deferred = this.$q.defer();
this.apiWorkPackages.loadWorkPackageById(workPackageId, forceUpdate)
.then((workPackage:WorkPackageResource) => {
workPackage.schema.$load().then(() => {
deferred.resolve(workPackage);
});
});
return deferred.promise;
});
return state;
}

@ -65,7 +65,7 @@ describe('wpDisplayAttr directive', () => {
scope = $rootScope.$new();
// Expected request for updates
_$httpBackend_.expectGET('/api/v3/work_packages').respond(200);
_$httpBackend_.expectGET('/api/v3/work_packages/1').respond(200);
compile = () => {
$compile(element)(scope);
@ -86,6 +86,7 @@ describe('wpDisplayAttr directive', () => {
mybool: false,
type: {id: 1, name: 'Bug'},
sheep: 10,
id: 1,
customField1: 'asdf1234',
emptyField: null,
schema: {

@ -93,19 +93,17 @@ export class WorkPackageDisplayAttributeController {
protected updateAttribute(wp) {
this.workPackage = wp;
this.schema.$load().then(() => {
this.field = <DisplayField>this.wpDisplayField.getField(this.workPackage, this.attribute, this.schema[this.attribute]);
this.field = <DisplayField>this.wpDisplayField.getField(this.workPackage, this.attribute, this.schema[this.attribute]);
if (this.field.isManualRenderer) {
this.__d__renderer = this.__d__renderer || this.$element.find(".__d__renderer");
this.field.render(this.__d__renderer, this);
}
if (this.field.isManualRenderer) {
this.__d__renderer = this.__d__renderer || this.$element.find(".__d__renderer");
this.field.render(this.__d__renderer, this);
}
this.$element.attr("aria-label", this.label + " " + this.displayText);
this.$element.attr("aria-label", this.label + " " + this.displayText);
this.__d__cell = this.__d__cell || this.$element.find(".__d__cell");
this.__d__cell.toggleClass("-placeholder", this.isEmpty);
});
this.__d__cell = this.__d__cell || this.$element.find(".__d__cell");
this.__d__cell.toggleClass("-placeholder", this.isEmpty);
}
}

@ -74,6 +74,10 @@ export class WorkPackageSingleViewController {
},
};
if (this.workPackage) {
this.init(this.workPackage);
}
wpCacheService.loadWorkPackage(wpId).observe($scope).subscribe(wp => this.init(wp));
$scope.$on('workPackageUpdatedInEditor', () => {
this.wpNotificationsService.showSave(this.workPackage);
@ -124,27 +128,24 @@ export class WorkPackageSingleViewController {
this.workPackage.attachments.updateElements();
}
this.workPackage.schema.$load().then(schema => {
this.setFocus();
this.setFocus();
var otherGroup: any = _.find(this.groupedFields, {groupName: 'other'});
otherGroup.attributes = [];
var otherGroup: any = _.find(this.groupedFields, {groupName: 'other'});
otherGroup.attributes = [];
angular.forEach(schema, (prop, propName) => {
if (propName.match(/^customField/)) {
otherGroup.attributes.push(propName);
}
});
angular.forEach(this.workPackage.schema, (prop, propName) => {
if (propName.match(/^customField/)) {
otherGroup.attributes.push(propName);
}
});
otherGroup.attributes.sort((leftField, rightField) => {
var getLabel = field => this.singleViewWp.getLabel(field);
var left = getLabel(leftField).toLowerCase();
var right = getLabel(rightField).toLowerCase();
otherGroup.attributes.sort((leftField, rightField) => {
var getLabel = field => this.singleViewWp.getLabel(field);
var left = getLabel(leftField).toLowerCase();
var right = getLabel(rightField).toLowerCase();
return left.localeCompare(right);
});
return left.localeCompare(right);
});
}
}

@ -1,5 +1,4 @@
<div class="wp-edit-field inplace-edit"
ng-if="::vm.workPackage"
ng-switch="vm.active"
ng-class="[
vm.errorenous && '-error' || '',
@ -31,7 +30,7 @@
<wp-display-attr ng-switch-when="false"
attribute="::vm.fieldName"
schema="vm.workPackage.schema"
work-package="::vm.workPackage"
work-package="::vm.formCtrl.workPackage"
placeholder="::vm.displayPlaceholder"
label="vm.fieldLabel"
class="inplace-edit--read-value __d__inplace-edit--read-value"

@ -116,40 +116,38 @@ export class WorkPackageEditFieldController {
}
public initializeField() {
// Activate field when creating a work package
// and the schema requires this field
if (this.workPackage.isNew && this.workPackage.requiredValueFor(this.fieldName)) {
this.activate();
var activeField = this.formCtrl.firstActiveField;
if (!activeField || this.formCtrl.fields[activeField].fieldIndex > this.fieldIndex) {
this.formCtrl.firstActiveField = this.fieldName;
}
}
// Mark the td field if it is inline-editable
// We're resolving the non-form schema here since its loaded anyway for the table
this.workPackage.schema.$load().then(schema => {
var fieldSchema = schema[this.fieldName];
const fieldSchema = this.workPackage.schema[this.fieldName];
this.editable = fieldSchema && fieldSchema.writable;
this.fieldType = fieldSchema && this.wpEditField.fieldType(fieldSchema.type);
this.editable = fieldSchema && fieldSchema.writable;
this.fieldType = fieldSchema && this.wpEditField.fieldType(fieldSchema.type);
this.updateDisplayAttributes();
this.updateDisplayAttributes();
if (fieldSchema) {
this.fieldLabel = this.fieldLabel || fieldSchema.name;
if (fieldSchema) {
this.fieldLabel = this.fieldLabel || fieldSchema.name;
// Activate the field automatically when in editAllMode
if (this.inEditMode && this.isEditable) {
// Set focus on the first field
if(this.fieldName === 'subject')
this.activate(true);
else
this.activate();
// Activate field when creating a work package
// and the schema requires this field
if (this.workPackage.isNew && this.isRequired() && !this.workPackage[this.fieldName]) {
this.activate();
var activeField = this.formCtrl.firstActiveField;
if (!activeField || this.formCtrl.fields[activeField].fieldIndex > this.fieldIndex) {
this.formCtrl.firstActiveField = this.fieldName;
}
}
});
// Activate the field automatically when in editAllMode
if (this.inEditMode && this.isEditable) {
// Set focus on the first field
if (this.fieldName === 'subject')
this.activate(true);
else
this.activate();
}
}
}
public activateIfEditable(event) {
@ -314,7 +312,7 @@ export class WorkPackageEditFieldController {
}
protected buildEditField(): ng.IPromise<any> {
return this.formCtrl.loadSchema().then(schema => {
return this.workPackage.loadFormSchema().then(schema => {
this.field = <EditField>this.wpEditField.getField(this.workPackage, this.fieldName, schema[this.fieldName]);
this.workPackage.storePristine(this.fieldName);
});
@ -358,11 +356,6 @@ function wpEditField(wpCacheService: WorkPackageCacheService) {
scope.vm.initializeField();
});
if (formCtrl.workPackage) {
scope.vm.workPackage = formCtrl.workPackage;
scope.vm.initializeField();
}
element.addClass(scope.vm.fieldName);
element.keyup(event => {
if (event.keyCode === 27) {

@ -63,12 +63,6 @@ export class WorkPackageEditFormController {
});
}
public isFieldRequired() {
return _.filter((this.fields as any), (name: string) => {
return !this.workPackage[name] && this.workPackage.requiredValueFor(name);
});
}
public registerField(field) {
this.fields[field.fieldName] = field;
field.setErrors(this.errorsPerAttribute[field.fieldName] || []);
@ -105,10 +99,6 @@ export class WorkPackageEditFormController {
return this.workPackage.isEditable;
}
public loadSchema() {
return this.workPackage.getSchema();
}
/**
* Update the form and embedded schema.
* In edit-all mode, this allows fields to cause changes to the form (e.g., type switch)

@ -201,7 +201,6 @@ declare namespace op {
interface WorkPackage extends api.v3.WorkPackage, WorkPackageLinks {
getForm();
getSchema();
save();
links:WorkPackageLinks;
}

Loading…
Cancel
Save