mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-03-19 21:22:31 +00:00
refactor: remove lodash
This commit is contained in:
@@ -38,6 +38,7 @@
|
|||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"unicorn/filename-case": "error",
|
"unicorn/filename-case": "error",
|
||||||
|
"unicorn/no-array-reduce": "off",
|
||||||
"unicorn/no-array-callback-reference": "off",
|
"unicorn/no-array-callback-reference": "off",
|
||||||
"unicorn/no-await-expression-member": "off",
|
"unicorn/no-await-expression-member": "off",
|
||||||
"unicorn/prefer-object-from-entries": "off",
|
"unicorn/prefer-object-from-entries": "off",
|
||||||
|
|||||||
84
package-lock.json
generated
84
package-lock.json
generated
@@ -3880,6 +3880,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@polka/url": {
|
||||||
|
"version": "1.0.0-next.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz",
|
||||||
|
"integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g=="
|
||||||
|
},
|
||||||
"@schematics/angular": {
|
"@schematics/angular": {
|
||||||
"version": "12.2.16",
|
"version": "12.2.16",
|
||||||
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-12.2.16.tgz",
|
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-12.2.16.tgz",
|
||||||
@@ -4403,21 +4408,6 @@
|
|||||||
"@types/leaflet": "*"
|
"@types/leaflet": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/lodash": {
|
|
||||||
"version": "4.14.179",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.179.tgz",
|
|
||||||
"integrity": "sha512-uwc1x90yCKqGcIOAT6DwOSuxnrAbpkdPsUOZtwrXb4D/6wZs+6qG7QnIawDuZWg0sWpxl+ltIKCaLoMlna678w==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"@types/lodash-es": {
|
|
||||||
"version": "4.17.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.6.tgz",
|
|
||||||
"integrity": "sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"@types/lodash": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@types/marked": {
|
"@types/marked": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/marked/-/marked-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/marked/-/marked-2.0.5.tgz",
|
||||||
@@ -8442,8 +8432,7 @@
|
|||||||
"duplexer": {
|
"duplexer": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
|
||||||
"integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
|
"integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"duplexer2": {
|
"duplexer2": {
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
@@ -10451,6 +10440,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/guid-typescript/-/guid-typescript-1.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/guid-typescript/-/guid-typescript-1.0.9.tgz",
|
||||||
"integrity": "sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ=="
|
"integrity": "sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ=="
|
||||||
},
|
},
|
||||||
|
"gzip-size": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==",
|
||||||
|
"requires": {
|
||||||
|
"duplexer": "^0.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"handle-thing": {
|
"handle-thing": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
|
||||||
@@ -12681,11 +12678,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
},
|
},
|
||||||
"lodash-es": {
|
|
||||||
"version": "4.17.21",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
|
||||||
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
|
|
||||||
},
|
|
||||||
"lodash._baseassign": {
|
"lodash._baseassign": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz",
|
||||||
@@ -13479,6 +13471,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mrmime": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ=="
|
||||||
|
},
|
||||||
"ms": {
|
"ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
@@ -18037,6 +18034,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"sirv": {
|
||||||
|
"version": "1.0.19",
|
||||||
|
"resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz",
|
||||||
|
"integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==",
|
||||||
|
"requires": {
|
||||||
|
"@polka/url": "^1.0.0-next.20",
|
||||||
|
"mrmime": "^1.0.0",
|
||||||
|
"totalist": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"sisteransi": {
|
"sisteransi": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||||
@@ -19495,6 +19502,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
|
||||||
"integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA="
|
"integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA="
|
||||||
},
|
},
|
||||||
|
"totalist": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g=="
|
||||||
|
},
|
||||||
"tough-cookie": {
|
"tough-cookie": {
|
||||||
"version": "2.5.0",
|
"version": "2.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
|
||||||
@@ -20319,6 +20331,34 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"webpack-bundle-analyzer": {
|
||||||
|
"version": "4.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz",
|
||||||
|
"integrity": "sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ==",
|
||||||
|
"requires": {
|
||||||
|
"acorn": "^8.0.4",
|
||||||
|
"acorn-walk": "^8.0.0",
|
||||||
|
"chalk": "^4.1.0",
|
||||||
|
"commander": "^7.2.0",
|
||||||
|
"gzip-size": "^6.0.0",
|
||||||
|
"lodash": "^4.17.20",
|
||||||
|
"opener": "^1.5.2",
|
||||||
|
"sirv": "^1.0.7",
|
||||||
|
"ws": "^7.3.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"commander": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="
|
||||||
|
},
|
||||||
|
"ws": {
|
||||||
|
"version": "7.5.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz",
|
||||||
|
"integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"webpack-dev-middleware": {
|
"webpack-dev-middleware": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.0.0.tgz",
|
||||||
|
|||||||
@@ -95,7 +95,7 @@
|
|||||||
"jsonpath-plus": "6.0.1",
|
"jsonpath-plus": "6.0.1",
|
||||||
"leaflet": "1.7.1",
|
"leaflet": "1.7.1",
|
||||||
"leaflet.markercluster": "1.5.3",
|
"leaflet.markercluster": "1.5.3",
|
||||||
"lodash-es": "4.17.21",
|
"webpack-bundle-analyzer": "4.5.0",
|
||||||
"moment": "2.29.1",
|
"moment": "2.29.1",
|
||||||
"ngx-logger": "4.3.3",
|
"ngx-logger": "4.3.3",
|
||||||
"ngx-markdown": "12.0.1",
|
"ngx-markdown": "12.0.1",
|
||||||
@@ -134,7 +134,6 @@
|
|||||||
"@types/jasminewd2": "2.0.10",
|
"@types/jasminewd2": "2.0.10",
|
||||||
"@types/leaflet": "1.7.9",
|
"@types/leaflet": "1.7.9",
|
||||||
"@types/leaflet.markercluster": "1.4.6",
|
"@types/leaflet.markercluster": "1.4.6",
|
||||||
"@types/lodash-es": "4.17.6",
|
|
||||||
"@types/node": "14.18.12",
|
"@types/node": "14.18.12",
|
||||||
"@types/qs": "6.9.7",
|
"@types/qs": "6.9.7",
|
||||||
"@typescript-eslint/eslint-plugin": "5.13.0",
|
"@typescript-eslint/eslint-plugin": "5.13.0",
|
||||||
|
|||||||
27
src/app/_helpers/collections/chunk.spec.ts
Normal file
27
src/app/_helpers/collections/chunk.spec.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {chunk} from './chunk';
|
||||||
|
|
||||||
|
describe('chunk', function () {
|
||||||
|
it('should chunk items in the correct sizes', function () {
|
||||||
|
expect(chunk([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3)).toEqual([
|
||||||
|
[1, 2, 3],
|
||||||
|
[4, 5, 6],
|
||||||
|
[7, 8, 9],
|
||||||
|
[10],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
28
src/app/_helpers/collections/chunk.ts
Normal file
28
src/app/_helpers/collections/chunk.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chunk array into smaller arrays of a specified size.
|
||||||
|
*
|
||||||
|
* @param array The array to chunk.
|
||||||
|
* @param chunkSize The size of each chunk.
|
||||||
|
*/
|
||||||
|
export function chunk<T>(array: T[], chunkSize = 1): T[][] {
|
||||||
|
const arrayCopy = [...array];
|
||||||
|
const out: T[][] = [];
|
||||||
|
if (chunkSize <= 0) return out;
|
||||||
|
while (arrayCopy.length > 0) out.push(arrayCopy.splice(0, chunkSize));
|
||||||
|
return out;
|
||||||
|
}
|
||||||
39
src/app/_helpers/collections/get.spec.ts
Normal file
39
src/app/_helpers/collections/get.spec.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
import {get} from './get';
|
||||||
|
|
||||||
|
describe('get', function () {
|
||||||
|
it('should get a simple path', function () {
|
||||||
|
const object = {
|
||||||
|
a: {
|
||||||
|
b: {
|
||||||
|
c: 'd',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(get(object, 'a.b.c')).toBe('d');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return undefined for a non-existent path', function () {
|
||||||
|
const object = {
|
||||||
|
a: {
|
||||||
|
b: {
|
||||||
|
c: 'd',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(get(object, 'a.b.c.d')).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
30
src/app/_helpers/collections/get.ts
Normal file
30
src/app/_helpers/collections/get.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a value from a nested object.
|
||||||
|
* The path must be key names separated by dots.
|
||||||
|
* If the path doesn't exist, undefined is returned.
|
||||||
|
*/
|
||||||
|
export function get<U = unknown>(object: object, path: string): U {
|
||||||
|
return path.split('.').reduce(
|
||||||
|
(accumulator, current) =>
|
||||||
|
accumulator?.hasOwnProperty(current)
|
||||||
|
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
(accumulator as any)[current]
|
||||||
|
: undefined,
|
||||||
|
object,
|
||||||
|
) as unknown as U;
|
||||||
|
}
|
||||||
100
src/app/_helpers/collections/group-by.spec.ts
Normal file
100
src/app/_helpers/collections/group-by.spec.ts
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {groupBy, groupByProperty} from './group-by';
|
||||||
|
|
||||||
|
describe('groupBy', () => {
|
||||||
|
it('should group an array by a key', () => {
|
||||||
|
const array = [
|
||||||
|
{id: 1, name: 'one'},
|
||||||
|
{id: 2, name: 'two'},
|
||||||
|
{id: 3, name: 'three'},
|
||||||
|
{id: 4, name: 'four'},
|
||||||
|
{id: 5, name: 'five'},
|
||||||
|
];
|
||||||
|
|
||||||
|
const result = groupBy(array, it => it.name);
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
one: [{id: 1, name: 'one'}],
|
||||||
|
two: [{id: 2, name: 'two'}],
|
||||||
|
three: [{id: 3, name: 'three'}],
|
||||||
|
four: [{id: 4, name: 'four'}],
|
||||||
|
five: [{id: 5, name: 'five'}],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle multiple elements per group', () => {
|
||||||
|
const array = [
|
||||||
|
{id: 1, name: 'one'},
|
||||||
|
{id: 2, name: 'two'},
|
||||||
|
{id: 3, name: 'three'},
|
||||||
|
{id: 4, name: 'four'},
|
||||||
|
{id: 5, name: 'five'},
|
||||||
|
{id: 6, name: 'one'},
|
||||||
|
{id: 7, name: 'two'},
|
||||||
|
{id: 8, name: 'three'},
|
||||||
|
{id: 9, name: 'four'},
|
||||||
|
{id: 10, name: 'five'},
|
||||||
|
];
|
||||||
|
|
||||||
|
const result = groupBy(array, it => it.name);
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
one: [
|
||||||
|
{id: 1, name: 'one'},
|
||||||
|
{id: 6, name: 'one'},
|
||||||
|
],
|
||||||
|
two: [
|
||||||
|
{id: 2, name: 'two'},
|
||||||
|
{id: 7, name: 'two'},
|
||||||
|
],
|
||||||
|
three: [
|
||||||
|
{id: 3, name: 'three'},
|
||||||
|
{id: 8, name: 'three'},
|
||||||
|
],
|
||||||
|
four: [
|
||||||
|
{id: 4, name: 'four'},
|
||||||
|
{id: 9, name: 'four'},
|
||||||
|
],
|
||||||
|
five: [
|
||||||
|
{id: 5, name: 'five'},
|
||||||
|
{id: 10, name: 'five'},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('groupByProperty', function () {
|
||||||
|
it('should group by property', () => {
|
||||||
|
const array = [
|
||||||
|
{id: 1, name: 'one'},
|
||||||
|
{id: 2, name: 'two'},
|
||||||
|
{id: 3, name: 'three'},
|
||||||
|
{id: 4, name: 'four'},
|
||||||
|
{id: 5, name: 'five'},
|
||||||
|
];
|
||||||
|
|
||||||
|
const result = groupByProperty(array, 'name');
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
one: [{id: 1, name: 'one'}],
|
||||||
|
two: [{id: 2, name: 'two'}],
|
||||||
|
three: [{id: 3, name: 'three'}],
|
||||||
|
four: [{id: 4, name: 'four'}],
|
||||||
|
five: [{id: 5, name: 'five'}],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
39
src/app/_helpers/collections/group-by.ts
Normal file
39
src/app/_helpers/collections/group-by.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Group an array by a function
|
||||||
|
*/
|
||||||
|
export function groupBy<T>(
|
||||||
|
collection: T[],
|
||||||
|
group: (item: T) => string | undefined,
|
||||||
|
): Record<string, T[]> {
|
||||||
|
return collection.reduce((accumulator: Record<string, T[]>, item) => {
|
||||||
|
const key = group(item) || '';
|
||||||
|
accumulator[key] = accumulator[key] ?? [];
|
||||||
|
accumulator[key].push(item);
|
||||||
|
return accumulator;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export function groupByProperty<T extends object>(
|
||||||
|
collection: T[],
|
||||||
|
property: keyof T,
|
||||||
|
): Record<string, T[]> {
|
||||||
|
return groupBy(collection, item => item[property] as unknown as string);
|
||||||
|
}
|
||||||
41
src/app/_helpers/collections/key-by.spec.ts
Normal file
41
src/app/_helpers/collections/key-by.spec.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
import {keyBy} from './key-by';
|
||||||
|
|
||||||
|
describe('keyBy', function () {
|
||||||
|
it('should key objects', function () {
|
||||||
|
const objects = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'foo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'bar',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const result = keyBy(objects, it => it.id);
|
||||||
|
expect(result).toEqual({
|
||||||
|
1: {
|
||||||
|
id: 1,
|
||||||
|
name: 'foo',
|
||||||
|
},
|
||||||
|
2: {
|
||||||
|
id: 2,
|
||||||
|
name: 'bar',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
30
src/app/_helpers/collections/key-by.ts
Normal file
30
src/app/_helpers/collections/key-by.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an object composed of keys generated from the results of running
|
||||||
|
* each element of collection thru iteratee. The corresponding value of
|
||||||
|
* each key is the last element responsible for generating the key. The
|
||||||
|
* iteratee is invoked with one argument: (value).
|
||||||
|
*/
|
||||||
|
export function keyBy<T>(
|
||||||
|
collection: T[],
|
||||||
|
key: (item: T) => string | number,
|
||||||
|
): Record<string, T> {
|
||||||
|
return collection.reduce((accumulator, item) => {
|
||||||
|
accumulator[key(item)] = item;
|
||||||
|
return accumulator;
|
||||||
|
}, {} as Record<string | number, T>);
|
||||||
|
}
|
||||||
50
src/app/_helpers/collections/map-values.spec.ts
Normal file
50
src/app/_helpers/collections/map-values.spec.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {mapValues} from './map-values';
|
||||||
|
|
||||||
|
describe('map-values', () => {
|
||||||
|
it('should map values', () => {
|
||||||
|
const object = {
|
||||||
|
a: 1,
|
||||||
|
b: 2,
|
||||||
|
c: 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = mapValues(object, value => value * 2);
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
a: 2,
|
||||||
|
b: 4,
|
||||||
|
c: 6,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not modify the original object', () => {
|
||||||
|
const object = {
|
||||||
|
a: 1,
|
||||||
|
b: 2,
|
||||||
|
c: 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
mapValues(object, value => value * 2);
|
||||||
|
|
||||||
|
expect(object).toEqual({
|
||||||
|
a: 1,
|
||||||
|
b: 2,
|
||||||
|
c: 3,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
32
src/app/_helpers/collections/map-values.ts
Normal file
32
src/app/_helpers/collections/map-values.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps the values of an object to a new object
|
||||||
|
*/
|
||||||
|
export function mapValues<T extends object, U>(
|
||||||
|
object: T,
|
||||||
|
transform: (value: T[keyof T], key: keyof T) => U,
|
||||||
|
): {[key in keyof T]: U} {
|
||||||
|
const result = {} as {[key in keyof T]: U};
|
||||||
|
|
||||||
|
for (const key in object) {
|
||||||
|
if (object.hasOwnProperty(key)) {
|
||||||
|
result[key] = transform(object[key], key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
44
src/app/_helpers/collections/min.spec.ts
Normal file
44
src/app/_helpers/collections/min.spec.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {minBy} from './min';
|
||||||
|
|
||||||
|
describe('minBy', function () {
|
||||||
|
it('should pick the minimum value based on transform', function () {
|
||||||
|
expect(
|
||||||
|
minBy(
|
||||||
|
[
|
||||||
|
{id: 1, name: 'A'},
|
||||||
|
{id: 2, name: 'B'},
|
||||||
|
{id: 3, name: 'C'},
|
||||||
|
],
|
||||||
|
it => it.id,
|
||||||
|
),
|
||||||
|
).toEqual({id: 1, name: 'A'});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not return undefined if there are other choices', function () {
|
||||||
|
expect(
|
||||||
|
minBy(
|
||||||
|
[
|
||||||
|
{id: undefined, name: 'B'},
|
||||||
|
{id: 1, name: 'A'},
|
||||||
|
{id: undefined, name: 'C'},
|
||||||
|
],
|
||||||
|
it => it.id,
|
||||||
|
),
|
||||||
|
).toEqual({id: 1, name: 'A'});
|
||||||
|
});
|
||||||
|
});
|
||||||
26
src/app/_helpers/collections/min.ts
Normal file
26
src/app/_helpers/collections/min.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the minimum value of a collection.
|
||||||
|
*/
|
||||||
|
export function minBy<T>(
|
||||||
|
array: T[],
|
||||||
|
transform: (item: T) => number | undefined,
|
||||||
|
): T {
|
||||||
|
const transforms = array.map(transform);
|
||||||
|
const min = Math.min(...(transforms.filter(it => !!it) as number[]));
|
||||||
|
return array.find((_, i) => transforms[i] === min) as T;
|
||||||
|
}
|
||||||
23
src/app/_helpers/collections/omit.spec.ts
Normal file
23
src/app/_helpers/collections/omit.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
import {omit} from './omit';
|
||||||
|
|
||||||
|
describe('omit', function () {
|
||||||
|
it('should omit keys', function () {
|
||||||
|
const object = {a: 1, b: 2, c: 3};
|
||||||
|
const result = omit(object, 'a', 'c');
|
||||||
|
expect(result).toEqual({b: 2});
|
||||||
|
});
|
||||||
|
});
|
||||||
26
src/app/_helpers/collections/omit.ts
Normal file
26
src/app/_helpers/collections/omit.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new object without the specified keys.
|
||||||
|
*/
|
||||||
|
export function omit<T extends object, U extends keyof T>(
|
||||||
|
object: T,
|
||||||
|
...keys: U[]
|
||||||
|
): Omit<T, U> {
|
||||||
|
const out = {...object};
|
||||||
|
for (const key of keys) delete out[key];
|
||||||
|
return out as Exclude<T, U>;
|
||||||
|
}
|
||||||
25
src/app/_helpers/collections/partition.spec.ts
Normal file
25
src/app/_helpers/collections/partition.spec.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {partition} from './partition';
|
||||||
|
|
||||||
|
describe('partition', function () {
|
||||||
|
it('should partition an array', function () {
|
||||||
|
expect(partition([1, 2, 3, 4], it => it % 2 === 0)).toEqual([
|
||||||
|
[2, 4],
|
||||||
|
[1, 3],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
31
src/app/_helpers/collections/partition.ts
Normal file
31
src/app/_helpers/collections/partition.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Partitions a list into two lists. One with the elements that satisfy a predicate,
|
||||||
|
* and one with the elements that don't satisfy the predicate.
|
||||||
|
*/
|
||||||
|
export function partition<T>(
|
||||||
|
array: T[],
|
||||||
|
transform: (item: T) => boolean,
|
||||||
|
): [T[], T[]] {
|
||||||
|
return array.reduce<[T[], T[]]>(
|
||||||
|
(accumulator, item) => {
|
||||||
|
accumulator[transform(item) ? 0 : 1].push(item);
|
||||||
|
return accumulator;
|
||||||
|
},
|
||||||
|
[[], []],
|
||||||
|
);
|
||||||
|
}
|
||||||
23
src/app/_helpers/collections/pick.spec.ts
Normal file
23
src/app/_helpers/collections/pick.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
import {pick} from './pick';
|
||||||
|
|
||||||
|
describe('pick', function () {
|
||||||
|
it('should pick properties', function () {
|
||||||
|
const object = {a: 1, b: 2, c: 3};
|
||||||
|
const result = pick(object, ['a', 'c']);
|
||||||
|
expect(result).toEqual({a: 1, c: 3});
|
||||||
|
});
|
||||||
|
});
|
||||||
29
src/app/_helpers/collections/pick.ts
Normal file
29
src/app/_helpers/collections/pick.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pick a set of properties from an object
|
||||||
|
*/
|
||||||
|
export function pick<T extends object, U extends keyof T>(
|
||||||
|
object: T,
|
||||||
|
keys: U[],
|
||||||
|
): Pick<T, U> {
|
||||||
|
return keys.reduce((accumulator, key) => {
|
||||||
|
if (object.hasOwnProperty(key)) {
|
||||||
|
accumulator[key] = object[key];
|
||||||
|
}
|
||||||
|
return accumulator;
|
||||||
|
}, {} as Pick<T, U>);
|
||||||
|
}
|
||||||
30
src/app/_helpers/collections/shuffle.spec.ts
Normal file
30
src/app/_helpers/collections/shuffle.spec.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
import {shuffle} from './shuffle';
|
||||||
|
|
||||||
|
describe('shuffle', function () {
|
||||||
|
it('should shuffle an array', function () {
|
||||||
|
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||||
|
const shuffled = shuffle(array);
|
||||||
|
expect(shuffled).not.toEqual(array);
|
||||||
|
expect(shuffled).toEqual(jasmine.arrayContaining(array));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not modify the original array', function () {
|
||||||
|
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||||
|
shuffle(array);
|
||||||
|
expect(array).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
|
||||||
|
});
|
||||||
|
});
|
||||||
28
src/app/_helpers/collections/shuffle.ts
Normal file
28
src/app/_helpers/collections/shuffle.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shuffles an array
|
||||||
|
*/
|
||||||
|
export function shuffle<T>(array: T[]): T[] {
|
||||||
|
const copy = [...array];
|
||||||
|
const out = [];
|
||||||
|
|
||||||
|
while (copy.length > 0) {
|
||||||
|
out.push(copy.splice(Math.floor(Math.random() * copy.length), 1)[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
32
src/app/_helpers/collections/string-sort.spec.ts
Normal file
32
src/app/_helpers/collections/string-sort.spec.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {stringSort, stringSortBy} from './string-sort';
|
||||||
|
|
||||||
|
describe('stringSort', () => {
|
||||||
|
it('should sort an array of strings', () => {
|
||||||
|
expect(['a', 'c', 'b', 'd'].sort(stringSort)).toEqual(['a', 'b', 'c', 'd']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('stringSortBy', () => {
|
||||||
|
it('should sort an array of strings', () => {
|
||||||
|
expect(
|
||||||
|
[{item: 'a'}, {item: 'c'}, {item: 'b'}, {item: 'd'}].sort(
|
||||||
|
stringSortBy(it => it.item),
|
||||||
|
),
|
||||||
|
).toEqual([{item: 'a'}, {item: 'b'}, {item: 'c'}, {item: 'd'}]);
|
||||||
|
});
|
||||||
|
});
|
||||||
38
src/app/_helpers/collections/string-sort.ts
Normal file
38
src/app/_helpers/collections/string-sort.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sort function for two strings
|
||||||
|
*/
|
||||||
|
export function stringSort(a = '', b = ''): number {
|
||||||
|
if (a < b) return -1;
|
||||||
|
if (a > b) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sort function for two strings that allows for a custom transform
|
||||||
|
*/
|
||||||
|
export function stringSortBy<T>(
|
||||||
|
map: (item: T) => string | undefined,
|
||||||
|
): (a: T, b: T) => number {
|
||||||
|
return (a: T, b: T): number => {
|
||||||
|
const aValue = map(a) || '';
|
||||||
|
const bValue = map(b) || '';
|
||||||
|
if (aValue < bValue) return -1;
|
||||||
|
if (aValue > bValue) return 1;
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
31
src/app/_helpers/collections/sum.spec.ts
Normal file
31
src/app/_helpers/collections/sum.spec.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
import {sum, sumBy} from './sum';
|
||||||
|
|
||||||
|
describe('sum', () => {
|
||||||
|
it('should return the sum of all elements in the collection', () => {
|
||||||
|
const collection = [1, 2, 3, 4, 5];
|
||||||
|
const result = sum(collection);
|
||||||
|
expect(result).toBe(15);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('sumBy', function () {
|
||||||
|
it('should return the sum of all elements in the collection', () => {
|
||||||
|
const collection = [{a: 1}, {a: 2}, {a: 3}, {a: 4}, {a: 5}];
|
||||||
|
const result = sumBy(collection, it => it.a);
|
||||||
|
expect(result).toBe(15);
|
||||||
|
});
|
||||||
|
});
|
||||||
37
src/app/_helpers/collections/sum.ts
Normal file
37
src/app/_helpers/collections/sum.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sum an an array
|
||||||
|
*/
|
||||||
|
export function sumBy<T extends object>(
|
||||||
|
collection: T[],
|
||||||
|
transform: (value: T) => number | undefined,
|
||||||
|
): number {
|
||||||
|
return collection.reduce(
|
||||||
|
(accumulator, item) => accumulator + (transform(item) || 0),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sum an array of numbers
|
||||||
|
*/
|
||||||
|
export function sum(collection: Array<number | undefined>): number {
|
||||||
|
return collection.reduce<number>(
|
||||||
|
(accumulator, item) => accumulator + (item || 0),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
}
|
||||||
25
src/app/_helpers/collections/zip.spec.ts
Normal file
25
src/app/_helpers/collections/zip.spec.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
import {zip} from './zip';
|
||||||
|
|
||||||
|
describe('zip', function () {
|
||||||
|
it('should zip arrays together', function () {
|
||||||
|
expect(zip([1, 2, 3], [4, 5, 6])).toEqual([
|
||||||
|
[1, 4],
|
||||||
|
[2, 5],
|
||||||
|
[3, 6],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
21
src/app/_helpers/collections/zip.ts
Normal file
21
src/app/_helpers/collections/zip.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zip two arrays together.
|
||||||
|
*/
|
||||||
|
export function zip<T, U>(a: T[], b: U[]): [T, U][] {
|
||||||
|
return a.map((_, i) => [a[i], b[i]]);
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2021 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -13,7 +13,6 @@
|
|||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import {Component, OnInit} from '@angular/core';
|
import {Component, OnInit} from '@angular/core';
|
||||||
import {map} from 'lodash-es';
|
|
||||||
import {ModalController} from '@ionic/angular';
|
import {ModalController} from '@ionic/angular';
|
||||||
import {AboutLicenseModalComponent} from './about-license-modal.component';
|
import {AboutLicenseModalComponent} from './about-license-modal.component';
|
||||||
import licensesFile from 'src/assets/about/licenses.json';
|
import licensesFile from 'src/assets/about/licenses.json';
|
||||||
@@ -59,9 +58,7 @@ export class AboutLicensesComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loadLicenses(): License[] {
|
loadLicenses(): License[] {
|
||||||
return map(
|
return Object.values(licensesFile as Record<string, object>).map(
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
||||||
licensesFile as Record<string, object>,
|
|
||||||
(value, key) =>
|
(value, key) =>
|
||||||
({
|
({
|
||||||
name: key,
|
name: key,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licens for
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
* more details.
|
* more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
@@ -14,7 +14,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Component, ViewChild} from '@angular/core';
|
import {Component, ViewChild} from '@angular/core';
|
||||||
import {flatMap} from 'lodash-es';
|
|
||||||
import {ActivatedRoute} from '@angular/router';
|
import {ActivatedRoute} from '@angular/router';
|
||||||
import {AssessmentsProvider} from '../assessments.provider';
|
import {AssessmentsProvider} from '../assessments.provider';
|
||||||
import {
|
import {
|
||||||
@@ -48,14 +47,16 @@ export class AssessmentsDetailComponent implements ViewWillEnter {
|
|||||||
event.resolve(
|
event.resolve(
|
||||||
assessment
|
assessment
|
||||||
? assessment
|
? assessment
|
||||||
: flatMap(assessments, it =>
|
: assessments
|
||||||
|
.flatMap(it =>
|
||||||
Array.isArray(it.superAssessments)
|
Array.isArray(it.superAssessments)
|
||||||
? it.superAssessments.map(superAssessment => ({
|
? it.superAssessments.map(superAssessment => ({
|
||||||
...superAssessment,
|
...superAssessment,
|
||||||
origin: it.origin,
|
origin: it.origin,
|
||||||
}))
|
}))
|
||||||
: [],
|
: [],
|
||||||
).find(it => it?.uid === event.uid),
|
)
|
||||||
|
.find(it => it?.uid === event.uid),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licens for
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
* more details.
|
* more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
@@ -22,7 +22,6 @@ import {
|
|||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import {AssessmentsProvider} from '../assessments.provider';
|
import {AssessmentsProvider} from '../assessments.provider';
|
||||||
import {SCAssessment, SCCourseOfStudy} from '@openstapps/core';
|
import {SCAssessment, SCCourseOfStudy} from '@openstapps/core';
|
||||||
import {groupBy, mapValues} from 'lodash-es';
|
|
||||||
import {ActivatedRoute, Router} from '@angular/router';
|
import {ActivatedRoute, Router} from '@angular/router';
|
||||||
import {Subscription} from 'rxjs';
|
import {Subscription} from 'rxjs';
|
||||||
import {NGXLogger} from 'ngx-logger';
|
import {NGXLogger} from 'ngx-logger';
|
||||||
@@ -30,6 +29,8 @@ import {materialSharedAxisX} from '../../../animation/material-motion';
|
|||||||
import {SharedAxisChoreographer} from '../../../animation/animation-choreographer';
|
import {SharedAxisChoreographer} from '../../../animation/animation-choreographer';
|
||||||
import {DataProvider, DataScope} from '../../data/data.provider';
|
import {DataProvider, DataScope} from '../../data/data.provider';
|
||||||
import {DataRoutingService} from '../../data/data-routing.service';
|
import {DataRoutingService} from '../../data/data-routing.service';
|
||||||
|
import {groupBy} from '../../../_helpers/collections/group-by';
|
||||||
|
import {mapValues} from '../../../_helpers/collections/map-values';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-assessments-page',
|
selector: 'app-assessments-page',
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licens for
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
* more details.
|
* more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
import {Component, Input} from '@angular/core';
|
import {Component, Input} from '@angular/core';
|
||||||
import {SCAssessment, SCCourseOfStudyWithoutReferences} from '@openstapps/core';
|
import {SCAssessment, SCCourseOfStudyWithoutReferences} from '@openstapps/core';
|
||||||
import {sum, sumBy} from 'lodash-es';
|
import {sum, sumBy} from '../../../../_helpers/collections/sum';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'course-of-study-assessment',
|
selector: 'course-of-study-assessment',
|
||||||
@@ -40,6 +40,6 @@ export class CourseOfStudyAssessmentComponent {
|
|||||||
.map(assessment => Number(assessment.grade))
|
.map(assessment => Number(assessment.grade))
|
||||||
.filter(grade => !Number.isNaN(grade));
|
.filter(grade => !Number.isNaN(grade));
|
||||||
this.grade = grades.length > 0 ? sum(grades) / grades.length : 0;
|
this.grade = grades.length > 0 ? sum(grades) / grades.length : 0;
|
||||||
this.ects = sumBy(this._assessments, 'ects');
|
this.ects = sumBy(this._assessments, it => it.ects);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2021 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licens for
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
* more details.
|
* more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
@@ -27,7 +27,6 @@ import {DateFormatPipe, DurationPipe} from 'ngx-moment';
|
|||||||
import {BackgroundFetch} from '@transistorsoft/capacitor-background-fetch';
|
import {BackgroundFetch} from '@transistorsoft/capacitor-background-fetch';
|
||||||
import {StorageProvider} from '../../storage/storage.provider';
|
import {StorageProvider} from '../../storage/storage.provider';
|
||||||
import {CalendarService} from '../../calendar/calendar.service';
|
import {CalendarService} from '../../calendar/calendar.service';
|
||||||
import {flatMap} from 'lodash-es';
|
|
||||||
import {toICal} from '../../calendar/ical/ical';
|
import {toICal} from '../../calendar/ical/ical';
|
||||||
import {Subscription} from 'rxjs';
|
import {Subscription} from 'rxjs';
|
||||||
import {ChangesOf} from './changes';
|
import {ChangesOf} from './changes';
|
||||||
@@ -173,7 +172,7 @@ export class ScheduleSyncService implements OnDestroy {
|
|||||||
const dateSeries = (await this.scheduleProvider.getDateSeries(this.uuids))
|
const dateSeries = (await this.scheduleProvider.getDateSeries(this.uuids))
|
||||||
.dates;
|
.dates;
|
||||||
|
|
||||||
const events = flatMap(dateSeries, event =>
|
const events = dateSeries.flatMap(event =>
|
||||||
toICal(event, this.translator.translator, {
|
toICal(event, this.translator.translator, {
|
||||||
allowRRuleExceptions: false,
|
allowRRuleExceptions: false,
|
||||||
excludeCancelledEvents: true,
|
excludeCancelledEvents: true,
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2021 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licens for
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
* more details.
|
* more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
@@ -15,8 +15,8 @@
|
|||||||
|
|
||||||
import {findRRules, RRule} from './ical';
|
import {findRRules, RRule} from './ical';
|
||||||
import moment, {unitOfTime} from 'moment';
|
import moment, {unitOfTime} from 'moment';
|
||||||
import {shuffle} from 'lodash-es';
|
|
||||||
import {SCISO8601Date} from '@openstapps/core';
|
import {SCISO8601Date} from '@openstapps/core';
|
||||||
|
import {shuffle} from '../../../_helpers/collections/shuffle';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2021 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licens for
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
* more details.
|
* more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
@@ -20,16 +20,9 @@ import {
|
|||||||
SCThingWithCategories,
|
SCThingWithCategories,
|
||||||
SCUuid,
|
SCUuid,
|
||||||
} from '@openstapps/core';
|
} from '@openstapps/core';
|
||||||
import {
|
|
||||||
difference,
|
|
||||||
flatMap,
|
|
||||||
isObject,
|
|
||||||
last,
|
|
||||||
mapValues,
|
|
||||||
minBy,
|
|
||||||
size,
|
|
||||||
} from 'lodash-es';
|
|
||||||
import moment, {unitOfTime} from 'moment';
|
import moment, {unitOfTime} from 'moment';
|
||||||
|
import {minBy} from '../../../_helpers/collections/min';
|
||||||
|
import {mapValues} from '../../../_helpers/collections/map-values';
|
||||||
|
|
||||||
export interface ICalEvent {
|
export interface ICalEvent {
|
||||||
name?: string;
|
name?: string;
|
||||||
@@ -126,7 +119,7 @@ export function findRRules(
|
|||||||
for (let i = 0; i < sorted.length; i++) {
|
for (let i = 0; i < sorted.length; i++) {
|
||||||
const current = sorted[i];
|
const current = sorted[i];
|
||||||
const next = sorted[i + 1] as SCISO8601Date | undefined;
|
const next = sorted[i + 1] as SCISO8601Date | undefined;
|
||||||
const element = last(output);
|
const element = output[output.length - 1];
|
||||||
|
|
||||||
const units: unitOfTime.Diff[] = element?.freq
|
const units: unitOfTime.Diff[] = element?.freq
|
||||||
? [element.freq]
|
? [element.freq]
|
||||||
@@ -208,8 +201,9 @@ export function toICal(
|
|||||||
options: ToICalOptions = {},
|
options: ToICalOptions = {},
|
||||||
): ICalEvent[] {
|
): ICalEvent[] {
|
||||||
const rrules = findRRules(
|
const rrules = findRRules(
|
||||||
options.excludeCancelledEvents
|
options.excludeCancelledEvents && dateSeries.exceptions
|
||||||
? difference(dateSeries.dates, dateSeries.exceptions ?? [])
|
? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
dateSeries.dates.filter(it => !dateSeries.exceptions!.includes(it))
|
||||||
: dateSeries.dates,
|
: dateSeries.dates,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -276,8 +270,9 @@ function stringifyLinebreaks<T extends string | unknown[] | unknown>(
|
|||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
return value.map(stringifyLinebreaks) as T;
|
return value.map(stringifyLinebreaks) as T;
|
||||||
}
|
}
|
||||||
if (isObject(value)) {
|
// noinspection SuspiciousTypeOfGuard
|
||||||
return mapValues(value, stringifyLinebreaks) as T;
|
if (value instanceof Object) {
|
||||||
|
return mapValues<object, unknown>(value, stringifyLinebreaks) as T;
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@@ -348,7 +343,7 @@ export function serializeICalEvent(iCal: ICalEvent): ICalLike {
|
|||||||
`STATUS:${normalized.cancelled === true ? 'CANCELLED' : 'CONFIRMED'}`,
|
`STATUS:${normalized.cancelled === true ? 'CANCELLED' : 'CONFIRMED'}`,
|
||||||
`URL:${normalized.url}`,
|
`URL:${normalized.url}`,
|
||||||
// `RDATE;VALUE=DATE:${normalized.dates.join(',')}`,
|
// `RDATE;VALUE=DATE:${normalized.dates.join(',')}`,
|
||||||
size(normalized.exceptionDates) > 0
|
(normalized.exceptionDates?.length ?? 0) > 0
|
||||||
? `EXDATE;VALUE=DATE:${normalized.exceptionDates?.join(',')}`
|
? `EXDATE;VALUE=DATE:${normalized.exceptionDates?.join(',')}`
|
||||||
: undefined,
|
: undefined,
|
||||||
`RRULE:${serializeRRule(normalized.rrule)}`,
|
`RRULE:${serializeRRule(normalized.rrule)}`,
|
||||||
@@ -372,7 +367,7 @@ export function serializeICal(iCal: ICalEvent[]): string {
|
|||||||
'CALSCALE:GREGORIAN',
|
'CALSCALE:GREGORIAN',
|
||||||
'COLOR:#FF0000',
|
'COLOR:#FF0000',
|
||||||
'METHOD:PUBLISH',
|
'METHOD:PUBLISH',
|
||||||
...flatMap(iCal, serializeICalEvent),
|
...iCal.flatMap(serializeICalEvent),
|
||||||
'END:VCALENDAR',
|
'END:VCALENDAR',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -384,7 +379,7 @@ export function getNativeCalendarExport(
|
|||||||
dateSeries: SCDateSeries[],
|
dateSeries: SCDateSeries[],
|
||||||
translator: SCThingTranslator,
|
translator: SCThingTranslator,
|
||||||
): ICalEvent[] {
|
): ICalEvent[] {
|
||||||
return flatMap(dateSeries, event =>
|
return dateSeries.flatMap(event =>
|
||||||
toICal(event, translator, {
|
toICal(event, translator, {
|
||||||
allowRRuleExceptions: false,
|
allowRRuleExceptions: false,
|
||||||
excludeCancelledEvents: true,
|
excludeCancelledEvents: true,
|
||||||
@@ -401,14 +396,14 @@ export function getICalExport(
|
|||||||
includeCancelled: boolean,
|
includeCancelled: boolean,
|
||||||
): ICalEvent[] {
|
): ICalEvent[] {
|
||||||
return [
|
return [
|
||||||
...flatMap(dateSeries, event =>
|
...dateSeries.flatMap(event =>
|
||||||
toICal(event, translator, {
|
toICal(event, translator, {
|
||||||
allowRRuleExceptions: false,
|
allowRRuleExceptions: false,
|
||||||
excludeCancelledEvents: !includeCancelled,
|
excludeCancelledEvents: !includeCancelled,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
...(includeCancelled
|
...(includeCancelled
|
||||||
? flatMap(dateSeries, event => toICalUpdates(event, translator))
|
? dateSeries.flatMap(event => toICalUpdates(event, translator))
|
||||||
: []),
|
: []),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2021 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -27,8 +27,8 @@ import {
|
|||||||
import {BehaviorSubject, Observable, Subscription} from 'rxjs';
|
import {BehaviorSubject, Observable, Subscription} from 'rxjs';
|
||||||
import {DataProvider} from '../data/data.provider';
|
import {DataProvider} from '../data/data.provider';
|
||||||
import {map} from 'rxjs/operators';
|
import {map} from 'rxjs/operators';
|
||||||
import {pick} from 'lodash-es';
|
|
||||||
import {DateFormatPipe, DurationPipe} from 'ngx-moment';
|
import {DateFormatPipe, DurationPipe} from 'ngx-moment';
|
||||||
|
import {pick} from '../../_helpers/collections/pick';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -36,7 +36,7 @@ import {DateFormatPipe, DurationPipe} from 'ngx-moment';
|
|||||||
export function toDateSeriesRelevantData(
|
export function toDateSeriesRelevantData(
|
||||||
dateSeries: SCDateSeries,
|
dateSeries: SCDateSeries,
|
||||||
): DateSeriesRelevantData {
|
): DateSeriesRelevantData {
|
||||||
return pick(dateSeries, ...dateSeriesRelevantKeys);
|
return pick(dateSeries, dateSeriesRelevantKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DateSeriesRelevantKeys =
|
export type DateSeriesRelevantKeys =
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2021 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -23,18 +23,6 @@ import {
|
|||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import {ModalController, PopoverController} from '@ionic/angular';
|
import {ModalController, PopoverController} from '@ionic/angular';
|
||||||
import {SCDateSeries} from '@openstapps/core';
|
import {SCDateSeries} from '@openstapps/core';
|
||||||
import {
|
|
||||||
difference,
|
|
||||||
every,
|
|
||||||
flatMap,
|
|
||||||
groupBy,
|
|
||||||
mapValues,
|
|
||||||
some,
|
|
||||||
sortBy,
|
|
||||||
union,
|
|
||||||
values,
|
|
||||||
} from 'lodash-es';
|
|
||||||
import {capitalize, last} from 'lodash-es';
|
|
||||||
import {Subscription} from 'rxjs';
|
import {Subscription} from 'rxjs';
|
||||||
import {
|
import {
|
||||||
DateSeriesRelevantData,
|
DateSeriesRelevantData,
|
||||||
@@ -44,6 +32,9 @@ import {
|
|||||||
import {CalendarService} from '../../calendar/calendar.service';
|
import {CalendarService} from '../../calendar/calendar.service';
|
||||||
import {AddEventReviewModalComponent} from '../../calendar/add-event-review-modal.component';
|
import {AddEventReviewModalComponent} from '../../calendar/add-event-review-modal.component';
|
||||||
import {ThingTranslatePipe} from '../../../translation/thing-translate.pipe';
|
import {ThingTranslatePipe} from '../../../translation/thing-translate.pipe';
|
||||||
|
import {groupBy, groupByProperty} from '../../../_helpers/collections/group-by';
|
||||||
|
import {mapValues} from '../../../_helpers/collections/map-values';
|
||||||
|
import {stringSortBy} from '../../../_helpers/collections/string-sort';
|
||||||
|
|
||||||
enum Selection {
|
enum Selection {
|
||||||
ON = 2,
|
ON = 2,
|
||||||
@@ -93,10 +84,10 @@ class TreeNode<T extends TreeNode<any> | SelectionValue> {
|
|||||||
: Selection.OFF,
|
: Selection.OFF,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.checked = every(selections, it => it === Selection.ON);
|
this.checked = selections.every(it => it === Selection.ON);
|
||||||
this.indeterminate = this.checked
|
this.indeterminate = this.checked
|
||||||
? false
|
? false
|
||||||
: some(selections, it => it > Selection.OFF);
|
: selections.some(it => it > Selection.OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -174,21 +165,11 @@ interface SelectionValue {
|
|||||||
styleUrls: ['add-event-popover.scss'],
|
styleUrls: ['add-event-popover.scss'],
|
||||||
})
|
})
|
||||||
export class AddEventPopoverComponent implements OnInit, OnDestroy {
|
export class AddEventPopoverComponent implements OnInit, OnDestroy {
|
||||||
/**
|
|
||||||
* Lodash alias
|
|
||||||
*/
|
|
||||||
capitalize: (item: string) => string = capitalize;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The item the action belongs to
|
* The item the action belongs to
|
||||||
*/
|
*/
|
||||||
@Input() items: SCDateSeries[];
|
@Input() items: SCDateSeries[];
|
||||||
|
|
||||||
/**
|
|
||||||
* Lodash alias
|
|
||||||
*/
|
|
||||||
last: <T>(item: T[] | null | undefined) => T | undefined = last;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selection of the item
|
* Selection of the item
|
||||||
*/
|
*/
|
||||||
@@ -229,17 +210,16 @@ export class AddEventPopoverComponent implements OnInit, OnDestroy {
|
|||||||
this.partialDateSeries = result;
|
this.partialDateSeries = result;
|
||||||
|
|
||||||
this.selection = new TreeNode(
|
this.selection = new TreeNode(
|
||||||
values(
|
Object.values(
|
||||||
groupBy(
|
groupBy(
|
||||||
sortBy(
|
this.items
|
||||||
this.items.map(item => ({
|
.map(item => ({
|
||||||
selected: this.partialDateSeries.some(
|
selected: this.partialDateSeries.some(
|
||||||
it => it.uid === item.uid,
|
it => it.uid === item.uid,
|
||||||
),
|
),
|
||||||
item: item,
|
item: item,
|
||||||
})),
|
}))
|
||||||
it => it.item.repeatFrequency,
|
.sort(stringSortBy(it => it.item.repeatFrequency)),
|
||||||
),
|
|
||||||
it => it.item.repeatFrequency,
|
it => it.item.repeatFrequency,
|
||||||
),
|
),
|
||||||
).map(item => new TreeNode(item, this.ref)),
|
).map(item => new TreeNode(item, this.ref)),
|
||||||
@@ -254,7 +234,10 @@ export class AddEventPopoverComponent implements OnInit, OnDestroy {
|
|||||||
unselected: DateSeriesRelevantData[];
|
unselected: DateSeriesRelevantData[];
|
||||||
} {
|
} {
|
||||||
const selection = mapValues(
|
const selection = mapValues(
|
||||||
groupBy(flatMap(this.selection.children, 'children'), 'selected'),
|
groupByProperty(
|
||||||
|
this.selection.children.flatMap(it => it.children),
|
||||||
|
'selected',
|
||||||
|
),
|
||||||
value => value.map(it => toDateSeriesRelevantData(it.item)),
|
value => value.map(it => toDateSeriesRelevantData(it.item)),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -285,9 +268,12 @@ export class AddEventPopoverComponent implements OnInit, OnDestroy {
|
|||||||
if (save) {
|
if (save) {
|
||||||
const {selected, unselected} = this.getSelection();
|
const {selected, unselected} = this.getSelection();
|
||||||
console.log(selected, unselected);
|
console.log(selected, unselected);
|
||||||
this.scheduleProvider.partialEvents$.next(
|
this.scheduleProvider.partialEvents$.next([
|
||||||
union(difference(this.partialDateSeries, unselected), selected),
|
...new Set([
|
||||||
);
|
...this.partialDateSeries.filter(it => !unselected.includes(it)),
|
||||||
|
...selected,
|
||||||
|
]),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.popoverController.dismiss();
|
await this.popoverController.dismiss();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
~ Copyright (C) 2021 StApps
|
~ Copyright (C) 2022 StApps
|
||||||
~ This program is free software: you can redistribute it and/or modify it
|
~ This program is free software: you can redistribute it and/or modify it
|
||||||
~ under the terms of the GNU General Public License as published by the Free
|
~ under the terms of the GNU General Public License as published by the Free
|
||||||
~ Software Foundation, version 3.
|
~ Software Foundation, version 3.
|
||||||
@@ -54,13 +54,16 @@
|
|||||||
{{ 'data.chips.add_events.popover.AT' | translate }}
|
{{ 'data.chips.add_events.popover.AT' | translate }}
|
||||||
{{ date.item.dates[0] | amDateFormat: 'HH:mm ddd' }}
|
{{ date.item.dates[0] | amDateFormat: 'HH:mm ddd' }}
|
||||||
{{ 'data.chips.add_events.popover.UNTIL' | translate }}
|
{{ 'data.chips.add_events.popover.UNTIL' | translate }}
|
||||||
{{ last(date.item.dates) | amDateFormat: 'll' }}
|
{{ date.item.dates[date.item.dates.length - 1] | amDateFormat: 'll' }}
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<ng-template #single_event>
|
<ng-template #single_event>
|
||||||
<ion-label class="ion-text-wrap">
|
<ion-label class="ion-text-wrap">
|
||||||
{{ date.item.duration | amDuration: 'hours' }}
|
{{ date.item.duration | amDuration: 'hours' }}
|
||||||
{{ 'data.chips.add_events.popover.AT' | translate }}
|
{{ 'data.chips.add_events.popover.AT' | translate }}
|
||||||
{{ last(date.item.dates) | amDateFormat: 'll, HH:mm' }}
|
{{
|
||||||
|
date.item.dates[date.item.dates.length - 1]
|
||||||
|
| amDateFormat: 'll, HH:mm'
|
||||||
|
}}
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ion-checkbox slot="start" [checked]="date.selected"> </ion-checkbox>
|
<ion-checkbox slot="start" [checked]="date.selected"> </ion-checkbox>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
/* tslint:disable:prefer-function-over-method */
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2021 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -13,10 +12,11 @@
|
|||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable:prefer-function-over-method */
|
||||||
import {Component, Input, OnDestroy} from '@angular/core';
|
import {Component, Input, OnDestroy} from '@angular/core';
|
||||||
import {PopoverController} from '@ionic/angular';
|
import {PopoverController} from '@ionic/angular';
|
||||||
import {SCDateSeries, SCThing, SCThingType, SCUuid} from '@openstapps/core';
|
import {SCDateSeries, SCThing, SCThingType, SCUuid} from '@openstapps/core';
|
||||||
import {difference, map} from 'lodash-es';
|
|
||||||
import {Subscription} from 'rxjs';
|
import {Subscription} from 'rxjs';
|
||||||
import {ScheduleProvider} from '../../../calendar/schedule.provider';
|
import {ScheduleProvider} from '../../../calendar/schedule.provider';
|
||||||
import {AddEventPopoverComponent} from '../add-event-popover.component';
|
import {AddEventPopoverComponent} from '../add-event-popover.component';
|
||||||
@@ -180,7 +180,9 @@ export class AddEventActionChipComponent implements OnDestroy {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (
|
switch (
|
||||||
difference(map(associatedDateSeries, 'uid'), this.uuids).length
|
associatedDateSeries
|
||||||
|
.map(it => it.uid)
|
||||||
|
.filter(it => !this.uuids.includes(it)).length
|
||||||
) {
|
) {
|
||||||
case 0:
|
case 0:
|
||||||
this.applyState(AddEventStates.ADDED_ALL);
|
this.applyState(AddEventStates.ADDED_ALL);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2021 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -29,7 +29,6 @@ async function delay(ms: number): Promise<void> {
|
|||||||
* ['a', 'b', 'c'] => {0: 'a', 1: 'b', 2: 'c'}
|
* ['a', 'b', 'c'] => {0: 'a', 1: 'b', 2: 'c'}
|
||||||
*/
|
*/
|
||||||
export function arrayToIndexMap<T>(array: T[]): Record<number, T> {
|
export function arrayToIndexMap<T>(array: T[]): Record<number, T> {
|
||||||
// eslint-disable-next-line unicorn/no-array-reduce
|
|
||||||
return array.reduce((previous, current, index) => {
|
return array.reduce((previous, current, index) => {
|
||||||
previous[index] = current;
|
previous[index] = current;
|
||||||
return previous;
|
return previous;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018-2021 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -31,10 +31,10 @@ import {
|
|||||||
SCFeedbackRequest,
|
SCFeedbackRequest,
|
||||||
SCFeedbackResponse,
|
SCFeedbackResponse,
|
||||||
} from '@openstapps/core';
|
} from '@openstapps/core';
|
||||||
import {chunk, fromPairs, toPairs} from 'lodash-es';
|
|
||||||
import {environment} from '../../../environments/environment';
|
import {environment} from '../../../environments/environment';
|
||||||
import {StorageProvider} from '../storage/storage.provider';
|
import {StorageProvider} from '../storage/storage.provider';
|
||||||
import {StAppsWebHttpClient} from './stapps-web-http-client.provider';
|
import {StAppsWebHttpClient} from './stapps-web-http-client.provider';
|
||||||
|
import {chunk} from '../../_helpers/collections/chunk';
|
||||||
|
|
||||||
export enum DataScope {
|
export enum DataScope {
|
||||||
Local = 'local',
|
Local = 'local',
|
||||||
@@ -275,8 +275,8 @@ export class DataProvider {
|
|||||||
return Object.assign(
|
return Object.assign(
|
||||||
{},
|
{},
|
||||||
...(await Promise.all(
|
...(await Promise.all(
|
||||||
chunk(toPairs(query), this.backendQueriesLimit).map(request =>
|
chunk(Object.entries(query), this.backendQueriesLimit).map(request =>
|
||||||
this.client.multiSearch(fromPairs(request)),
|
this.client.multiSearch(Object.fromEntries(request)),
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2019 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -17,7 +17,6 @@ import moment, {Moment} from 'moment';
|
|||||||
|
|
||||||
import {AfterViewInit, Component, Input, OnDestroy} from '@angular/core';
|
import {AfterViewInit, Component, Input, OnDestroy} from '@angular/core';
|
||||||
import {SCDish, SCISO8601Date, SCPlace} from '@openstapps/core';
|
import {SCDish, SCISO8601Date, SCPlace} from '@openstapps/core';
|
||||||
import {keys} from 'lodash-es';
|
|
||||||
import {PlaceMensaService} from './place-mensa-service';
|
import {PlaceMensaService} from './place-mensa-service';
|
||||||
import {DataRoutingService} from '../../../../data-routing.service';
|
import {DataRoutingService} from '../../../../data-routing.service';
|
||||||
import {Router} from '@angular/router';
|
import {Router} from '@angular/router';
|
||||||
@@ -83,7 +82,7 @@ export class PlaceMensaDetailComponent implements AfterViewInit, OnDestroy {
|
|||||||
delete result[key];
|
delete result[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.selectedDay = keys(result)[0];
|
this.selectedDay = Object.keys(result)[0];
|
||||||
});
|
});
|
||||||
this.subscriptions.push(
|
this.subscriptions.push(
|
||||||
this.dataRoutingService.itemSelectListener().subscribe(item => {
|
this.dataRoutingService.itemSelectListener().subscribe(item => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2019 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -17,13 +17,13 @@ import {Injectable} from '@angular/core';
|
|||||||
import {
|
import {
|
||||||
SCDish,
|
SCDish,
|
||||||
SCISO8601Date,
|
SCISO8601Date,
|
||||||
SCMultiSearchRequest,
|
|
||||||
SCPlace,
|
SCPlace,
|
||||||
|
SCSearchQuery,
|
||||||
SCThingType,
|
SCThingType,
|
||||||
} from '@openstapps/core';
|
} from '@openstapps/core';
|
||||||
import {keyBy, mapValues, range} from 'lodash-es';
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import {DataProvider} from '../../../../data.provider';
|
import {DataProvider} from '../../../../data.provider';
|
||||||
|
import {mapValues} from '../../../../../../_helpers/collections/map-values';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO
|
* TODO
|
||||||
@@ -43,9 +43,18 @@ export class PlaceMensaService {
|
|||||||
place: SCPlace,
|
place: SCPlace,
|
||||||
days: number,
|
days: number,
|
||||||
): Promise<Record<SCISO8601Date, SCDish[]>> {
|
): Promise<Record<SCISO8601Date, SCDish[]>> {
|
||||||
const request: SCMultiSearchRequest = mapValues(
|
const request = mapValues<
|
||||||
keyBy(range(days).map(i => moment().add(i, 'days').toISOString())),
|
Record<SCISO8601Date, SCISO8601Date>,
|
||||||
(date: SCISO8601Date) => ({
|
SCSearchQuery
|
||||||
|
>(
|
||||||
|
Array.from({length: days})
|
||||||
|
.map((_, i) => i)
|
||||||
|
.map(i => moment().add(i, 'days').toISOString())
|
||||||
|
.reduce((accumulator, item) => {
|
||||||
|
accumulator[item] = item;
|
||||||
|
return accumulator;
|
||||||
|
}, {} as Record<SCISO8601Date, SCISO8601Date>),
|
||||||
|
date => ({
|
||||||
filter: {
|
filter: {
|
||||||
arguments: {
|
arguments: {
|
||||||
filters: [
|
filters: [
|
||||||
@@ -82,7 +91,7 @@ export class PlaceMensaService {
|
|||||||
|
|
||||||
return mapValues(
|
return mapValues(
|
||||||
await this.dataProvider.multiSearch(request),
|
await this.dataProvider.multiSearch(request),
|
||||||
'data',
|
it => it.data,
|
||||||
) as Record<SCISO8601Date, SCDish[]>;
|
) as Record<SCISO8601Date, SCDish[]>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {JQueryRequestor, Requestor} from '@openid/appauth';
|
import {JQueryRequestor, Requestor} from '@openid/appauth';
|
||||||
import {
|
import {
|
||||||
@@ -31,6 +46,7 @@ export class LibraryAccountService {
|
|||||||
private readonly authHelper: AuthHelperService,
|
private readonly authHelper: AuthHelperService,
|
||||||
readonly configProvider: ConfigProvider,
|
readonly configProvider: ConfigProvider,
|
||||||
) {
|
) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
const config: SCFeatureConfigurationExtern = (
|
const config: SCFeatureConfigurationExtern = (
|
||||||
configProvider.getValue('features') as SCFeatureConfiguration
|
configProvider.getValue('features') as SCFeatureConfiguration
|
||||||
).extern!.paia;
|
).extern!.paia;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2020 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2021 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -16,7 +16,6 @@ import {Component, Input, OnDestroy, OnInit, ViewChild} from '@angular/core';
|
|||||||
import {ActivatedRoute} from '@angular/router';
|
import {ActivatedRoute} from '@angular/router';
|
||||||
import {Platform} from '@ionic/angular';
|
import {Platform} from '@ionic/angular';
|
||||||
import {SCISO8601Date, SCUuid} from '@openstapps/core';
|
import {SCISO8601Date, SCUuid} from '@openstapps/core';
|
||||||
import {last} from 'lodash-es';
|
|
||||||
import moment, {Moment} from 'moment';
|
import moment, {Moment} from 'moment';
|
||||||
import {DateFormatPipe} from 'ngx-moment';
|
import {DateFormatPipe} from 'ngx-moment';
|
||||||
import {Subscription} from 'rxjs';
|
import {Subscription} from 'rxjs';
|
||||||
@@ -178,7 +177,8 @@ export class CalendarViewComponent implements OnDestroy, OnInit {
|
|||||||
let dayString: string | number | null =
|
let dayString: string | number | null =
|
||||||
this.activatedRoute.snapshot.paramMap.get('date');
|
this.activatedRoute.snapshot.paramMap.get('date');
|
||||||
if (dayString == undefined || dayString === 'now') {
|
if (dayString == undefined || dayString === 'now') {
|
||||||
const urlFragment: string = last(window.location.href.split('/')) ?? '';
|
const fragments = window.location.href.split('/');
|
||||||
|
const urlFragment: string = fragments[fragments.length - 1] ?? '';
|
||||||
|
|
||||||
dayString = /^\d{4}-\d{2}-\d{2}$/.test(urlFragment)
|
dayString = /^\d{4}-\d{2}-\d{2}$/.test(urlFragment)
|
||||||
? urlFragment
|
? urlFragment
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2021 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -33,8 +33,8 @@ import {
|
|||||||
ViewContainerRef,
|
ViewContainerRef,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import Swiper from 'swiper';
|
import Swiper from 'swiper';
|
||||||
import {drop, dropRight, forEach, range, take, takeRight, zip} from 'lodash-es';
|
|
||||||
import {materialManualFade} from '../../../../animation/material-motion';
|
import {materialManualFade} from '../../../../animation/material-motion';
|
||||||
|
import {zip} from '../../../../_helpers/collections/zip';
|
||||||
|
|
||||||
export interface SlideContext {
|
export interface SlideContext {
|
||||||
$implicit: number;
|
$implicit: number;
|
||||||
@@ -221,17 +221,23 @@ export class InfiniteSwiperComponent
|
|||||||
);
|
);
|
||||||
|
|
||||||
// delete slides that are going to be dropped
|
// delete slides that are going to be dropped
|
||||||
for (const slide of (direction ? takeRight : take)(slides, deltaAmount)) {
|
for (const slide of [...slides].splice(
|
||||||
|
direction ? -deltaAmount : 0,
|
||||||
|
deltaAmount,
|
||||||
|
)) {
|
||||||
slide?.destroy();
|
slide?.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
// reuse existing slides
|
// reuse existing slides
|
||||||
const newElements: undefined[] = Array.from({length: deltaAmount});
|
const newElements: undefined[] = Array.from({length: deltaAmount});
|
||||||
const shiftedSlides = direction
|
const shiftedSlides = direction
|
||||||
? [...newElements, ...dropRight(slides, deltaAmount)]
|
? [...newElements, ...slides.slice(0, -deltaAmount)]
|
||||||
: [...drop(slides, deltaAmount), ...newElements];
|
: [...slides.slice(deltaAmount), ...newElements];
|
||||||
|
|
||||||
forEach(zip(containers, shiftedSlides), ([container, element], i) => {
|
for (const [i, [container, element]] of zip(
|
||||||
|
containers,
|
||||||
|
shiftedSlides,
|
||||||
|
).entries()) {
|
||||||
// TODO: we should be able to skip this... In theory.
|
// TODO: we should be able to skip this... In theory.
|
||||||
while (container!.length > 0) {
|
while (container!.length > 0) {
|
||||||
console.warn('Slide container is not empty after detach!');
|
console.warn('Slide container is not empty after detach!');
|
||||||
@@ -245,12 +251,14 @@ export class InfiniteSwiperComponent
|
|||||||
$implicit: this.virtualIndex + (i - this.slidesPerView),
|
$implicit: this.virtualIndex + (i - this.slidesPerView),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
this.swiper.slideTo(this.slidesPerView, 0, false);
|
this.swiper.slideTo(this.slidesPerView, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
resetSlides() {
|
resetSlides() {
|
||||||
this.slidesArray = range(0, this.slidesPerView * 3);
|
this.slidesArray = Array.from({length: this.slidesPerView * 3}).map(
|
||||||
|
(_, i) => i,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
@@ -7,14 +6,16 @@
|
|||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licens for
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
* more details.
|
* more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import {groupRangeOverlaps} from './range-overlap';
|
import {groupRangeOverlaps} from './range-overlap';
|
||||||
import {shuffle} from 'lodash-es';
|
import {shuffle} from '../../../../_helpers/collections/shuffle';
|
||||||
|
|
||||||
interface SimpleRange {
|
interface SimpleRange {
|
||||||
starty: number;
|
starty: number;
|
||||||
|
|||||||
@@ -6,13 +6,13 @@
|
|||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licens for
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
* more details.
|
* more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import {flatMap, max, min, partition} from 'lodash-es';
|
import {partition} from '../../../../_helpers/collections/partition';
|
||||||
|
|
||||||
export interface RangeInfo<T> {
|
export interface RangeInfo<T> {
|
||||||
elements: T[];
|
elements: T[];
|
||||||
@@ -75,11 +75,9 @@ function internalGroupRangeOverlaps<T>(input: RangeInfo<T>[]): RangeInfo<T>[] {
|
|||||||
ranges = rest;
|
ranges = rest;
|
||||||
const elements = [range, ...overlaps];
|
const elements = [range, ...overlaps];
|
||||||
result.push({
|
result.push({
|
||||||
elements: flatMap(elements, 'elements'),
|
elements: elements.flatMap(it => it.elements),
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
start: Math.min(...elements.map(it => it.start)),
|
||||||
start: min(elements.map(it => it.start))!,
|
end: Math.max(...elements.map(it => it.end)),
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
||||||
end: max(elements.map(it => it.end))!,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return cumulativeReorders === 0 ? result : internalGroupRangeOverlaps(result);
|
return cumulativeReorders === 0 ? result : internalGroupRangeOverlaps(result);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2021 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -14,12 +14,14 @@
|
|||||||
*/
|
*/
|
||||||
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
|
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
|
||||||
import {SCDateSeries, SCUuid} from '@openstapps/core';
|
import {SCDateSeries, SCUuid} from '@openstapps/core';
|
||||||
import {flatMap, groupBy, isNil, omit, sortBy} from 'lodash-es';
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import {Subscription} from 'rxjs';
|
import {Subscription} from 'rxjs';
|
||||||
import {materialFade} from '../../../animation/material-motion';
|
import {materialFade} from '../../../animation/material-motion';
|
||||||
import {ScheduleProvider} from '../../calendar/schedule.provider';
|
import {ScheduleProvider} from '../../calendar/schedule.provider';
|
||||||
import {ScheduleEvent} from './schema/schema';
|
import {ScheduleEvent} from './schema/schema';
|
||||||
|
import {groupBy} from '../../../_helpers/collections/group-by';
|
||||||
|
import {omit} from '../../../_helpers/collections/omit';
|
||||||
|
import {stringSortBy} from '../../../_helpers/collections/string-sort';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A single event
|
* A single event
|
||||||
@@ -72,9 +74,10 @@ export class ScheduleSingleEventsComponent implements OnInit, OnDestroy {
|
|||||||
static groupDateSeriesToDays(
|
static groupDateSeriesToDays(
|
||||||
dateSeries: SCDateSeries[],
|
dateSeries: SCDateSeries[],
|
||||||
): ScheduleSingleEvent[][] {
|
): ScheduleSingleEvent[][] {
|
||||||
return sortBy(
|
return Object.entries(
|
||||||
groupBy(
|
groupBy(
|
||||||
flatMap(dateSeries, event =>
|
dateSeries
|
||||||
|
.flatMap(event =>
|
||||||
event.dates.map(date => ({
|
event.dates.map(date => ({
|
||||||
dateUnix: moment(date).unix(),
|
dateUnix: moment(date).unix(),
|
||||||
day: moment(date).startOf('day').toISOString(),
|
day: moment(date).startOf('day').toISOString(),
|
||||||
@@ -94,10 +97,11 @@ export class ScheduleSingleEventsComponent implements OnInit, OnDestroy {
|
|||||||
)
|
)
|
||||||
.sort((a, b) => a.dateUnix - b.dateUnix)
|
.sort((a, b) => a.dateUnix - b.dateUnix)
|
||||||
.map(event => omit(event, 'dateUnix')),
|
.map(event => omit(event, 'dateUnix')),
|
||||||
'day',
|
it => it.day,
|
||||||
),
|
),
|
||||||
'day',
|
)
|
||||||
);
|
.sort(stringSortBy(([key]) => key))
|
||||||
|
.map(([_, value]) => value);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(protected readonly scheduleProvider: ScheduleProvider) {}
|
constructor(protected readonly scheduleProvider: ScheduleProvider) {}
|
||||||
@@ -115,7 +119,7 @@ export class ScheduleSingleEventsComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
// TODO: replace with filter
|
// TODO: replace with filter
|
||||||
return ScheduleSingleEventsComponent.groupDateSeriesToDays(
|
return ScheduleSingleEventsComponent.groupDateSeriesToDays(
|
||||||
dateSeries.dates.filter(it => isNil(it.repeatFrequency)),
|
dateSeries.dates.filter(it => !it.repeatFrequency),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2021 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -92,7 +92,6 @@ export class ScheduleViewComponent extends CalendarViewComponent {
|
|||||||
|
|
||||||
for (const series of dateSeries.dates) {
|
for (const series of dateSeries.dates) {
|
||||||
const weekDays = Object.keys(
|
const weekDays = Object.keys(
|
||||||
// eslint-disable-next-line unicorn/no-array-reduce
|
|
||||||
series.dates.reduce((accumulator, date) => {
|
series.dates.reduce((accumulator, date) => {
|
||||||
accumulator[moment(date).isoWeekday()] = true;
|
accumulator[moment(date).isoWeekday()] = true;
|
||||||
return accumulator;
|
return accumulator;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2021 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -17,7 +17,6 @@ import {Component, OnInit} from '@angular/core';
|
|||||||
import {AddEventReviewModalComponent} from '../../calendar/add-event-review-modal.component';
|
import {AddEventReviewModalComponent} from '../../calendar/add-event-review-modal.component';
|
||||||
import {ModalController} from '@ionic/angular';
|
import {ModalController} from '@ionic/angular';
|
||||||
import {ScheduleProvider} from '../../calendar/schedule.provider';
|
import {ScheduleProvider} from '../../calendar/schedule.provider';
|
||||||
import {map} from 'lodash-es';
|
|
||||||
import {Directory, Encoding, Filesystem} from '@capacitor/filesystem';
|
import {Directory, Encoding, Filesystem} from '@capacitor/filesystem';
|
||||||
import {Share} from '@capacitor/share';
|
import {Share} from '@capacitor/share';
|
||||||
import {Device} from '@capacitor/device';
|
import {Device} from '@capacitor/device';
|
||||||
@@ -99,7 +98,7 @@ export class CalendarSyncSettingsComponent implements OnInit {
|
|||||||
|
|
||||||
async setSetting(settings: Partial<Record<CALENDAR_SYNC_KEYS, boolean>>) {
|
async setSetting(settings: Partial<Record<CALENDAR_SYNC_KEYS, boolean>>) {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
map(settings, (setting, key) =>
|
Object.entries(settings).map(([key, setting]) =>
|
||||||
this.storageProvider.put(calendarSettingStorageKey(key), setting),
|
this.storageProvider.put(calendarSettingStorageKey(key), setting),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2021 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2021 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -439,7 +439,6 @@ export class NumberLocalizedPipe implements PipeTransform, OnDestroy {
|
|||||||
const options = formatOptions
|
const options = formatOptions
|
||||||
?.split(',')
|
?.split(',')
|
||||||
.map(element => element.split(':'))
|
.map(element => element.split(':'))
|
||||||
// eslint-disable-next-line unicorn/no-array-reduce
|
|
||||||
.reduce(
|
.reduce(
|
||||||
(accumulator, [key, value_]) => ({
|
(accumulator, [key, value_]) => ({
|
||||||
...accumulator,
|
...accumulator,
|
||||||
@@ -512,7 +511,6 @@ export class DateLocalizedFormatPipe implements PipeTransform, OnDestroy {
|
|||||||
const options = formatOptions
|
const options = formatOptions
|
||||||
?.split(',')
|
?.split(',')
|
||||||
.map(element => element.split(':'))
|
.map(element => element.split(':'))
|
||||||
// eslint-disable-next-line unicorn/no-array-reduce
|
|
||||||
.reduce(
|
.reduce(
|
||||||
(accumulator, [key, value_]) => ({
|
(accumulator, [key, value_]) => ({
|
||||||
...accumulator,
|
...accumulator,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2021 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -18,7 +18,7 @@ import {TranslateService} from '@ngx-translate/core';
|
|||||||
import {isThing, SCThings, SCThingType} from '@openstapps/core';
|
import {isThing, SCThings, SCThingType} from '@openstapps/core';
|
||||||
import {Subscription} from 'rxjs';
|
import {Subscription} from 'rxjs';
|
||||||
import {ThingTranslateService} from './thing-translate.service';
|
import {ThingTranslateService} from './thing-translate.service';
|
||||||
import {get} from 'lodash-es';
|
import {get} from '../_helpers/collections/get';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@Pipe({
|
@Pipe({
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2021 StApps
|
* Copyright (C) 2022 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -14,7 +14,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Injectable, Pipe, PipeTransform} from '@angular/core';
|
import {Injectable, Pipe, PipeTransform} from '@angular/core';
|
||||||
import {last} from 'lodash-es';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the last value of an array
|
* Get the last value of an array
|
||||||
@@ -30,6 +29,6 @@ export class ArrayLastPipe implements PipeTransform {
|
|||||||
*/
|
*/
|
||||||
// tslint:disable-next-line:prefer-function-over-method
|
// tslint:disable-next-line:prefer-function-over-method
|
||||||
transform<T>(value: T[]): T | undefined {
|
transform<T>(value: T[]): T | undefined {
|
||||||
return last(value);
|
return value[value.length - 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
"importHelpers": true,
|
"importHelpers": true,
|
||||||
"module": "es2020",
|
"module": "es2020",
|
||||||
"lib": [
|
"lib": [
|
||||||
"es2018",
|
"es2020",
|
||||||
"dom"
|
"dom"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user