Merge pull request #4067 from FinnStutzenstein/prettify
Using prettify instead of pretty-quick-wrapper
This commit is contained in:
commit
2f7336b257
@ -68,7 +68,7 @@ matrix:
|
||||
install:
|
||||
- npm install
|
||||
script:
|
||||
- npm run prettify-all
|
||||
- npm run prettify-check
|
||||
|
||||
- language: node_js
|
||||
name: "Client: Testing"
|
||||
|
@ -18,8 +18,8 @@
|
||||
"compodoc": "./node_modules/.bin/compodoc --hideGenerator -p src/tsconfig.app.json -n 'OpenSlides Documentation' -d ../Compodoc -s -w -t -o --port",
|
||||
"extract": "ngx-translate-extract -i ./src -o ./src/assets/i18n/template-en.pot -clean --sort --format pot -m _",
|
||||
"po2json": "./node_modules/.bin/po2json -f mf src/assets/i18n/de.po src/assets/i18n/de.json && ./node_modules/.bin/po2json -f mf src/assets/i18n/cs.po src/assets/i18n/cs.json",
|
||||
"prettify-changes": "pretty-quick --staged",
|
||||
"prettify-all": "pretty-quick"
|
||||
"prettify-check": "prettier --config ./.prettierrc --list-different \"src/{app,environments}/**/*{.ts,.js,.json,.css,.scss}\"",
|
||||
"prettify-write": "prettier --config ./.prettierrc --write \"src/{app,environments}/**/*{.ts,.js,.json,.css,.scss}\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": "^7.1.1",
|
||||
@ -71,7 +71,6 @@
|
||||
"karma-jasmine-html-reporter": "^0.2.2",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^1.15.3",
|
||||
"pretty-quick": "^1.8.0",
|
||||
"protractor": "^5.4.1",
|
||||
"ts-node": "~7.0.1",
|
||||
"tslint": "~5.11.0",
|
||||
|
@ -54,7 +54,6 @@ export class AppComponent {
|
||||
* TODO: Overloading can be extended to more functions.
|
||||
*/
|
||||
private overloadArrayToString(): void {
|
||||
|
||||
Array.prototype.toString = function(): string {
|
||||
let string = '';
|
||||
const iterations = Math.min(this.length, 3);
|
||||
|
@ -1,7 +1,7 @@
|
||||
// import { _ } from '@biesbjerg/ngx-translate-extract';
|
||||
|
||||
function _(key: string | string[]): string | string[] {
|
||||
return key;
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -19,10 +19,12 @@ function _(key: string | string[]): string | string[] {
|
||||
// Core config strings
|
||||
_('Presentation and assembly system');
|
||||
_('Event name');
|
||||
_('<a href="http://www.openslides.org">OpenSlides</a> is a free ' +
|
||||
_(
|
||||
'<a href="http://www.openslides.org">OpenSlides</a> is a free ' +
|
||||
'web based presentation and assembly system for visualizing ' +
|
||||
'and controlling agenda, motions and elections of an ' +
|
||||
'assembly.');
|
||||
'assembly.'
|
||||
);
|
||||
_('General');
|
||||
_('Event');
|
||||
_('Short description of event');
|
||||
@ -94,7 +96,6 @@ _('Public item');
|
||||
_('Internal item');
|
||||
_('Hidden item');
|
||||
|
||||
|
||||
// Motions config strings
|
||||
// subgroup general
|
||||
_('General');
|
||||
@ -115,13 +116,17 @@ _('Hide recommendation on projector');
|
||||
_('Stop submitting new motions by non-staff users');
|
||||
_('Allow to disable versioning');
|
||||
_('Name of recommender');
|
||||
_('Will be displayed as label before selected recommendation. Use an empty value to disable the recommendation system.');
|
||||
_(
|
||||
'Will be displayed as label before selected recommendation. Use an empty value to disable the recommendation system.'
|
||||
);
|
||||
_('Name of recommender for statute amendments');
|
||||
_('Will be displayed as label before selected recommendation for statute amendments. Use an empty value to disable the recommendation system.');
|
||||
_(
|
||||
'Will be displayed as label before selected recommendation for statute amendments. Use an empty value to disable the recommendation system.'
|
||||
);
|
||||
_('Default text version for change recommendations');
|
||||
// subgroup Amendments
|
||||
_('Amendments');
|
||||
_('Activate statute amendments')
|
||||
_('Activate statute amendments');
|
||||
_('Activate amendments');
|
||||
_('Show amendments together with motions');
|
||||
_('Prefix for the identifier for amendments');
|
||||
@ -210,7 +215,6 @@ _('Called with');
|
||||
_('Recommendation');
|
||||
_('Motion block');
|
||||
|
||||
|
||||
// Assignment config strings
|
||||
_('Election method');
|
||||
_('Automatic assign of method');
|
||||
@ -220,10 +224,12 @@ _('Always Yes/No per candidate');
|
||||
_('Elections');
|
||||
_('Ballot and ballot papers');
|
||||
_('The 100-%-base of an election result consists of');
|
||||
_('For Yes/No/Abstain per candidate and Yes/No per candidate the 100-%-base ' +
|
||||
_(
|
||||
'For Yes/No/Abstain per candidate and Yes/No per candidate the 100-%-base ' +
|
||||
'depends on the election method: If there is only one option per candidate, ' +
|
||||
'the sum of all votes of all candidates is 100 %. Otherwise for each ' +
|
||||
'candidate the sum of all votes is 100 %.');
|
||||
'candidate the sum of all votes is 100 %.'
|
||||
);
|
||||
_('Yes/No/Abstain per candidate');
|
||||
_('Yes/No per candidate');
|
||||
_('All valid ballots');
|
||||
@ -316,7 +322,9 @@ _('Email subject');
|
||||
_('Your login for {event_name}');
|
||||
_('You can use {event_name} as a placeholder.');
|
||||
_('Email body');
|
||||
_('Dear {name},\n\nthis is your OpenSlides login for the event {event_name}:\n\n {url}\n username: {username}\n password: {password}\n\nThis email was generated automatically.');
|
||||
_(
|
||||
'Dear {name},\n\nthis is your OpenSlides login for the event {event_name}:\n\n {url}\n username: {username}\n password: {password}\n\nThis email was generated automatically.'
|
||||
);
|
||||
_('Use these placeholders: {name}, {event_name}, {url}, {username}, {password}. The url referrs to the system url.');
|
||||
|
||||
// default groups
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
type QueryParamValue = string | number | boolean;
|
||||
|
||||
/**
|
||||
|
@ -79,7 +79,11 @@ export class AppLoadService {
|
||||
// between (ModelConstructor<BaseModel>) and (new (...args: any[]) => (BaseModel & Searchable)), we would not have
|
||||
// to check if the result of the contructor (the model instance) is really a searchable.
|
||||
if (!isSearchable(new entry.model())) {
|
||||
throw Error(`Wrong configuration for ${entry.collectionString}: you gave a searchOrder, but the model is not searchable.`);
|
||||
throw Error(
|
||||
`Wrong configuration for ${
|
||||
entry.collectionString
|
||||
}: you gave a searchOrder, but the model is not searchable.`
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -115,40 +115,44 @@ export class CsvExportService {
|
||||
csvContent.push(header);
|
||||
|
||||
// create lines
|
||||
csvContent = csvContent.concat(models.map(model => {
|
||||
return columns.map(column => {
|
||||
let value: string;
|
||||
csvContent = csvContent.concat(
|
||||
models.map(model => {
|
||||
return columns.map(column => {
|
||||
let value: string;
|
||||
|
||||
if (isPropertyDefinition(column)) {
|
||||
const property: any = model[column.property];
|
||||
if (typeof property === 'number') {
|
||||
value = property.toString(10);
|
||||
} else if (!property) {
|
||||
value = '';
|
||||
} else if (property === true) {
|
||||
value = '1';
|
||||
} else if (property === false) {
|
||||
value = '0';
|
||||
} else {
|
||||
value = property.toString();
|
||||
if (isPropertyDefinition(column)) {
|
||||
const property: any = model[column.property];
|
||||
if (typeof property === 'number') {
|
||||
value = property.toString(10);
|
||||
} else if (!property) {
|
||||
value = '';
|
||||
} else if (property === true) {
|
||||
value = '1';
|
||||
} else if (property === false) {
|
||||
value = '0';
|
||||
} else {
|
||||
value = property.toString();
|
||||
}
|
||||
} else if (isMapDefinition(column)) {
|
||||
value = column.map(model);
|
||||
}
|
||||
} else if (isMapDefinition(column)) {
|
||||
value = column.map(model);
|
||||
}
|
||||
tsList = this.checkCsvTextSafety(value, tsList);
|
||||
tsList = this.checkCsvTextSafety(value, tsList);
|
||||
|
||||
return value;
|
||||
});
|
||||
}));
|
||||
return value;
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
// assemble lines, putting text separator in place
|
||||
if (!tsList.length) {
|
||||
throw new Error('no usable text separator left for valid csv text');
|
||||
}
|
||||
|
||||
const csvContentAsString: string = csvContent.map(line => {
|
||||
return line.map(entry => tsList[0] + entry + tsList[0]).join(columnSeparator);
|
||||
}).join(lineSeparator);
|
||||
const csvContentAsString: string = csvContent
|
||||
.map(line => {
|
||||
return line.map(entry => tsList[0] + entry + tsList[0]).join(columnSeparator);
|
||||
})
|
||||
.join(lineSeparator);
|
||||
this.exporter.saveFile(csvContentAsString, filename);
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,9 @@ export class DataStoreService {
|
||||
/**
|
||||
* Observable subject for changed or deleted models in the datastore.
|
||||
*/
|
||||
private readonly changedOrDeletedSubject: Subject<BaseModel | DeletedInformation> = new Subject<BaseModel | DeletedInformation>();
|
||||
private readonly changedOrDeletedSubject: Subject<BaseModel | DeletedInformation> = new Subject<
|
||||
BaseModel | DeletedInformation
|
||||
>();
|
||||
|
||||
/**
|
||||
* Observe the datastore for changes and deletions.
|
||||
@ -358,7 +360,7 @@ export class DataStoreService {
|
||||
collection: collectionString,
|
||||
id: +id // needs casting, because Objects.keys gives all keys as strings...
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
if (models && models.length) {
|
||||
await this.add(models, newMaxChangeId);
|
||||
|
@ -5,7 +5,6 @@ import { BaseModel } from '../../shared/models/base/base-model';
|
||||
import { BaseViewModel } from '../../site/base/base-view-model';
|
||||
import { StorageService } from './storage.service';
|
||||
|
||||
|
||||
/**
|
||||
* Describes the available filters for a listView.
|
||||
* @param isActive: the current state of the filter
|
||||
@ -18,7 +17,7 @@ import { StorageService } from './storage.service';
|
||||
export interface OsFilter {
|
||||
property: string;
|
||||
label?: string;
|
||||
options: (OsFilterOption | string )[];
|
||||
options: (OsFilterOption | string)[];
|
||||
count?: number;
|
||||
}
|
||||
|
||||
@ -31,15 +30,12 @@ export interface OsFilterOption {
|
||||
isActive?: boolean;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Filter for the list view. List views can subscribe to its' dataService (providing filter definitions)
|
||||
* and will receive their filtered data as observable
|
||||
*/
|
||||
|
||||
export abstract class FilterListService<M extends BaseModel, V extends BaseViewModel> {
|
||||
|
||||
/**
|
||||
* stores the currently used raw data to be used for the filter
|
||||
*/
|
||||
@ -70,11 +66,14 @@ export abstract class FilterListService<M extends BaseModel, V extends BaseViewM
|
||||
* Initializes the filterService. Returns the filtered data as Observable
|
||||
*/
|
||||
public filter(): Observable<V[]> {
|
||||
this.repo.getViewModelListObservable().pipe(auditTime(100)).subscribe( data => {
|
||||
this.currentRawData = data;
|
||||
this.filteredData = this.filterData(data);
|
||||
this.filterDataOutput.next(this.filteredData);
|
||||
});
|
||||
this.repo
|
||||
.getViewModelListObservable()
|
||||
.pipe(auditTime(100))
|
||||
.subscribe(data => {
|
||||
this.currentRawData = data;
|
||||
this.filteredData = this.filterData(data);
|
||||
this.filterDataOutput.next(this.filteredData);
|
||||
});
|
||||
this.loadStorageDefinition(this.filterDefinitions);
|
||||
return this.filterDataOutput;
|
||||
}
|
||||
@ -84,11 +83,12 @@ export abstract class FilterListService<M extends BaseModel, V extends BaseViewM
|
||||
* @param filter
|
||||
*/
|
||||
public addFilterOption(filterName: string, option: OsFilterOption): void {
|
||||
const filter = this.filterDefinitions.find(f => f.property === filterName );
|
||||
const filter = this.filterDefinitions.find(f => f.property === filterName);
|
||||
if (filter) {
|
||||
const filterOption = filter.options.find(o =>
|
||||
(typeof o !== 'string') && o.condition === option.condition) as OsFilterOption;
|
||||
if (filterOption && !filterOption.isActive){
|
||||
const filterOption = filter.options.find(
|
||||
o => typeof o !== 'string' && o.condition === option.condition
|
||||
) as OsFilterOption;
|
||||
if (filterOption && !filterOption.isActive) {
|
||||
filterOption.isActive = true;
|
||||
filter.count += 1;
|
||||
}
|
||||
@ -103,11 +103,12 @@ export abstract class FilterListService<M extends BaseModel, V extends BaseViewM
|
||||
}
|
||||
|
||||
public removeFilterOption(filterName: string, option: OsFilterOption): void {
|
||||
const filter = this.filterDefinitions.find(f => f.property === filterName );
|
||||
const filter = this.filterDefinitions.find(f => f.property === filterName);
|
||||
if (filter) {
|
||||
const filterOption = filter.options.find(o =>
|
||||
(typeof o !== 'string') && o.condition === option.condition) as OsFilterOption;
|
||||
if (filterOption && filterOption.isActive){
|
||||
const filterOption = filter.options.find(
|
||||
o => typeof o !== 'string' && o.condition === option.condition
|
||||
) as OsFilterOption;
|
||||
if (filterOption && filterOption.isActive) {
|
||||
filterOption.isActive = false;
|
||||
filter.count -= 1;
|
||||
this.filteredData = this.filterData(this.currentRawData);
|
||||
@ -126,11 +127,10 @@ export abstract class FilterListService<M extends BaseModel, V extends BaseViewM
|
||||
option.isActive ? this.removeFilterOption(filterName, option) : this.addFilterOption(filterName, option);
|
||||
}
|
||||
|
||||
public updateFilterDefinitions(filters: OsFilter[]) : void {
|
||||
public updateFilterDefinitions(filters: OsFilter[]): void {
|
||||
this.loadStorageDefinition(filters);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the currently saved filter definition from the StorageService,
|
||||
* check their match with current definitions and set the current filter
|
||||
@ -141,35 +141,39 @@ export abstract class FilterListService<M extends BaseModel, V extends BaseViewM
|
||||
return;
|
||||
}
|
||||
const me = this;
|
||||
this.store.get('filter_' + this.name).then(function(storedData: { name: string, data: OsFilter[] }): void {
|
||||
const storedFilters = (storedData && storedData.data) ? storedData.data : [];
|
||||
definitions.forEach(definedFilter => {
|
||||
const matchingStoreFilter = storedFilters.find(f => f.property === definedFilter.property);
|
||||
let count = 0;
|
||||
definedFilter.options.forEach(option => {
|
||||
if (typeof option === 'string'){
|
||||
return;
|
||||
};
|
||||
if (matchingStoreFilter && matchingStoreFilter.options){
|
||||
const storedOption = matchingStoreFilter.options.find(o =>
|
||||
typeof o !== 'string' && o.condition === option.condition) as OsFilterOption;
|
||||
if (storedOption) {
|
||||
option.isActive = storedOption.isActive;
|
||||
this.store.get('filter_' + this.name).then(
|
||||
function(storedData: { name: string; data: OsFilter[] }): void {
|
||||
const storedFilters = storedData && storedData.data ? storedData.data : [];
|
||||
definitions.forEach(definedFilter => {
|
||||
const matchingStoreFilter = storedFilters.find(f => f.property === definedFilter.property);
|
||||
let count = 0;
|
||||
definedFilter.options.forEach(option => {
|
||||
if (typeof option === 'string') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (option.isActive) {
|
||||
count += 1;
|
||||
}
|
||||
if (matchingStoreFilter && matchingStoreFilter.options) {
|
||||
const storedOption = matchingStoreFilter.options.find(
|
||||
o => typeof o !== 'string' && o.condition === option.condition
|
||||
) as OsFilterOption;
|
||||
if (storedOption) {
|
||||
option.isActive = storedOption.isActive;
|
||||
}
|
||||
}
|
||||
if (option.isActive) {
|
||||
count += 1;
|
||||
}
|
||||
});
|
||||
definedFilter.count = count;
|
||||
});
|
||||
definedFilter.count = count;
|
||||
});
|
||||
me.filterDefinitions = definitions;
|
||||
me.filteredData = me.filterData(me.currentRawData);
|
||||
me.filterDataOutput.next(me.filteredData);
|
||||
}, function(error: any) : void {
|
||||
me.filteredData = me.filterData(me.currentRawData);
|
||||
me.filterDataOutput.next(me.filteredData);
|
||||
});
|
||||
me.filterDefinitions = definitions;
|
||||
me.filteredData = me.filterData(me.currentRawData);
|
||||
me.filterDataOutput.next(me.filteredData);
|
||||
},
|
||||
function(error: any): void {
|
||||
me.filteredData = me.filterData(me.currentRawData);
|
||||
me.filterDataOutput.next(me.filteredData);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -177,10 +181,11 @@ export abstract class FilterListService<M extends BaseModel, V extends BaseViewM
|
||||
*/
|
||||
private setStorageDefinition(): void {
|
||||
this.store.set('filter_' + this.name, {
|
||||
name: 'filter_' + this.name, data: this.filterDefinitions});
|
||||
name: 'filter_' + this.name,
|
||||
data: this.filterDefinitions
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Takes an array of data and applies current filters
|
||||
*/
|
||||
@ -189,7 +194,7 @@ export abstract class FilterListService<M extends BaseModel, V extends BaseViewM
|
||||
if (!data) {
|
||||
return filteredData;
|
||||
}
|
||||
if (!this.filterDefinitions || !this.filterDefinitions.length){
|
||||
if (!this.filterDefinitions || !this.filterDefinitions.length) {
|
||||
return data;
|
||||
}
|
||||
data.forEach(newItem => {
|
||||
@ -200,7 +205,7 @@ export abstract class FilterListService<M extends BaseModel, V extends BaseViewM
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!excluded){
|
||||
if (!excluded) {
|
||||
filteredData.push(newItem);
|
||||
}
|
||||
});
|
||||
@ -214,27 +219,27 @@ export abstract class FilterListService<M extends BaseModel, V extends BaseViewM
|
||||
*/
|
||||
private checkIncluded(item: V, filter: OsFilter): boolean {
|
||||
for (const option of filter.options) {
|
||||
if (typeof option === 'string' ){
|
||||
if (typeof option === 'string') {
|
||||
continue;
|
||||
}
|
||||
if (option.isActive) {
|
||||
if (option.condition === null ) {
|
||||
if (option.condition === null) {
|
||||
return this.checkIncludedNegative(item, filter);
|
||||
}
|
||||
if (item[filter.property] === undefined) {
|
||||
return false;
|
||||
}
|
||||
if (item[filter.property] instanceof BaseModel ) {
|
||||
if (item[filter.property].id === option.condition){
|
||||
if (item[filter.property] instanceof BaseModel) {
|
||||
if (item[filter.property].id === option.condition) {
|
||||
return true;
|
||||
}
|
||||
} else if (item[filter.property] === option.condition){
|
||||
}
|
||||
} else if (item[filter.property] === option.condition) {
|
||||
return true;
|
||||
} else if (item[filter.property].toString() === option.condition){
|
||||
} else if (item[filter.property].toString() === option.condition) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -254,7 +259,7 @@ export abstract class FilterListService<M extends BaseModel, V extends BaseViewM
|
||||
}
|
||||
if (item[filter.property] === option.condition) {
|
||||
return false;
|
||||
} else if (item[filter.property].toString() === option.condition){
|
||||
} else if (item[filter.property].toString() === option.condition) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -271,20 +276,19 @@ export abstract class FilterListService<M extends BaseModel, V extends BaseViewM
|
||||
}
|
||||
|
||||
public get hasActiveFilters(): number {
|
||||
if (!this.filterDefinitions || !this.filterDefinitions.length){
|
||||
if (!this.filterDefinitions || !this.filterDefinitions.length) {
|
||||
return 0;
|
||||
}
|
||||
let filters = 0;
|
||||
for (const filter of this.filterDefinitions) {
|
||||
if (filter.count){
|
||||
if (filter.count) {
|
||||
filters += 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
return filters;
|
||||
}
|
||||
|
||||
public hasFilterOptions(): boolean {
|
||||
return (this.filterDefinitions && this.filterDefinitions.length) ? true : false;
|
||||
return this.filterDefinitions && this.filterDefinitions.length ? true : false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -55,7 +55,13 @@ export class HttpService {
|
||||
* @param customHeader optional custom HTTP header of required
|
||||
* @returns a promise containing a generic
|
||||
*/
|
||||
private async send<T>(path: string, method: HTTPMethod, data?: any, queryParams?: QueryParams, customHeader?: HttpHeaders): Promise<T> {
|
||||
private async send<T>(
|
||||
path: string,
|
||||
method: HTTPMethod,
|
||||
data?: any,
|
||||
queryParams?: QueryParams,
|
||||
customHeader?: HttpHeaders
|
||||
): Promise<T> {
|
||||
// end early, if we are in history mode
|
||||
if (this.OSStatus.isInHistoryMode && method !== HTTPMethod.GET) {
|
||||
throw this.handleError('You cannot make changes while in history mode');
|
||||
|
@ -8,7 +8,6 @@ import { Injectable } from '@angular/core';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class OpenSlidesStatusService {
|
||||
|
||||
/**
|
||||
* Saves, if OpenSlides is in the history mode.
|
||||
*/
|
||||
@ -37,6 +36,6 @@ export class OpenSlidesStatusService {
|
||||
* Leaves the histroy mode
|
||||
*/
|
||||
public leaveHistroyMode(): void {
|
||||
this.historyMode = false;
|
||||
this.historyMode = false;
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,12 @@ import { TimeTravelService } from './time-travel.service';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
describe('TimeTravelService', () => {
|
||||
beforeEach(() => TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
providers: [TimeTravelService]
|
||||
}));
|
||||
beforeEach(() =>
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
providers: [TimeTravelService]
|
||||
})
|
||||
);
|
||||
|
||||
it('should be created', () => {
|
||||
const service: TimeTravelService = TestBed.get(TimeTravelService);
|
||||
|
@ -52,7 +52,7 @@ export class TimeTravelService {
|
||||
private DS: DataStoreService,
|
||||
private OSStatus: OpenSlidesStatusService,
|
||||
private OpenSlides: OpenSlidesService
|
||||
) { }
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Main entry point to set OpenSlides to another history point.
|
||||
@ -65,11 +65,11 @@ export class TimeTravelService {
|
||||
for (const historyObject of fullDataHistory) {
|
||||
let collectionString: string;
|
||||
let id: string;
|
||||
[collectionString, id] = historyObject.element_id.split(':')
|
||||
[collectionString, id] = historyObject.element_id.split(':');
|
||||
|
||||
if (historyObject.full_data) {
|
||||
const targetClass = this.modelMapperService.getModelConstructor(collectionString);
|
||||
await this.DS.add([new targetClass(historyObject.full_data)])
|
||||
await this.DS.add([new targetClass(historyObject.full_data)]);
|
||||
} else {
|
||||
await this.DS.remove(collectionString, [+id]);
|
||||
}
|
||||
@ -94,7 +94,7 @@ export class TimeTravelService {
|
||||
* @returns the full history on the given date
|
||||
*/
|
||||
private async getHistoryData(history: History): Promise<HistoryData[]> {
|
||||
const historyUrl = '/core/history/'
|
||||
const historyUrl = '/core/history/';
|
||||
const queryParams = { timestamp: Math.ceil(+history.unixtime) };
|
||||
return this.httpService.get<HistoryData[]>(environment.urlPrefix + historyUrl, null, queryParams);
|
||||
}
|
||||
|
@ -71,11 +71,7 @@ export class WebsocketService {
|
||||
* @param zone
|
||||
* @param translate
|
||||
*/
|
||||
public constructor(
|
||||
private matSnackBar: MatSnackBar,
|
||||
private zone: NgZone,
|
||||
public translate: TranslateService
|
||||
) {}
|
||||
public constructor(private matSnackBar: MatSnackBar, private zone: NgZone, public translate: TranslateService) {}
|
||||
|
||||
/**
|
||||
* Creates a new WebSocket connection and handles incomming events.
|
||||
|
@ -51,7 +51,7 @@ interface ChoiceDialogData {
|
||||
* it will be an array of numbers and optionally an action string for multichoice
|
||||
* dialogs
|
||||
*/
|
||||
export type ChoiceAnswer = undefined | { action?: string; items: number | number[]};
|
||||
export type ChoiceAnswer = undefined | { action?: string; items: number | number[] };
|
||||
|
||||
/**
|
||||
* A dialog with choice fields.
|
||||
|
@ -5,19 +5,16 @@ describe('FilterMenuComponent', () => {
|
||||
// TODO test won't work without a BaseViewModel
|
||||
// let component: FilterMenuComponent<V>;
|
||||
// let fixture: ComponentFixture<FilterMenuComponent<V>>;
|
||||
|
||||
// beforeEach(async(() => {
|
||||
// TestBed.configureTestingModule({
|
||||
// declarations: [FilterMenuComponent]
|
||||
// }).compileComponents();
|
||||
// }));
|
||||
|
||||
// beforeEach(() => {
|
||||
// fixture = TestBed.createComponent(FilterMenuComponent);
|
||||
// component = fixture.componentInstance;
|
||||
// fixture.detectChanges();
|
||||
// });
|
||||
|
||||
// it('should create', () => {
|
||||
// expect(component).toBeTruthy();
|
||||
// });
|
||||
|
@ -18,7 +18,6 @@ import { FilterListService, OsFilterOption } from '../../../../core/services/fil
|
||||
styleUrls: ['./filter-menu.component.scss']
|
||||
})
|
||||
export class FilterMenuComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* An event emitter to submit a desire to close this component
|
||||
* TODO: Might be an easier way to do this
|
||||
@ -37,8 +36,7 @@ export class FilterMenuComponent implements OnInit {
|
||||
* Constructor. Does nothing.
|
||||
* @param service
|
||||
*/
|
||||
public constructor() {
|
||||
}
|
||||
public constructor() {}
|
||||
|
||||
/**
|
||||
* Directly closes again if no sorting is available
|
||||
@ -53,12 +51,12 @@ export class FilterMenuComponent implements OnInit {
|
||||
* Tests for escape key (to colose the sidebar)
|
||||
* @param event
|
||||
*/
|
||||
public checkKeyEvent(event: KeyboardEvent) : void {
|
||||
if (event.key === 'Escape'){
|
||||
this.dismissed.next(true)
|
||||
public checkKeyEvent(event: KeyboardEvent): void {
|
||||
if (event.key === 'Escape') {
|
||||
this.dismissed.next(true);
|
||||
}
|
||||
}
|
||||
public isFilter(option: OsFilterOption) : boolean{
|
||||
return (typeof option === 'string') ? false : true;
|
||||
public isFilter(option: OsFilterOption): boolean {
|
||||
return typeof option === 'string' ? false : true;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
import { OsSortBottomSheetComponent } from './os-sort-bottom-sheet.component';
|
||||
|
||||
|
||||
describe('OsSortBottomSheetComponent', () => {
|
||||
// let component: OsSortBottomSheetComponent<any>;
|
||||
let fixture: ComponentFixture<OsSortBottomSheetComponent<any>>;
|
||||
|
@ -19,21 +19,21 @@ import { SortListService } from '../../../../core/services/sort-list.service';
|
||||
styleUrls: ['./os-sort-bottom-sheet.component.scss']
|
||||
})
|
||||
export class OsSortBottomSheetComponent<V extends BaseViewModel> implements OnInit {
|
||||
|
||||
/**
|
||||
* Constructor. Gets a reference to itself (for closing after interaction)
|
||||
* @param data
|
||||
* @param sheetRef
|
||||
*/
|
||||
public constructor(
|
||||
@Inject(MAT_BOTTOM_SHEET_DATA) public data: SortListService<V>, private sheetRef: MatBottomSheetRef ) {
|
||||
}
|
||||
@Inject(MAT_BOTTOM_SHEET_DATA) public data: SortListService<V>,
|
||||
private sheetRef: MatBottomSheetRef
|
||||
) {}
|
||||
|
||||
/**
|
||||
* init fucntion. Closes inmediately if no sorting is available.
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
if (!this.data || !this.data.sortOptions || !this.data.sortOptions.options.length){
|
||||
if (!this.data || !this.data.sortOptions || !this.data.sortOptions.options.length) {
|
||||
throw new Error('No sorting available for a sorting list');
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ describe('OsSortFilterBarComponent', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
imports: [E2EImportsModule]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
|
@ -4,8 +4,8 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { BaseViewModel } from '../../../site/base/base-view-model';
|
||||
import { OsSortBottomSheetComponent } from './os-sort-bottom-sheet/os-sort-bottom-sheet.component';
|
||||
import { FilterMenuComponent} from './filter-menu/filter-menu.component';
|
||||
import { OsSortingItem } from '../../../core/services/sort-list.service'
|
||||
import { FilterMenuComponent } from './filter-menu/filter-menu.component';
|
||||
import { OsSortingItem } from '../../../core/services/sort-list.service';
|
||||
import { SortListService } from '../../../core/services/sort-list.service';
|
||||
import { ViewportService } from '../../../core/services/viewport.service';
|
||||
|
||||
@ -29,7 +29,6 @@ import { ViewportService } from '../../../core/services/viewport.service';
|
||||
styleUrls: ['./os-sort-filter-bar.component.scss']
|
||||
})
|
||||
export class OsSortFilterBarComponent<V extends BaseViewModel> {
|
||||
|
||||
/**
|
||||
* The currently active sorting service for the list view
|
||||
*/
|
||||
@ -68,7 +67,11 @@ export class OsSortFilterBarComponent<V extends BaseViewModel> {
|
||||
* @param vp
|
||||
* @param bottomSheet
|
||||
*/
|
||||
public constructor(public translate: TranslateService, public vp: ViewportService, private bottomSheet: MatBottomSheet) {
|
||||
public constructor(
|
||||
public translate: TranslateService,
|
||||
public vp: ViewportService,
|
||||
private bottomSheet: MatBottomSheet
|
||||
) {
|
||||
this.filterMenu = new FilterMenuComponent();
|
||||
}
|
||||
|
||||
@ -77,9 +80,7 @@ export class OsSortFilterBarComponent<V extends BaseViewModel> {
|
||||
*/
|
||||
public openSortDropDown(): void {
|
||||
if (this.vp.isMobile) {
|
||||
const bottomSheetRef = this.bottomSheet.open(OsSortBottomSheetComponent,
|
||||
{ data: this.sortService }
|
||||
);
|
||||
const bottomSheetRef = this.bottomSheet.open(OsSortBottomSheetComponent, { data: this.sortService });
|
||||
bottomSheetRef.afterDismissed().subscribe(result => {
|
||||
if (result) {
|
||||
this.sortService.sortProperty = result;
|
||||
@ -92,7 +93,7 @@ export class OsSortFilterBarComponent<V extends BaseViewModel> {
|
||||
* Listen to keypresses on the quick-search input
|
||||
*/
|
||||
public applySearch(event: KeyboardEvent, value?: string): void {
|
||||
if (event.key === 'Escape' ) {
|
||||
if (event.key === 'Escape') {
|
||||
this.searchFieldChange.emit('');
|
||||
this.isSearchBar = false;
|
||||
} else {
|
||||
@ -104,16 +105,16 @@ export class OsSortFilterBarComponent<V extends BaseViewModel> {
|
||||
* Checks if there is an active SortService present
|
||||
*/
|
||||
public get hasSorting(): boolean {
|
||||
return (this.sortService && this.sortService.isActive);
|
||||
return this.sortService && this.sortService.isActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there is an active FilterService present
|
||||
*/
|
||||
public get hasFilters(): boolean {
|
||||
if (this.filterService && this.filterService.hasFilterOptions()){
|
||||
if (this.filterService && this.filterService.hasFilterOptions()) {
|
||||
return true;
|
||||
};
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -122,7 +123,7 @@ export class OsSortFilterBarComponent<V extends BaseViewModel> {
|
||||
* @param option
|
||||
*/
|
||||
public getSortIcon(option: OsSortingItem<V>): string {
|
||||
if (this.sortService.sortProperty !== option.property){
|
||||
if (this.sortService.sortProperty !== option.property) {
|
||||
return '';
|
||||
}
|
||||
return this.sortService.ascending ? 'arrow_downward' : 'arrow_upward';
|
||||
@ -133,7 +134,7 @@ export class OsSortFilterBarComponent<V extends BaseViewModel> {
|
||||
* the property is used.
|
||||
* @param option
|
||||
*/
|
||||
public getSortLabel(option: OsSortingItem<V>) : string {
|
||||
public getSortLabel(option: OsSortingItem<V>): string {
|
||||
if (option.label) {
|
||||
return option.label;
|
||||
}
|
||||
@ -146,7 +147,7 @@ export class OsSortFilterBarComponent<V extends BaseViewModel> {
|
||||
* that input applied
|
||||
*/
|
||||
public toggleSearchBar(): void {
|
||||
if (!this.isSearchBar){
|
||||
if (!this.isSearchBar) {
|
||||
this.isSearchBar = true;
|
||||
} else {
|
||||
this.searchFieldChange.emit('');
|
||||
|
@ -78,7 +78,7 @@ export class SortingListComponent implements OnInit, OnDestroy {
|
||||
if (newValues instanceof Observable) {
|
||||
this.inputSubscription = newValues.subscribe(values => {
|
||||
this.updateArray(values);
|
||||
})
|
||||
});
|
||||
} else {
|
||||
this.inputSubscription = null;
|
||||
this.updateArray(newValues);
|
||||
|
@ -10,7 +10,12 @@ import { BehaviorSubject } from 'rxjs';
|
||||
* A test model for the sorting
|
||||
*/
|
||||
class TestModel implements Identifiable, Displayable {
|
||||
public constructor(public id: number, public name: string, public weight: number, public parent_id: number | null){}
|
||||
public constructor(
|
||||
public id: number,
|
||||
public name: string,
|
||||
public weight: number,
|
||||
public parent_id: number | null
|
||||
) {}
|
||||
|
||||
public getTitle(): string {
|
||||
return this.name;
|
||||
|
@ -3,11 +3,10 @@ import { Poll } from './poll';
|
||||
import { AgendaBaseModel } from '../base/agenda-base-model';
|
||||
import { SearchRepresentation } from '../../../core/services/search.service';
|
||||
|
||||
|
||||
export const assignmentPhase = [
|
||||
{key: 0, name: 'Searching for candidates'},
|
||||
{key: 1, name: 'Voting'},
|
||||
{key: 2, name: 'Finished'}
|
||||
{ key: 0, name: 'Searching for candidates' },
|
||||
{ key: 1, name: 'Voting' },
|
||||
{ key: 2, name: 'Finished' }
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -46,7 +46,6 @@ export abstract class AgendaBaseModel extends ProjectableBaseModel implements Ag
|
||||
*/
|
||||
public abstract formatForSearch(): SearchRepresentation;
|
||||
|
||||
|
||||
/**
|
||||
* Should return the URL to the detail view. Used for the agenda, that the
|
||||
* user can navigate to the content object.
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { DetailNavigable } from "./detail-navigable";
|
||||
import { DetailNavigable } from './detail-navigable';
|
||||
|
||||
/**
|
||||
* An Interface for all extra information needed for content objects of items.
|
||||
|
@ -98,7 +98,7 @@ export abstract class BaseModel<T = object> extends OpenSlidesComponent
|
||||
// topicS, motionS, (media)fileS, motion blockS, commentS, personal noteS, projectorS, messageS, countdownS, ...)
|
||||
// Just categorIES need to overwrite this...
|
||||
} else {
|
||||
return this._verboseName
|
||||
return this._verboseName;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
import { BaseModel } from '../base/base-model';
|
||||
|
||||
/**
|
||||
|
@ -86,7 +86,7 @@ export class Motion extends AgendaBaseModel {
|
||||
* @override
|
||||
*/
|
||||
public formatForSearch(): SearchRepresentation {
|
||||
let searchValues = [this.title, this.text, this.reason]
|
||||
let searchValues = [this.title, this.text, this.reason];
|
||||
if (this.amendment_paragraphs) {
|
||||
searchValues = searchValues.concat(this.amendment_paragraphs.filter(x => !!x));
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ export class WorkflowState extends Deserializer {
|
||||
* Checks if a workflowstate has no 'next state' left, and is final
|
||||
*/
|
||||
public get isFinalState(): boolean {
|
||||
if (!this.next_states_id || !this.next_states_id.length ){
|
||||
if (!this.next_states_id || !this.next_states_id.length) {
|
||||
return true;
|
||||
}
|
||||
if (this.next_states_id.length === 1 && this.next_states_id[0] === 0) {
|
||||
|
@ -4,7 +4,10 @@ import { Topic } from '../../shared/models/topics/topic';
|
||||
|
||||
export const AgendaAppConfig: AppConfig = {
|
||||
name: 'agenda',
|
||||
models: [{ collectionString: 'agenda/item', model: Item }, { collectionString: 'topics/topic', model: Topic, searchOrder: 1 }],
|
||||
models: [
|
||||
{ collectionString: 'agenda/item', model: Item },
|
||||
{ collectionString: 'topics/topic', model: Topic, searchOrder: 1 }
|
||||
],
|
||||
mainMenuEntries: [
|
||||
{
|
||||
route: '/agenda',
|
||||
|
@ -12,7 +12,7 @@ import { ItemInfoDialogComponent } from './components/item-info-dialog/item-info
|
||||
*/
|
||||
@NgModule({
|
||||
imports: [CommonModule, AgendaRoutingModule, SharedModule],
|
||||
entryComponents: [ ItemInfoDialogComponent ],
|
||||
entryComponents: [ItemInfoDialogComponent],
|
||||
declarations: [AgendaListComponent, TopicDetailComponent, ItemInfoDialogComponent]
|
||||
})
|
||||
export class AgendaModule {}
|
||||
|
@ -1,5 +1,4 @@
|
||||
.os-listview-table {
|
||||
|
||||
/** Title */
|
||||
.mat-column-title {
|
||||
padding-left: 26px;
|
||||
@ -27,7 +26,6 @@
|
||||
height: $icon-size;
|
||||
width: $icon-size;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,6 @@ import { ListViewBaseComponent } from 'app/site/base/list-view-base';
|
||||
import { PromptService } from '../../../../core/services/prompt.service';
|
||||
import { ViewItem } from '../../models/view-item';
|
||||
|
||||
|
||||
import { AgendaCsvExportService } from '../../services/agenda-csv-export.service';
|
||||
import { ItemInfoDialogComponent } from '../item-info-dialog/item-info-dialog.component';
|
||||
import { ViewportService } from 'app/core/services/viewport.service';
|
||||
|
@ -73,7 +73,7 @@ export class SpeakerListComponent extends BaseViewComponent implements OnInit {
|
||||
private itemRepo: AgendaRepositoryService,
|
||||
private op: OperatorService
|
||||
) {
|
||||
super(title, translate, snackBar)
|
||||
super(title, translate, snackBar);
|
||||
this.addSpeakerForm = new FormGroup({ user_id: new FormControl([]) });
|
||||
this.getAgendaItemByUrl();
|
||||
}
|
||||
|
@ -44,14 +44,14 @@ export class ViewItem extends BaseViewModel {
|
||||
return '';
|
||||
}
|
||||
|
||||
public get verboseType() : string {
|
||||
public get verboseType(): string {
|
||||
if (this.item && this.item.verboseType) {
|
||||
return this.item.verboseType;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public get verboseCsvType() : string {
|
||||
public get verboseCsvType(): string {
|
||||
if (this.item) {
|
||||
return this.item.verboseCsvType;
|
||||
}
|
||||
|
@ -11,10 +11,7 @@ describe('AgendaCsvExportService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject(
|
||||
[AgendaCsvExportService],
|
||||
(service: AgendaCsvExportService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}
|
||||
));
|
||||
it('should be created', inject([AgendaCsvExportService], (service: AgendaCsvExportService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
||||
|
@ -12,7 +12,6 @@ import { ViewItem } from '../models/view-item';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AgendaCsvExportService {
|
||||
|
||||
/**
|
||||
* Does nothing.
|
||||
*
|
||||
@ -27,10 +26,14 @@ export class AgendaCsvExportService {
|
||||
* @param Agendas Agendas to export
|
||||
*/
|
||||
public exportItemList(items: ViewItem[]): void {
|
||||
this.csvExport.export(items,
|
||||
this.csvExport.export(
|
||||
items,
|
||||
[
|
||||
{ label: 'Title', map: viewItem => viewItem.getTitle() },
|
||||
{ label: 'Text', map: viewItem => viewItem.contentObject ? viewItem.contentObject.getCSVExportText() : '' },
|
||||
{
|
||||
label: 'Text',
|
||||
map: viewItem => (viewItem.contentObject ? viewItem.contentObject.getCSVExportText() : '')
|
||||
},
|
||||
{ label: 'Duration', property: 'duration' },
|
||||
{ label: 'Comment', property: 'comment' },
|
||||
{ label: 'Item type', property: 'verboseCsvType' }
|
||||
|
@ -1,16 +1,15 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { FilterListService, OsFilter, OsFilterOption } from "../../../core/services/filter-list.service";
|
||||
import { Item, itemVisibilityChoices } from "../../../shared/models/agenda/item";
|
||||
import { ViewItem } from "../models/view-item";
|
||||
import { StorageService } from "app/core/services/storage.service";
|
||||
import { AgendaRepositoryService } from "./agenda-repository.service";
|
||||
import { FilterListService, OsFilter, OsFilterOption } from '../../../core/services/filter-list.service';
|
||||
import { Item, itemVisibilityChoices } from '../../../shared/models/agenda/item';
|
||||
import { ViewItem } from '../models/view-item';
|
||||
import { StorageService } from 'app/core/services/storage.service';
|
||||
import { AgendaRepositoryService } from './agenda-repository.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AgendaFilterListService extends FilterListService<Item, ViewItem> {
|
||||
|
||||
protected name = 'Agenda';
|
||||
|
||||
public filterOptions: OsFilter[] = [];
|
||||
@ -22,22 +21,22 @@ export class AgendaFilterListService extends FilterListService<Item, ViewItem> {
|
||||
*/
|
||||
public constructor(store: StorageService, repo: AgendaRepositoryService) {
|
||||
super(store, repo);
|
||||
this.filterOptions = [{
|
||||
this.filterOptions = [
|
||||
{
|
||||
label: 'Visibility',
|
||||
property: 'type',
|
||||
options: this.createVisibilityFilterOptions()
|
||||
}, {
|
||||
},
|
||||
{
|
||||
label: 'Hidden Status',
|
||||
property: 'done',
|
||||
options: [
|
||||
{label: 'Open', condition: false},
|
||||
{label: 'Closed', condition: true}
|
||||
]
|
||||
}];
|
||||
options: [{ label: 'Open', condition: false }, { label: 'Closed', condition: true }]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
private createVisibilityFilterOptions(): OsFilterOption[] {
|
||||
const options = [];
|
||||
const options = [];
|
||||
itemVisibilityChoices.forEach(choice => {
|
||||
options.push({
|
||||
condition: choice.key as number,
|
||||
@ -46,6 +45,4 @@ export class AgendaFilterListService extends FilterListService<Item, ViewItem> {
|
||||
});
|
||||
return options;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ export class AgendaRepositoryService extends BaseRepository<ViewItem, Item> {
|
||||
* deleted (right now)
|
||||
*/
|
||||
public delete(item: ViewItem): Promise<void> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -196,7 +196,7 @@ export class AgendaRepositoryService extends BaseRepository<ViewItem, Item> {
|
||||
* Agenda items are created implicitly and do not have on create functions
|
||||
*/
|
||||
public async create(item: Item): Promise<Identifiable> {
|
||||
throw new Error("Method not implemented.");
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7,7 +7,8 @@ describe('TopicRepositoryService', () => {
|
||||
beforeEach(() =>
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule]
|
||||
}));
|
||||
})
|
||||
);
|
||||
|
||||
it('should be created', () => {
|
||||
const service: TopicRepositoryService = TestBed.get(TopicRepositoryService);
|
||||
|
@ -10,8 +10,6 @@ import { PromptService } from '../../../core/services/prompt.service';
|
||||
import { ViewAssignment } from '../models/view-assignment';
|
||||
import { AssignmentSortListService } from '../services/assignment-sort-list.service';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Listview for the assignments
|
||||
*
|
||||
@ -22,7 +20,6 @@ import { AssignmentSortListService } from '../services/assignment-sort-list.serv
|
||||
styleUrls: ['./assignment-list.component.scss']
|
||||
})
|
||||
export class AssignmentListComponent extends ListViewBaseComponent<ViewAssignment> implements OnInit {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param titleService
|
||||
|
@ -1,27 +1,27 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
|
||||
import { AssignmentRepositoryService } from "./assignment-repository.service";
|
||||
import { Assignment, assignmentPhase } from "../../../shared/models/assignments/assignment";
|
||||
import { FilterListService, OsFilter, OsFilterOption } from "../../../core/services/filter-list.service";
|
||||
import { StorageService } from "app/core/services/storage.service";
|
||||
import { ViewAssignment } from "../models/view-assignment";
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { AssignmentRepositoryService } from './assignment-repository.service';
|
||||
import { Assignment, assignmentPhase } from '../../../shared/models/assignments/assignment';
|
||||
import { FilterListService, OsFilter, OsFilterOption } from '../../../core/services/filter-list.service';
|
||||
import { StorageService } from 'app/core/services/storage.service';
|
||||
import { ViewAssignment } from '../models/view-assignment';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AssignmentFilterListService extends FilterListService<Assignment, ViewAssignment> {
|
||||
|
||||
protected name = 'Assignment';
|
||||
|
||||
public filterOptions: OsFilter[];
|
||||
|
||||
public constructor(store: StorageService, assignmentRepo: AssignmentRepositoryService) {
|
||||
super(store, assignmentRepo);
|
||||
this.filterOptions = [{
|
||||
property: 'phase',
|
||||
options: this.createPhaseOptions()
|
||||
}];
|
||||
this.filterOptions = [
|
||||
{
|
||||
property: 'phase',
|
||||
options: this.createPhaseOptions()
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
private createPhaseOptions(): OsFilterOption[] {
|
||||
|
@ -24,10 +24,7 @@ export class AssignmentRepositoryService extends BaseRepository<ViewAssignment,
|
||||
* @param DS The DataStore
|
||||
* @param mapperService Maps collection strings to classes
|
||||
*/
|
||||
public constructor(
|
||||
DS: DataStoreService,
|
||||
mapperService: CollectionStringModelMapperService
|
||||
) {
|
||||
public constructor(DS: DataStoreService, mapperService: CollectionStringModelMapperService) {
|
||||
super(DS, mapperService, Assignment, [User, Item, Tag]);
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,6 @@ import { ViewAssignment } from '../models/view-assignment';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AssignmentSortListService extends SortListService<ViewAssignment> {
|
||||
|
||||
public sortOptions: OsSortingDefinition<ViewAssignment> = {
|
||||
sortProperty: 'assignment',
|
||||
sortAscending: true,
|
||||
@ -18,5 +17,4 @@ export class AssignmentSortListService extends SortListService<ViewAssignment> {
|
||||
]
|
||||
};
|
||||
protected name = 'Assignment';
|
||||
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ export interface ModelEntry {
|
||||
|
||||
export interface SearchableModelEntry {
|
||||
collectionString: string;
|
||||
model: new (...args: any[]) => (BaseModel & Searchable);
|
||||
model: new (...args: any[]) => BaseModel & Searchable;
|
||||
searchOrder: number;
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
|
||||
protected DS: DataStoreService,
|
||||
protected collectionStringModelMapperService: CollectionStringModelMapperService,
|
||||
protected baseModelCtor: ModelConstructor<M>,
|
||||
protected depsModelCtors?: ModelConstructor<BaseModel>[],
|
||||
protected depsModelCtors?: ModelConstructor<BaseModel>[]
|
||||
) {
|
||||
super();
|
||||
this.setup();
|
||||
|
@ -80,7 +80,7 @@ export abstract class ListViewBaseComponent<V extends BaseViewModel> extends Bas
|
||||
this.sort.sort(newSort);
|
||||
}
|
||||
|
||||
public onFilterData(filteredDataSource: MatTableDataSource<V>) : void {
|
||||
public onFilterData(filteredDataSource: MatTableDataSource<V>): void {
|
||||
this.dataSource = filteredDataSource;
|
||||
this.dataSource.paginator = this.paginator;
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import { DataStoreService } from 'app/core/services/data-store.service';
|
||||
import { SearchService, SearchModel, SearchResult } from 'app/core/services/search.service';
|
||||
import { BaseViewComponent } from '../../../base/base-view';
|
||||
|
||||
type SearchModelEnabled = SearchModel & { enabled: boolean; };
|
||||
type SearchModelEnabled = SearchModel & { enabled: boolean };
|
||||
|
||||
/**
|
||||
* Component for the full search text.
|
||||
@ -78,16 +78,16 @@ export class SearchComponent extends BaseViewComponent implements OnInit {
|
||||
super(title, translate, matSnackBar);
|
||||
this.quickSearchform = new FormGroup({ query: new FormControl([]) });
|
||||
|
||||
this.registeredModels = this.searchService.getRegisteredModels().map(rm => ({...rm, enabled: true}));
|
||||
this.registeredModels = this.searchService.getRegisteredModels().map(rm => ({ ...rm, enabled: true }));
|
||||
|
||||
this.DS.changedOrDeletedObservable.pipe(auditTime(1)).subscribe(() => this.search());
|
||||
this.quickSearchSubject.pipe(debounceTime(250)).subscribe(query => this.search(query));
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the search query from the URL and does the initial search.
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
/**
|
||||
* Take the search query from the URL and does the initial search.
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
super.setTitle('Search');
|
||||
this.query = this.activatedRoute.snapshot.queryParams.query;
|
||||
this.quickSearchform.get('query').setValue(this.query);
|
||||
|
@ -4,9 +4,11 @@ import { DurationService } from './duration.service';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
describe('DurationService', () => {
|
||||
beforeEach(() => TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule]
|
||||
}));
|
||||
beforeEach(() =>
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule]
|
||||
})
|
||||
);
|
||||
|
||||
it('should be created', () => {
|
||||
const service: DurationService = TestBed.get(DurationService);
|
||||
|
@ -96,7 +96,7 @@ export class ViewHistory extends BaseViewModel {
|
||||
* @returns the CollectionString to the model
|
||||
*/
|
||||
public getCollectionString(): string {
|
||||
return this.element_id.split(":")[0]
|
||||
return this.element_id.split(':')[0];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,7 +104,7 @@ export class ViewHistory extends BaseViewModel {
|
||||
* @returns a model id
|
||||
*/
|
||||
public getModelID(): number {
|
||||
return +this.element_id.split(":")[1]
|
||||
return +this.element_id.split(':')[1];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -93,15 +93,18 @@ export class LoginMaskComponent extends BaseComponent implements OnInit, OnDestr
|
||||
// Get the login data. Save information to the login data service. If there is an
|
||||
// error, ignore it.
|
||||
// TODO: This has to be caught by the offline service
|
||||
this.http.get<any>(environment.urlPrefix + '/users/login/').then(response => {
|
||||
if (response.info_text) {
|
||||
this.installationNotice = this.matSnackBar.open(response.info_text, this.translate.instant('OK'), {
|
||||
duration: 5000
|
||||
});
|
||||
}
|
||||
this.loginDataService.setPrivacyPolicy(response.privacy_policy);
|
||||
this.loginDataService.setLegalNotice(response.legal_notice);
|
||||
}, () => {});
|
||||
this.http.get<any>(environment.urlPrefix + '/users/login/').then(
|
||||
response => {
|
||||
if (response.info_text) {
|
||||
this.installationNotice = this.matSnackBar.open(response.info_text, this.translate.instant('OK'), {
|
||||
duration: 5000
|
||||
});
|
||||
}
|
||||
this.loginDataService.setPrivacyPolicy(response.privacy_policy);
|
||||
this.loginDataService.setLegalNotice(response.legal_notice);
|
||||
},
|
||||
() => {}
|
||||
);
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
|
@ -15,11 +15,9 @@ describe('ResetPasswordConfirmComponent', () => {
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
providers: [
|
||||
{provide: MatSnackBar, useValue: spy}
|
||||
]
|
||||
providers: [{ provide: MatSnackBar, useValue: spy }]
|
||||
}).compileComponents();
|
||||
matSnackBarSpy = TestBed.get(MatSnackBar)
|
||||
matSnackBarSpy = TestBed.get(MatSnackBar);
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -10,7 +10,7 @@ describe('MediaUploadComponent', () => {
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
declarations: [MediaUploadComponent],
|
||||
declarations: [MediaUploadComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
|
@ -27,7 +27,7 @@ interface FileData {
|
||||
@Component({
|
||||
selector: 'os-media-upload',
|
||||
templateUrl: './media-upload.component.html',
|
||||
styleUrls: ['./media-upload.component.scss'],
|
||||
styleUrls: ['./media-upload.component.scss']
|
||||
})
|
||||
export class MediaUploadComponent extends BaseViewComponent implements OnInit {
|
||||
/**
|
||||
@ -168,7 +168,7 @@ export class MediaUploadComponent extends BaseViewComponent implements OnInit {
|
||||
filename: file.name,
|
||||
title: file.name,
|
||||
uploader_id: this.op.user.id,
|
||||
hidden: false,
|
||||
hidden: false
|
||||
};
|
||||
this.uploadList.data.push(newFile);
|
||||
|
||||
|
@ -26,7 +26,6 @@
|
||||
white-space: pre-line !important;
|
||||
}
|
||||
|
||||
|
||||
.edit-file-form {
|
||||
mat-form-field + mat-form-field {
|
||||
margin: 1em;
|
||||
|
@ -16,16 +16,13 @@ import { MediafileFilterListService } from '../../services/mediafile-filter.serv
|
||||
import { MediafilesSortListService } from '../../services/mediafiles-sort-list.service';
|
||||
import { ViewportService } from 'app/core/services/viewport.service';
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Lists all the uploaded files.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'os-mediafile-list',
|
||||
templateUrl: './mediafile-list.component.html',
|
||||
styleUrls: ['./mediafile-list.component.scss'],
|
||||
styleUrls: ['./mediafile-list.component.scss']
|
||||
})
|
||||
export class MediafileListComponent extends ListViewBaseComponent<ViewMediafile> implements OnInit {
|
||||
/**
|
||||
@ -106,7 +103,7 @@ export class MediafileListComponent extends ListViewBaseComponent<ViewMediafile>
|
||||
|
||||
this.fileEditForm = new FormGroup({
|
||||
title: new FormControl('', Validators.required),
|
||||
hidden: new FormControl(),
|
||||
hidden: new FormControl()
|
||||
});
|
||||
|
||||
this.filterService.filter().subscribe(filteredData => {
|
||||
@ -163,7 +160,7 @@ export class MediafileListComponent extends ListViewBaseComponent<ViewMediafile>
|
||||
}
|
||||
const updateData = new Mediafile({
|
||||
title: this.fileEditForm.value.title,
|
||||
hidden: this.fileEditForm.value.hidden,
|
||||
hidden: this.fileEditForm.value.hidden
|
||||
});
|
||||
|
||||
this.repo.update(updateData, this.fileToEdit).then(() => {
|
||||
@ -269,7 +266,7 @@ export class MediafileListComponent extends ListViewBaseComponent<ViewMediafile>
|
||||
*/
|
||||
public getColumnDefinition(): string[] {
|
||||
const columns = this.vp.isMobile ? this.displayedColumnsMobile : this.displayedColumnsDesktop;
|
||||
if (this.isMultiSelect){
|
||||
if (this.isMultiSelect) {
|
||||
return ['selector'].concat(columns);
|
||||
}
|
||||
return columns;
|
||||
|
@ -5,11 +5,11 @@ import { MediaUploadComponent } from './components/media-upload/media-upload.com
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', component: MediafileListComponent },
|
||||
{ path: 'upload', component: MediaUploadComponent },
|
||||
{ path: 'upload', component: MediaUploadComponent }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class MediafilesRoutingModule {}
|
||||
|
@ -122,5 +122,4 @@ export class ViewMediafile extends BaseViewModel {
|
||||
public is_hidden(): boolean {
|
||||
return this._mediafile.hidden;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import { ViewMediafile } from '../models/view-mediafile';
|
||||
* The structure of an image config object
|
||||
*/
|
||||
interface ImageConfigObject {
|
||||
display_name: string
|
||||
display_name: string;
|
||||
key: string;
|
||||
path: string;
|
||||
}
|
||||
@ -17,7 +17,7 @@ interface ImageConfigObject {
|
||||
* The structure of a font config
|
||||
*/
|
||||
interface FontConfigObject {
|
||||
display_name: string
|
||||
display_name: string;
|
||||
default: string;
|
||||
path: string;
|
||||
}
|
||||
@ -26,10 +26,10 @@ interface FontConfigObject {
|
||||
* Holds the required structure of the manage payload
|
||||
*/
|
||||
interface ManagementPayload {
|
||||
id: number,
|
||||
key?: string,
|
||||
default?: string,
|
||||
value: ImageConfigObject | FontConfigObject
|
||||
id: number;
|
||||
key?: string;
|
||||
default?: string;
|
||||
value: ImageConfigObject | FontConfigObject;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -38,7 +38,7 @@ interface ManagementPayload {
|
||||
* Declaring images as logos (web, projector, pdf, ...) is handles here.
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class MediaManageService {
|
||||
/**
|
||||
@ -61,7 +61,7 @@ export class MediaManageService {
|
||||
const restPath = `rest/core/config/${action}`;
|
||||
|
||||
const config = this.getMediaConfig(action);
|
||||
const path = (config.path !== file.downloadUrl) ? file.downloadUrl : '';
|
||||
const path = config.path !== file.downloadUrl ? file.downloadUrl : '';
|
||||
|
||||
// Create the payload that the server requires to manage a mediafile
|
||||
const payload: ManagementPayload = {
|
||||
@ -74,7 +74,7 @@ export class MediaManageService {
|
||||
default: (config as FontConfigObject).default,
|
||||
path: path
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return this.httpService.put<void>(restPath, payload);
|
||||
}
|
||||
|
@ -1,35 +1,36 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { FilterListService } from "../../../core/services/filter-list.service";
|
||||
import { Mediafile } from "../../../shared/models/mediafiles/mediafile";
|
||||
import { ViewMediafile } from "../models/view-mediafile";
|
||||
import { StorageService } from "app/core/services/storage.service";
|
||||
import { MediafileRepositoryService } from "./mediafile-repository.service";
|
||||
import { FilterListService } from '../../../core/services/filter-list.service';
|
||||
import { Mediafile } from '../../../shared/models/mediafiles/mediafile';
|
||||
import { ViewMediafile } from '../models/view-mediafile';
|
||||
import { StorageService } from 'app/core/services/storage.service';
|
||||
import { MediafileRepositoryService } from './mediafile-repository.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class MediafileFilterListService extends FilterListService<Mediafile, ViewMediafile> {
|
||||
|
||||
protected name = 'Mediafile';
|
||||
|
||||
public filterOptions = [{
|
||||
property: 'is_hidden', label: 'Hidden',
|
||||
options: [
|
||||
{ condition: true, label: 'is hidden' },
|
||||
{ condition: false, label: 'is not hidden', isActive: true }
|
||||
]
|
||||
}
|
||||
// , { TODO: is_pdf is not yet implemented on mediafile side
|
||||
// property: 'is_pdf', isActive: false, label: 'PDF',
|
||||
// options: [
|
||||
// {condition: true, label: 'is a PDF'},
|
||||
// {condition: false, label: 'is not a PDF'}
|
||||
// ]
|
||||
// }
|
||||
public filterOptions = [
|
||||
{
|
||||
property: 'is_hidden',
|
||||
label: 'Hidden',
|
||||
options: [
|
||||
{ condition: true, label: 'is hidden' },
|
||||
{ condition: false, label: 'is not hidden', isActive: true }
|
||||
]
|
||||
}
|
||||
// , { TODO: is_pdf is not yet implemented on mediafile side
|
||||
// property: 'is_pdf', isActive: false, label: 'PDF',
|
||||
// options: [
|
||||
// {condition: true, label: 'is a PDF'},
|
||||
// {condition: false, label: 'is not a PDF'}
|
||||
// ]
|
||||
// }
|
||||
];
|
||||
|
||||
public constructor(store: StorageService, repo: MediafileRepositoryService){
|
||||
public constructor(store: StorageService, repo: MediafileRepositoryService) {
|
||||
super(store, repo);
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import { HttpHeaders } from '@angular/common/http';
|
||||
* Repository for MediaFiles
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class MediafileRepositoryService extends BaseRepository<ViewMediafile, Mediafile> {
|
||||
/**
|
||||
@ -29,7 +29,7 @@ export class MediafileRepositoryService extends BaseRepository<ViewMediafile, Me
|
||||
DS: DataStoreService,
|
||||
mapperService: CollectionStringModelMapperService,
|
||||
private dataSend: DataSendService,
|
||||
private httpService: HttpService,
|
||||
private httpService: HttpService
|
||||
) {
|
||||
super(DS, mapperService, Mediafile, [User]);
|
||||
}
|
||||
|
@ -2,12 +2,10 @@ import { Injectable } from '@angular/core';
|
||||
import { SortListService, OsSortingDefinition } from '../../../core/services/sort-list.service';
|
||||
import { ViewMediafile } from '../models/view-mediafile';
|
||||
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class MediafilesSortListService extends SortListService<ViewMediafile> {
|
||||
|
||||
public sortOptions: OsSortingDefinition<ViewMediafile> = {
|
||||
sortProperty: 'title',
|
||||
sortAscending: true,
|
||||
|
@ -94,7 +94,7 @@ export class CategoryListComponent extends BaseViewComponent implements OnInit {
|
||||
* @param viewCategory
|
||||
*/
|
||||
public keyDownFunction(event: KeyboardEvent, viewCategory?: ViewCategory): void {
|
||||
if (event.key === "Enter") {
|
||||
if (event.key === 'Enter') {
|
||||
if (viewCategory) {
|
||||
this.onSaveButton(viewCategory);
|
||||
} else {
|
||||
|
@ -6,7 +6,6 @@ import { ViewChild, Component } from '@angular/core';
|
||||
import { ViewMotion } from '../../models/view-motion';
|
||||
|
||||
describe('ManageSubmittersComponent', () => {
|
||||
|
||||
@Component({
|
||||
selector: 'os-host-component',
|
||||
template: '<os-manage-submitters></os-manage-submitters>'
|
||||
|
@ -4,7 +4,7 @@
|
||||
font-size: 1em;
|
||||
}
|
||||
::ng-deep .mat-dialog-content {
|
||||
overflow: visible;
|
||||
overflow: visible;
|
||||
}
|
||||
.wide-form {
|
||||
textarea {
|
||||
|
@ -9,13 +9,14 @@ import { MotionDetailOriginalChangeRecommendationsComponent } from '../motion-de
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<os-motion-detail-diff
|
||||
[motion]="motion"
|
||||
[changes]="changes"
|
||||
(scrollToChange)="scrollToChange($event)"
|
||||
(createChangeRecommendation)="createChangeRecommendation($event)"
|
||||
>
|
||||
</os-motion-detail-diff>`
|
||||
<os-motion-detail-diff
|
||||
[motion]="motion"
|
||||
[changes]="changes"
|
||||
(scrollToChange)="scrollToChange($event)"
|
||||
(createChangeRecommendation)="createChangeRecommendation($event)"
|
||||
>
|
||||
</os-motion-detail-diff>
|
||||
`
|
||||
})
|
||||
class TestHostComponent {
|
||||
public motion: ViewMotion;
|
||||
|
@ -6,13 +6,14 @@ import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<os-motion-detail-original-change-recommendations
|
||||
[html]="html"
|
||||
[changeRecommendations]="changeRecommendations"
|
||||
(createChangeRecommendation)="createChangeRecommendation($event)"
|
||||
(gotoChangeRecommendation)="gotoChangeRecommendation($event)"
|
||||
>
|
||||
</os-motion-detail-original-change-recommendations>`
|
||||
<os-motion-detail-original-change-recommendations
|
||||
[html]="html"
|
||||
[changeRecommendations]="changeRecommendations"
|
||||
(createChangeRecommendation)="createChangeRecommendation($event)"
|
||||
(gotoChangeRecommendation)="gotoChangeRecommendation($event)"
|
||||
>
|
||||
</os-motion-detail-original-change-recommendations>
|
||||
`
|
||||
})
|
||||
class TestHostComponent {
|
||||
public html = '<p>Test123</p>';
|
||||
|
@ -21,7 +21,6 @@ import { ViewCategory } from '../../models/view-category';
|
||||
import { ViewMotionBlock } from '../../models/view-motion-block';
|
||||
import { WorkflowRepositoryService } from '../../services/workflow-repository.service';
|
||||
|
||||
|
||||
/**
|
||||
* Component that displays all the motions in a Table using DataSource.
|
||||
*/
|
||||
@ -31,7 +30,6 @@ import { WorkflowRepositoryService } from '../../services/workflow-repository.se
|
||||
styleUrls: ['./motion-list.component.scss']
|
||||
})
|
||||
export class MotionListComponent extends ListViewBaseComponent<ViewMotion> implements OnInit {
|
||||
|
||||
/**
|
||||
* Use for minimal width. Please note the 'selector' row for multiSelect mode,
|
||||
* to be able to display an indicator for the state of selection
|
||||
@ -52,7 +50,6 @@ export class MotionListComponent extends ListViewBaseComponent<ViewMotion> imple
|
||||
public statutesEnabled: boolean;
|
||||
public recomendationEnabled: boolean;
|
||||
|
||||
|
||||
public tags: ViewTag[] = [];
|
||||
public workflows: ViewWorkflow[] = [];
|
||||
public categories: ViewCategory[] = [];
|
||||
@ -112,11 +109,11 @@ export class MotionListComponent extends ListViewBaseComponent<ViewMotion> imple
|
||||
this.initTable();
|
||||
this.configService.get('motions_statutes_enabled').subscribe(enabled => (this.statutesEnabled = enabled));
|
||||
this.configService.get('motions_recommendations_by').subscribe(id => (this.recomendationEnabled = !!id));
|
||||
this.motionBlockRepo.getViewModelListObservable().subscribe(mBs => this.motionBlocks = mBs);
|
||||
this.categoryRepo.getViewModelListObservable().subscribe(cats => this.categories = cats);
|
||||
this.tagRepo.getViewModelListObservable().subscribe(tags => this.tags = tags);
|
||||
this.workflowRepo.getViewModelListObservable().subscribe(wfs => this.workflows = wfs);
|
||||
this.filterService.filter().subscribe(filteredData => this.sortService.data = filteredData);
|
||||
this.motionBlockRepo.getViewModelListObservable().subscribe(mBs => (this.motionBlocks = mBs));
|
||||
this.categoryRepo.getViewModelListObservable().subscribe(cats => (this.categories = cats));
|
||||
this.tagRepo.getViewModelListObservable().subscribe(tags => (this.tags = tags));
|
||||
this.workflowRepo.getViewModelListObservable().subscribe(wfs => (this.workflows = wfs));
|
||||
this.filterService.filter().subscribe(filteredData => (this.sortService.data = filteredData));
|
||||
this.sortService.sort().subscribe(sortedData => {
|
||||
this.dataSource.data = sortedData;
|
||||
this.checkSelection();
|
||||
@ -211,6 +208,4 @@ export class MotionListComponent extends ListViewBaseComponent<ViewMotion> imple
|
||||
this.raiseError(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -34,6 +34,6 @@ export class ViewMotionBlock extends BaseViewModel {
|
||||
}
|
||||
|
||||
public getTitle(): string {
|
||||
return this.title
|
||||
return this.title;
|
||||
}
|
||||
}
|
||||
|
@ -226,7 +226,7 @@ export class ViewMotion extends BaseViewModel {
|
||||
}
|
||||
|
||||
public get attachments_id(): number[] {
|
||||
return this.motion ? this.motion.attachments_id : null
|
||||
return this.motion ? this.motion.attachments_id : null;
|
||||
}
|
||||
|
||||
public get attachments(): Mediafile[] {
|
||||
|
@ -10,7 +10,6 @@ import { BaseViewModel } from '../../base/base-view-model';
|
||||
* @ignore
|
||||
*/
|
||||
export class ViewWorkflow extends BaseViewModel {
|
||||
|
||||
private _workflow: Workflow;
|
||||
|
||||
public constructor(workflow?: Workflow) {
|
||||
|
@ -935,15 +935,14 @@ describe('DiffService', () => {
|
||||
}
|
||||
));
|
||||
|
||||
it('works with multiple inserted paragraphs', inject(
|
||||
[DiffService],
|
||||
(service: DiffService) => {
|
||||
const before = '<p>This is the text before</p>',
|
||||
after = "<p>This is the text before</p>\n<p>This is one added line</p>\n<p>Another added line</p>";
|
||||
const diff = service.diff(before, after);
|
||||
expect(diff).toBe("<p>This is the text before</p>\n<p class=\"insert\">This is one added line</p>\n<p class=\"insert\">Another added line</p>");
|
||||
}
|
||||
));
|
||||
it('works with multiple inserted paragraphs', inject([DiffService], (service: DiffService) => {
|
||||
const before = '<p>This is the text before</p>',
|
||||
after = '<p>This is the text before</p>\n<p>This is one added line</p>\n<p>Another added line</p>';
|
||||
const diff = service.diff(before, after);
|
||||
expect(diff).toBe(
|
||||
'<p>This is the text before</p>\n<p class="insert">This is one added line</p>\n<p class="insert">Another added line</p>'
|
||||
);
|
||||
}));
|
||||
|
||||
it('does not a change in a very specific case', inject([DiffService], (service: DiffService) => {
|
||||
// See diff._fixWrongChangeDetection
|
||||
@ -965,17 +964,21 @@ describe('DiffService', () => {
|
||||
}));
|
||||
|
||||
it('does not delete a paragraph before an inserted one', inject([DiffService], (service: DiffService) => {
|
||||
const inHtml = '<ul class="os-split-before"><li>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</li>\n' +
|
||||
'</ul>',
|
||||
outHtml = '<ul class="os-split-before">\n' +
|
||||
const inHtml =
|
||||
'<ul class="os-split-before"><li>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</li>\n' +
|
||||
'</ul>',
|
||||
outHtml =
|
||||
'<ul class="os-split-before">\n' +
|
||||
'<li>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</li>\n' +
|
||||
'<li class="testclass">At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</li>\n' +
|
||||
'</ul>';
|
||||
const diff = service.diff(inHtml, outHtml);
|
||||
expect(diff).toBe('<ul class="os-split-before">' +
|
||||
'<li>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</li>' +
|
||||
'<li class="testclass insert">At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</li>' +
|
||||
'</ul>');
|
||||
expect(diff).toBe(
|
||||
'<ul class="os-split-before">' +
|
||||
'<li>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</li>' +
|
||||
'<li class="testclass insert">At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</li>' +
|
||||
'</ul>'
|
||||
);
|
||||
}));
|
||||
});
|
||||
|
||||
@ -1053,10 +1056,16 @@ describe('DiffService', () => {
|
||||
));
|
||||
|
||||
it('works with a replaced list item', inject([DiffService], (service: DiffService) => {
|
||||
const before = "<ul><li>Lorem ipsum <strong>dolor sit amet</strong>, consetetur sadipscing elitr, sed diam nonumy eirmod tempor.</li></ul>",
|
||||
after = "<ul>\n<li>\n<p>At vero eos et accusam et justo duo dolores et ea rebum.</p>\n</li>\n</ul>\n",
|
||||
expected = '<UL class="delete"><LI>' + noMarkup(1) + 'Lorem ipsum <STRONG>dolor sit amet</STRONG>, consetetur sadipscing elitr, sed diam nonumy ' + brMarkup(2) + 'eirmod tempor.</LI></UL>' +
|
||||
"<UL class=\"insert\">\n<LI>\n<P>At vero eos et accusam et justo duo dolores et ea rebum.</P>\n</LI>\n</UL>";
|
||||
const before =
|
||||
'<ul><li>Lorem ipsum <strong>dolor sit amet</strong>, consetetur sadipscing elitr, sed diam nonumy eirmod tempor.</li></ul>',
|
||||
after = '<ul>\n<li>\n<p>At vero eos et accusam et justo duo dolores et ea rebum.</p>\n</li>\n</ul>\n',
|
||||
expected =
|
||||
'<UL class="delete"><LI>' +
|
||||
noMarkup(1) +
|
||||
'Lorem ipsum <STRONG>dolor sit amet</STRONG>, consetetur sadipscing elitr, sed diam nonumy ' +
|
||||
brMarkup(2) +
|
||||
'eirmod tempor.</LI></UL>' +
|
||||
'<UL class="insert">\n<LI>\n<P>At vero eos et accusam et justo duo dolores et ea rebum.</P>\n</LI>\n</UL>';
|
||||
const diff = service.diff(before, after, 80, 1);
|
||||
const diffNormalized = service.normalizeHtmlForDiff(diff).toLowerCase();
|
||||
const expectedNormalized = service.normalizeHtmlForDiff(expected).toLowerCase();
|
||||
|
@ -491,12 +491,12 @@ describe('LinenumberingService', () => {
|
||||
expect(service.insertLineBreaksWithoutNumbers(outHtml, 80)).toBe(outHtml);
|
||||
}));
|
||||
|
||||
it('does not count within .insert nodes', inject(
|
||||
[LinenumberingService],
|
||||
(service: LinenumberingService) => {
|
||||
const inHtml = "<p>1234</p><ul class=\"insert\"><li>1234</li></ul><p>1234 1234</p>";
|
||||
it('does not count within .insert nodes', inject([LinenumberingService], (service: LinenumberingService) => {
|
||||
const inHtml = '<p>1234</p><ul class="insert"><li>1234</li></ul><p>1234 1234</p>';
|
||||
const outHtml = service.insertLineNumbers(inHtml, 10);
|
||||
expect(outHtml).toBe('<p>' + noMarkup(1) + '1234</p><ul class="insert"><li>1234</li></ul><p>' + noMarkup(2) + '1234 1234</p>');
|
||||
expect(outHtml).toBe(
|
||||
'<p>' + noMarkup(1) + '1234</p><ul class="insert"><li>1234</li></ul><p>' + noMarkup(2) + '1234 1234</p>'
|
||||
);
|
||||
expect(service.stripLineNumbers(outHtml)).toBe(inHtml);
|
||||
expect(service.insertLineBreaksWithoutNumbers(outHtml, 80)).toBe(outHtml);
|
||||
}));
|
||||
|
@ -4,10 +4,10 @@ import { LocalPermissionsService } from './local-permissions.service';
|
||||
import { E2EImportsModule } from '../../../../e2e-imports.module';
|
||||
|
||||
describe('LocalPermissionsService', () => {
|
||||
beforeEach(() => TestBed.configureTestingModule({ imports: [E2EImportsModule] }));
|
||||
beforeEach(() => TestBed.configureTestingModule({ imports: [E2EImportsModule] }));
|
||||
|
||||
it('should be created', () => {
|
||||
const service: LocalPermissionsService = TestBed.get(LocalPermissionsService);
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
it('should be created', () => {
|
||||
const service: LocalPermissionsService = TestBed.get(LocalPermissionsService);
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
@ -3,20 +3,17 @@ import { OperatorService } from '../../../core/services/operator.service';
|
||||
import { ViewMotion } from '../models/view-motion';
|
||||
import { ConfigService } from '../../../core/services/config.service';
|
||||
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class LocalPermissionsService {
|
||||
|
||||
public configMinSupporters: number;
|
||||
|
||||
public constructor(
|
||||
private operator: OperatorService,
|
||||
private configService: ConfigService,
|
||||
) {
|
||||
public constructor(private operator: OperatorService, private configService: ConfigService) {
|
||||
// load config variables
|
||||
this.configService.get('motions_min_supporters').subscribe(supporters => (this.configMinSupporters = supporters));
|
||||
this.configService
|
||||
.get('motions_min_supporters')
|
||||
.subscribe(supporters => (this.configMinSupporters = supporters));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -36,13 +33,11 @@ export class LocalPermissionsService {
|
||||
this.operator.hasPerms('motions.can_support') &&
|
||||
this.configMinSupporters > 0 &&
|
||||
motion.state.allow_support &&
|
||||
(motion.submitters.indexOf(this.operator.user) === -1) &&
|
||||
(motion.supporters.indexOf(this.operator.user) === -1));
|
||||
case 'unsupport':
|
||||
return (
|
||||
motion.state.allow_support &&
|
||||
(motion.supporters.indexOf(this.operator.user) !== -1)
|
||||
motion.submitters.indexOf(this.operator.user) === -1 &&
|
||||
motion.supporters.indexOf(this.operator.user) === -1
|
||||
);
|
||||
case 'unsupport':
|
||||
return motion.state.allow_support && motion.supporters.indexOf(this.operator.user) !== -1;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -4,9 +4,11 @@ import { MotionBlockRepositoryService } from './motion-block-repository.service'
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
describe('MotionBlockRepositoryService', () => {
|
||||
beforeEach(() => TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule]
|
||||
}));
|
||||
beforeEach(() =>
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule]
|
||||
})
|
||||
);
|
||||
|
||||
it('should be created', () => {
|
||||
const service: MotionBlockRepositoryService = TestBed.get(MotionBlockRepositoryService);
|
||||
|
@ -32,7 +32,7 @@ export class MotionBlockRepositoryService extends BaseRepository<ViewMotionBlock
|
||||
DS: DataStoreService,
|
||||
mapperService: CollectionStringModelMapperService,
|
||||
private dataSend: DataSendService,
|
||||
private motionRepo: MotionRepositoryService,
|
||||
private motionRepo: MotionRepositoryService
|
||||
) {
|
||||
super(DS, mapperService, MotionBlock);
|
||||
}
|
||||
|
@ -11,10 +11,7 @@ describe('MotionCsvExportService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject(
|
||||
[MotionCsvExportService],
|
||||
(service: MotionCsvExportService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}
|
||||
));
|
||||
it('should be created', inject([MotionCsvExportService], (service: MotionCsvExportService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
||||
|
@ -12,7 +12,6 @@ import { ViewMotion } from '../models/view-motion';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class MotionCsvExportService {
|
||||
|
||||
/**
|
||||
* Does nothing.
|
||||
*
|
||||
@ -51,11 +50,15 @@ export class MotionCsvExportService {
|
||||
this.csvExport.export(
|
||||
motions,
|
||||
[
|
||||
{ label: 'Called', map: motion => motion.sort_parent_id ? '' : motion.identifierOrTitle },
|
||||
{ label: 'Called with', map: motion => !motion.sort_parent_id ? '' : motion.identifierOrTitle },
|
||||
{ label: 'Called', map: motion => (motion.sort_parent_id ? '' : motion.identifierOrTitle) },
|
||||
{ label: 'Called with', map: motion => (!motion.sort_parent_id ? '' : motion.identifierOrTitle) },
|
||||
{ label: 'submitters', map: motion => motion.submitters.map(s => s.short_name).join(',') },
|
||||
{ property: 'title' },
|
||||
{ label: 'recommendation', map: motion => motion.recommendation ? this.translate.instant(motion.recommendation.recommendation_label) : '' },
|
||||
{
|
||||
label: 'recommendation',
|
||||
map: motion =>
|
||||
motion.recommendation ? this.translate.instant(motion.recommendation.recommendation_label) : ''
|
||||
},
|
||||
{ property: 'motion_block', label: 'Motion block' }
|
||||
],
|
||||
this.translate.instant('Call list') + '.csv'
|
||||
|
@ -1,31 +1,27 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { FilterListService, OsFilter } from "../../../core/services/filter-list.service";
|
||||
import { Motion } from "../../../shared/models/motions/motion";
|
||||
import { ViewMotion } from "../models/view-motion";
|
||||
import { CategoryRepositoryService } from "./category-repository.service";
|
||||
import { WorkflowRepositoryService } from "./workflow-repository.service";
|
||||
import { StorageService } from "../../../core/services/storage.service";
|
||||
import { MotionRepositoryService } from "./motion-repository.service";
|
||||
import { MotionBlockRepositoryService } from "./motion-block-repository.service";
|
||||
import { FilterListService, OsFilter } from '../../../core/services/filter-list.service';
|
||||
import { Motion } from '../../../shared/models/motions/motion';
|
||||
import { ViewMotion } from '../models/view-motion';
|
||||
import { CategoryRepositoryService } from './category-repository.service';
|
||||
import { WorkflowRepositoryService } from './workflow-repository.service';
|
||||
import { StorageService } from '../../../core/services/storage.service';
|
||||
import { MotionRepositoryService } from './motion-repository.service';
|
||||
import { MotionBlockRepositoryService } from './motion-block-repository.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class MotionFilterListService extends FilterListService<Motion, ViewMotion> {
|
||||
|
||||
protected name = 'Motion';
|
||||
/**
|
||||
* getter for the filterOptions. Note that in this case, the options are
|
||||
* generated dynamically, as the options change with the datastore
|
||||
*/
|
||||
public get filterOptions(): OsFilter[] {
|
||||
return [
|
||||
this.flowFilterOptions,
|
||||
this.categoryFilterOptions,
|
||||
this.motionBlockFilterOptions
|
||||
].concat(
|
||||
this.staticFilterOptions);
|
||||
return [this.flowFilterOptions, this.categoryFilterOptions, this.motionBlockFilterOptions].concat(
|
||||
this.staticFilterOptions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -54,28 +50,26 @@ export class MotionFilterListService extends FilterListService<Motion, ViewMotio
|
||||
label: 'Motion block',
|
||||
isActive: false,
|
||||
options: []
|
||||
}
|
||||
};
|
||||
public commentFilterOptions = {
|
||||
property: 'comment',
|
||||
isActive: false,
|
||||
options: []
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
public staticFilterOptions = [
|
||||
// TODO favorite (attached to user:whoamI!)
|
||||
// TODO personalNote (attached to user:whoamI!)
|
||||
];
|
||||
|
||||
public constructor(store: StorageService,
|
||||
public constructor(
|
||||
store: StorageService,
|
||||
private workflowRepo: WorkflowRepositoryService,
|
||||
private categoryRepo: CategoryRepositoryService,
|
||||
private motionBlockRepo: MotionBlockRepositoryService,
|
||||
// private commentRepo: MotionCommentRepositoryService
|
||||
motionRepo: MotionRepositoryService,
|
||||
|
||||
){
|
||||
motionRepo: MotionRepositoryService
|
||||
) {
|
||||
super(store, motionRepo);
|
||||
this.subscribeWorkflows();
|
||||
this.subscribeCategories();
|
||||
@ -125,11 +119,11 @@ export class MotionFilterListService extends FilterListService<Motion, ViewMotio
|
||||
workflows.forEach(workflow => {
|
||||
workflowOptions.push(workflow.name);
|
||||
workflow.states.forEach(state => {
|
||||
workflowOptions.push({
|
||||
condition: state.name,
|
||||
label: state.name,
|
||||
isActive: false
|
||||
});
|
||||
workflowOptions.push({
|
||||
condition: state.name,
|
||||
label: state.name,
|
||||
isActive: false
|
||||
});
|
||||
});
|
||||
});
|
||||
workflowOptions.push('-');
|
||||
|
@ -89,11 +89,10 @@ export class MotionMultiselectService {
|
||||
*/
|
||||
public async setStateOfMultiple(motions: ViewMotion[]): Promise<void> {
|
||||
const title = this.translate.instant('This will set the state of all selected motions to:');
|
||||
const choices = this.workflowRepo.getWorkflowStatesForMotions(motions)
|
||||
.map(workflowState => ({
|
||||
id: workflowState.id,
|
||||
label: workflowState.name
|
||||
}));
|
||||
const choices = this.workflowRepo.getWorkflowStatesForMotions(motions).map(workflowState => ({
|
||||
id: workflowState.id,
|
||||
label: workflowState.name
|
||||
}));
|
||||
const selectedChoice = await this.choiceService.open(title, choices);
|
||||
if (selectedChoice) {
|
||||
for (const motion of motions) {
|
||||
@ -117,12 +116,11 @@ export class MotionMultiselectService {
|
||||
label: workflowState.recommendation_label
|
||||
}));
|
||||
const clearChoice = 'Delete recommendation';
|
||||
const selectedChoice = await this.choiceService.open(title, choices, false,
|
||||
null, clearChoice);
|
||||
const selectedChoice = await this.choiceService.open(title, choices, false, null, clearChoice);
|
||||
if (selectedChoice) {
|
||||
const requestData = motions.map(motion => ({
|
||||
id: motion.id,
|
||||
recommendation: selectedChoice.action ? 0 : selectedChoice.items as number
|
||||
recommendation: selectedChoice.action ? 0 : (selectedChoice.items as number)
|
||||
}));
|
||||
await this.httpService.post('/rest/motions/motion/manage_multiple_recommendation', {
|
||||
motions: requestData
|
||||
@ -138,13 +136,19 @@ export class MotionMultiselectService {
|
||||
public async setCategory(motions: ViewMotion[]): Promise<void> {
|
||||
const title = this.translate.instant('This will set the category of all selected motions to:');
|
||||
const clearChoice = 'No category';
|
||||
const selectedChoice = await this.choiceService.open(title, this.categoryRepo.getViewModelList(),
|
||||
false, null, clearChoice);
|
||||
const selectedChoice = await this.choiceService.open(
|
||||
title,
|
||||
this.categoryRepo.getViewModelList(),
|
||||
false,
|
||||
null,
|
||||
clearChoice
|
||||
);
|
||||
if (selectedChoice) {
|
||||
for (const motion of motions) {
|
||||
await this.repo.update(
|
||||
{category_id: selectedChoice.action ? 0 : selectedChoice.items as number },
|
||||
motion);
|
||||
{ category_id: selectedChoice.action ? 0 : (selectedChoice.items as number) },
|
||||
motion
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -155,10 +159,11 @@ export class MotionMultiselectService {
|
||||
* @param motions The motions to add/remove the sumbitters to
|
||||
*/
|
||||
public async changeSubmitters(motions: ViewMotion[]): Promise<void> {
|
||||
const title = this.translate.instant('This will add or remove the following submitters for all selected motions:');
|
||||
const title = this.translate.instant(
|
||||
'This will add or remove the following submitters for all selected motions:'
|
||||
);
|
||||
const choices = ['Add', 'Remove'];
|
||||
const selectedChoice = await this.choiceService.open(title,
|
||||
this.userRepo.getViewModelList(), true, choices);
|
||||
const selectedChoice = await this.choiceService.open(title, this.userRepo.getViewModelList(), true, choices);
|
||||
if (selectedChoice && selectedChoice.action === choices[0]) {
|
||||
const requestData = motions.map(motion => {
|
||||
let submitterIds = [...motion.submitters_id, ...(selectedChoice.items as number[])];
|
||||
@ -190,8 +195,7 @@ export class MotionMultiselectService {
|
||||
public async changeTags(motions: ViewMotion[]): Promise<void> {
|
||||
const title = this.translate.instant('This will add or remove the following tags for all selected motions:');
|
||||
const choices = ['Add', 'Remove', 'Clear tags'];
|
||||
const selectedChoice = await this.choiceService.open(title, this.tagRepo.getViewModelList(), true,
|
||||
choices);
|
||||
const selectedChoice = await this.choiceService.open(title, this.tagRepo.getViewModelList(), true, choices);
|
||||
if (selectedChoice && selectedChoice.action === choices[0]) {
|
||||
const requestData = motions.map(motion => {
|
||||
let tagIds = [...motion.tags_id, ...(selectedChoice.items as number[])];
|
||||
@ -223,7 +227,6 @@ export class MotionMultiselectService {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Opens a dialog and changes the motionBlock for all given motions.
|
||||
*
|
||||
@ -232,12 +235,17 @@ export class MotionMultiselectService {
|
||||
public async setMotionBlock(motions: ViewMotion[]): Promise<void> {
|
||||
const title = this.translate.instant('This will change the motion Block for all selected motions:');
|
||||
const clearChoice = 'Clear motion block';
|
||||
const selectedChoice = await this.choiceService.open(title, this.motionBlockRepo.getViewModelList(),
|
||||
false, null, clearChoice);
|
||||
const selectedChoice = await this.choiceService.open(
|
||||
title,
|
||||
this.motionBlockRepo.getViewModelList(),
|
||||
false,
|
||||
null,
|
||||
clearChoice
|
||||
);
|
||||
if (selectedChoice) {
|
||||
for (const motion of motions) {
|
||||
const blockId = selectedChoice.action ? null : selectedChoice.items as number;
|
||||
await this.repo.update({motion_block_id: blockId}, motion);
|
||||
const blockId = selectedChoice.action ? null : (selectedChoice.items as number);
|
||||
await this.repo.update({ motion_block_id: blockId }, motion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ import { ViewMotionAmendedParagraph } from '../models/view-motion-amended-paragr
|
||||
import { CreateMotion } from '../models/create-motion';
|
||||
import { MotionBlock } from 'app/shared/models/motions/motion-block';
|
||||
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
|
||||
import { ConfigService } from "../../../core/services/config.service";
|
||||
import { ConfigService } from '../../../core/services/config.service';
|
||||
|
||||
/**
|
||||
* Repository Services for motions (and potentially categories)
|
||||
@ -44,7 +44,6 @@ import { ConfigService } from "../../../core/services/config.service";
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion> {
|
||||
|
||||
// The line length; comes from the config variable motions_line_length
|
||||
private lineLength = 90;
|
||||
|
||||
@ -81,9 +80,9 @@ export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion>
|
||||
super(DS, mapperService, Motion, [Category, User, Workflow, Item, MotionBlock, Mediafile]);
|
||||
|
||||
// load config variables
|
||||
this.configService.get('motions_line_length').subscribe(lineLength => this.lineLength = lineLength);
|
||||
this.configService.get('motions_default_line_numbering').subscribe(mode => this.defaultLineNumbering = mode);
|
||||
this.configService.get('motions_recommendation_text_mode').subscribe(mode => this.defaultCrMode = mode);
|
||||
this.configService.get('motions_line_length').subscribe(lineLength => (this.lineLength = lineLength));
|
||||
this.configService.get('motions_default_line_numbering').subscribe(mode => (this.defaultLineNumbering = mode));
|
||||
this.configService.get('motions_recommendation_text_mode').subscribe(mode => (this.defaultCrMode = mode));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,7 +105,20 @@ export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion>
|
||||
if (workflow) {
|
||||
state = workflow.getStateById(motion.state_id);
|
||||
}
|
||||
return new ViewMotion(motion, category, submitters, supporters, workflow, state, item, block, attachments, this.lineLength, this.defaultLineNumbering, this.defaultCrMode);
|
||||
return new ViewMotion(
|
||||
motion,
|
||||
category,
|
||||
submitters,
|
||||
supporters,
|
||||
workflow,
|
||||
state,
|
||||
item,
|
||||
block,
|
||||
attachments,
|
||||
this.lineLength,
|
||||
this.defaultLineNumbering,
|
||||
this.defaultCrMode
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -220,10 +232,12 @@ export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion>
|
||||
*/
|
||||
public async setSubmitters(viewMotion: ViewMotion, submitters: User[]): Promise<void> {
|
||||
const requestData = {
|
||||
motions: [{
|
||||
id: viewMotion.id,
|
||||
submitters: submitters.map(s => s.id),
|
||||
}]
|
||||
motions: [
|
||||
{
|
||||
id: viewMotion.id,
|
||||
submitters: submitters.map(s => s.id)
|
||||
}
|
||||
]
|
||||
};
|
||||
this.httpService.post('/rest/motions/motion/manage_multiple_submitters/', requestData);
|
||||
}
|
||||
|
@ -79,12 +79,13 @@ export class WorkflowRepositoryService extends BaseRepository<ViewWorkflow, Work
|
||||
*/
|
||||
public getWorkflowStatesForMotions(motions: ViewMotion[]): WorkflowState[] {
|
||||
let states: WorkflowState[] = [];
|
||||
const workflowIds = motions.map(motion => motion.workflow_id).filter((value, index, self) => self.indexOf(value) === index);
|
||||
const workflowIds = motions
|
||||
.map(motion => motion.workflow_id)
|
||||
.filter((value, index, self) => self.indexOf(value) === index);
|
||||
workflowIds.forEach(id => {
|
||||
const workflow = this.getViewModel(id);
|
||||
states = states.concat(workflow.states);
|
||||
});
|
||||
return states;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,6 @@ const routes: Routes = [
|
||||
path: 'history',
|
||||
loadChildren: './history/history.module#HistoryModule'
|
||||
}
|
||||
|
||||
],
|
||||
canActivateChild: [AuthGuard]
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ export class TagListComponent extends ListViewBaseComponent<ViewTag> implements
|
||||
if (event.key === 'Enter' && event.shiftKey) {
|
||||
this.submitNewTag();
|
||||
}
|
||||
if (event.key === "Escape") {
|
||||
if (event.key === 'Escape') {
|
||||
this.cancelEditing();
|
||||
}
|
||||
}
|
||||
|
@ -198,7 +198,7 @@ export class GroupListComponent extends BaseViewComponent implements OnInit {
|
||||
* Clicking escape while in #newGroupForm should toggle newGroup.
|
||||
*/
|
||||
public keyDownFunction(event: KeyboardEvent): void {
|
||||
if (event.key === "Escape") {
|
||||
if (event.key === 'Escape') {
|
||||
this.newGroup = false;
|
||||
}
|
||||
}
|
||||
|
@ -261,5 +261,4 @@ export class PasswordComponent extends BaseViewComponent implements OnInit {
|
||||
this.hide_user_password = !this.hide_user_password;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -321,7 +321,9 @@ export class UserDetailComponent extends BaseViewComponent implements OnInit {
|
||||
* click on the delete user button
|
||||
*/
|
||||
public async deleteUserButton(): Promise<void> {
|
||||
const content = this.translate.instant('Do you want to delete this participant?') + `<p><strong>${this.user.full_name}</strong>`;
|
||||
const content =
|
||||
this.translate.instant('Do you want to delete this participant?') +
|
||||
`<p><strong>${this.user.full_name}</strong>`;
|
||||
if (await this.promptService.open(this.translate.instant('Are you sure?'), content)) {
|
||||
this.repo.delete(this.user).then(() => this.router.navigate(['./users/']), this.raiseError);
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ import { UserSortListService } from '../../services/user-sort-list.service';
|
||||
styleUrls: ['./user-list.component.scss']
|
||||
})
|
||||
export class UserListComponent extends ListViewBaseComponent<ViewUser> implements OnInit {
|
||||
|
||||
/**
|
||||
* /**
|
||||
* The usual constructor for components
|
||||
@ -71,10 +70,9 @@ export class UserListComponent extends ListViewBaseComponent<ViewUser> implement
|
||||
super.setTitle('Users');
|
||||
this.initTable();
|
||||
|
||||
|
||||
this.filterService.filter().subscribe(filteredData => {
|
||||
this.sortService.data = filteredData;
|
||||
});
|
||||
this.sortService.data = filteredData;
|
||||
});
|
||||
this.sortService.sort().subscribe(sortedData => {
|
||||
this.dataSource.data = sortedData;
|
||||
this.checkSelection();
|
||||
@ -148,8 +146,7 @@ export class UserListComponent extends ListViewBaseComponent<ViewUser> implement
|
||||
public async setGroupSelected(): Promise<void> {
|
||||
const content = this.translate.instant('This will add or remove the following groups for all selected users:');
|
||||
const choices = ['Add group(s)', 'Remove group(s)'];
|
||||
const selectedChoice = await this.choiceService.open(content,
|
||||
this.groupRepo.getViewModelList(), true, choices);
|
||||
const selectedChoice = await this.choiceService.open(content, this.groupRepo.getViewModelList(), true, choices);
|
||||
if (selectedChoice) {
|
||||
for (const user of this.selectedRows) {
|
||||
const newGroups = [...user.groups_id];
|
||||
@ -187,7 +184,7 @@ export class UserListComponent extends ListViewBaseComponent<ViewUser> implement
|
||||
* Uses selectedRows defined via multiSelect mode.
|
||||
*/
|
||||
public async setPresentSelected(): Promise<void> {
|
||||
const content = this.translate.instant('Set the presence status for the selected users');
|
||||
const content = this.translate.instant('Set the presence status for the selected users');
|
||||
const options = ['Present', 'Not present'];
|
||||
const selectedChoice = await this.choiceService.open(content, null, false, options);
|
||||
if (selectedChoice) {
|
||||
@ -203,8 +200,7 @@ export class UserListComponent extends ListViewBaseComponent<ViewUser> implement
|
||||
* Uses selectedRows defined via multiSelect mode.
|
||||
*/
|
||||
public async setCommitteeSelected(): Promise<void> {
|
||||
const content = this.translate.instant(
|
||||
'Sets/unsets the committee status for the selected users');
|
||||
const content = this.translate.instant('Sets/unsets the committee status for the selected users');
|
||||
const options = ['Is committee', 'Is not committee'];
|
||||
const selectedChoice = await this.choiceService.open(content, null, false, options);
|
||||
if (selectedChoice) {
|
||||
@ -254,7 +250,5 @@ export class UserListComponent extends ListViewBaseComponent<ViewUser> implement
|
||||
public async setPresent(viewUser: ViewUser): Promise<void> {
|
||||
viewUser.user.is_present = !viewUser.user.is_present;
|
||||
await this.repo.update(viewUser.user, viewUser);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ export class ViewUser extends BaseViewModel {
|
||||
}
|
||||
|
||||
public get is_last_email_send(): boolean {
|
||||
if (this.user && this.user.last_email_send){
|
||||
if (this.user && this.user.last_email_send) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -105,7 +105,6 @@ export class ViewUser extends BaseViewModel {
|
||||
this._groups = groups;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* required by BaseViewModel. Don't confuse with the users title.
|
||||
*/
|
||||
|
@ -8,7 +8,8 @@ describe('GroupRepositoryService', () => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
providers: [GroupRepositoryService]
|
||||
}));
|
||||
})
|
||||
);
|
||||
|
||||
it('should be created', inject([GroupRepositoryService], (service: GroupRepositoryService) => {
|
||||
expect(service).toBeTruthy();
|
||||
|
@ -1,17 +1,16 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { FilterListService, OsFilter } from "../../../core/services/filter-list.service";
|
||||
import { StorageService } from "../../../core/services/storage.service";
|
||||
import { User } from "../../../shared/models/users/user";
|
||||
import { ViewUser } from "../models/view-user";
|
||||
import { GroupRepositoryService } from "./group-repository.service";
|
||||
import { UserRepositoryService } from "./user-repository.service";
|
||||
import { FilterListService, OsFilter } from '../../../core/services/filter-list.service';
|
||||
import { StorageService } from '../../../core/services/storage.service';
|
||||
import { User } from '../../../shared/models/users/user';
|
||||
import { ViewUser } from '../models/view-user';
|
||||
import { GroupRepositoryService } from './group-repository.service';
|
||||
import { UserRepositoryService } from './user-repository.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class UserFilterListService extends FilterListService<User, ViewUser> {
|
||||
|
||||
protected name = 'User';
|
||||
|
||||
private userGroupFilterOptions = {
|
||||
@ -26,30 +25,25 @@ export class UserFilterListService extends FilterListService<User, ViewUser> {
|
||||
property: 'is_present',
|
||||
label: 'Presence',
|
||||
isActive: false,
|
||||
options: [
|
||||
{ condition: true, label: 'Is present'},
|
||||
{ condition: false, label: 'Is not present'}]
|
||||
}, {
|
||||
options: [{ condition: true, label: 'Is present' }, { condition: false, label: 'Is not present' }]
|
||||
},
|
||||
{
|
||||
property: 'is_active',
|
||||
label: 'Active',
|
||||
isActive: false,
|
||||
options: [
|
||||
{ condition: true, label: 'Is active' },
|
||||
{ condition: false, label: 'Is not active' }]
|
||||
}, {
|
||||
options: [{ condition: true, label: 'Is active' }, { condition: false, label: 'Is not active' }]
|
||||
},
|
||||
{
|
||||
property: 'is_committee',
|
||||
label: 'Committee',
|
||||
isActive: false,
|
||||
options: [
|
||||
{ condition: true, label: 'Is a committee' },
|
||||
{ condition: false, label: 'Is not a committee'}]
|
||||
}, {
|
||||
options: [{ condition: true, label: 'Is a committee' }, { condition: false, label: 'Is not a committee' }]
|
||||
},
|
||||
{
|
||||
property: 'is_last_email_send',
|
||||
label: 'Last email send',
|
||||
isActive: false,
|
||||
options: [
|
||||
{ condition: true, label: 'Got an email' },
|
||||
{ condition: false, label: 'Didn\'t get an email' }]
|
||||
options: [{ condition: true, label: 'Got an email' }, { condition: false, label: "Didn't get an email" }]
|
||||
}
|
||||
];
|
||||
|
||||
@ -61,8 +55,7 @@ export class UserFilterListService extends FilterListService<User, ViewUser> {
|
||||
return [this.userGroupFilterOptions].concat(this.staticFilterOptions);
|
||||
}
|
||||
|
||||
public constructor(store: StorageService, private groupRepo: GroupRepositoryService,
|
||||
repo: UserRepositoryService){
|
||||
public constructor(store: StorageService, private groupRepo: GroupRepositoryService, repo: UserRepositoryService) {
|
||||
super(store, repo);
|
||||
this.subscribeGroups();
|
||||
}
|
||||
@ -79,6 +72,6 @@ export class UserFilterListService extends FilterListService<User, ViewUser> {
|
||||
});
|
||||
this.userGroupFilterOptions.options = groupOptions;
|
||||
this.updateFilterDefinitions(this.filterOptions);
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ export class UserRepositoryService extends BaseRepository<ViewUser, User> {
|
||||
public async resetPassword(user: ViewUser, password: string): Promise<void> {
|
||||
const path = `/rest/users/user/${user.id}/reset_password/`;
|
||||
await this.httpService.post(path, { password: password });
|
||||
await this.update({default_password: password}, user);
|
||||
await this.update({ default_password: password }, user);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -131,8 +131,8 @@ export class UserRepositoryService extends BaseRepository<ViewUser, User> {
|
||||
*/
|
||||
public async setNewPassword(oldPassword: string, newPassword: string): Promise<void> {
|
||||
await this.httpService.post(`${environment.urlPrefix}/users/setpassword/`, {
|
||||
old_password: oldPassword,
|
||||
new_password: newPassword
|
||||
old_password: oldPassword,
|
||||
new_password: newPassword
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,6 @@ import { ViewUser } from '../models/view-user';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class UserSortListService extends SortListService<ViewUser> {
|
||||
|
||||
public sortOptions: OsSortingDefinition<ViewUser> = {
|
||||
sortProperty: 'first_name',
|
||||
sortAscending: true,
|
||||
|
Loading…
Reference in New Issue
Block a user