mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-04-12 01:09:06 +00:00
Merge remote-tracking branch 'app/develop'
This commit is contained in:
@@ -1 +1,2 @@
|
||||
src/app/_helpers/data
|
||||
node_modules
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020,
|
||||
"sourceType": "module",
|
||||
"project": ["tsconfig.json", "e2e/tsconfig.e2e.json"],
|
||||
"project": ["tsconfig.json", "tsconfig.spec.json", "e2e/tsconfig.e2e.json"],
|
||||
"createDefaultProgram": true
|
||||
},
|
||||
"extends": [
|
||||
@@ -44,7 +44,6 @@
|
||||
],
|
||||
"unicorn/no-nested-ternary": "off",
|
||||
"unicorn/better-regex": "off",
|
||||
|
||||
"jsdoc/no-types": "error",
|
||||
"jsdoc/require-param": "off",
|
||||
"jsdoc/require-param-description": "error",
|
||||
@@ -52,7 +51,6 @@
|
||||
"jsdoc/require-returns": "off",
|
||||
"jsdoc/require-param-type": "off",
|
||||
"jsdoc/require-returns-type": "off",
|
||||
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
|
||||
@@ -26,7 +26,7 @@ setup:
|
||||
services:
|
||||
- docker:dind
|
||||
script:
|
||||
- docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.gitlab.com
|
||||
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.com
|
||||
- docker build -t registry.gitlab.com/openstapps/app .
|
||||
- docker push registry.gitlab.com/openstapps/app
|
||||
cache: {} # disable irrelevant cache for this job
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* Copyright (C) 2023 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.
|
||||
@@ -22,7 +22,7 @@ describe('App', () => {
|
||||
it('should have a proper working navigation', () => {
|
||||
cy.visit('/');
|
||||
|
||||
cy.contains('Einstellungen').click();
|
||||
cy.get('ion-title').contains('Einstellungen');
|
||||
cy.contains('ion-tab-button', 'Mensa').click();
|
||||
cy.get('ion-title').contains('Mensa');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* Copyright (C) 2023 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.
|
||||
@@ -54,14 +54,14 @@ describe('context menu', function () {
|
||||
|
||||
it('should truncate categories', function () {
|
||||
cy.get('stapps-context').within(() => {
|
||||
cy.contains('ion-item', '(4) Universitätsveranstaltung').should('not.exist');
|
||||
cy.contains('ion-item', '(1) Universitätsveranstaltung').should('not.exist');
|
||||
cy.get('.context-filter > ion-button').click();
|
||||
cy.contains('ion-item', '(4) Universitätsveranstaltung').should('exist');
|
||||
});
|
||||
});
|
||||
|
||||
it('should truncate long category items', function () {
|
||||
cy.contains('ion-list', 'Kategorien | Akademische Veranstaltung').within(() => {
|
||||
cy.contains('ion-list', 'Akademische Veranstaltung / Kategorien').within(() => {
|
||||
cy.contains('ion-item', '(1) Tutorium').should('not.exist');
|
||||
cy.get('div > ion-button').click();
|
||||
cy.contains('ion-item', '(1) Tutorium').should('exist');
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* Copyright (C) 2023 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.
|
||||
@@ -40,7 +40,6 @@ describe('favorites', function () {
|
||||
cy.get('.title').should('contain', text);
|
||||
cy.get('stapps-favorite-button').click();
|
||||
});
|
||||
cy.get('cdk-virtual-scroll-viewport').should('be.not.visible');
|
||||
cy.get('stapps-data-list').contains('Keine Ergebnisse').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -30,14 +30,14 @@ describe('ical', function () {
|
||||
|
||||
cy.get('ion-app > ion-modal').within(() => {
|
||||
cy.get('ion-footer > ion-toolbar > ion-button').should('have.attr', 'disabled');
|
||||
cy.contains('ion-item', /eine Stunde um 19. Jan. 2059, \d+:00/).click();
|
||||
cy.contains('ion-item', /19\.\s+Januar\s+2059,\s+\d{2}:00\s+-\s+\d{2}:00/).click();
|
||||
cy.get('ion-footer > ion-toolbar > ion-button').should('not.have.attr', 'disabled');
|
||||
cy.get('ion-footer > ion-toolbar > ion-button').click();
|
||||
});
|
||||
|
||||
cy.get('add-event-review-modal').within(() => {
|
||||
cy.get('ion-item-group').should('contain', 'UNIcert (Test)');
|
||||
cy.contains('ion-item-group', /19. Jan. 2059, \d+:00/);
|
||||
cy.contains('ion-item-group', /19\.\s+Jan\.\s+2059,\s+\d{2}:00/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
"compilerOptions": {
|
||||
"sourceMap": false,
|
||||
"types": ["cypress"]
|
||||
}
|
||||
},
|
||||
"exclude": []
|
||||
}
|
||||
|
||||
636
frontend/app/package-lock.json
generated
636
frontend/app/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openstapps/app",
|
||||
"version": "2.0.0",
|
||||
"version": "2.1.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -2735,6 +2735,7 @@
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz",
|
||||
"integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ajv": "^6.12.4",
|
||||
"debug": "^4.3.2",
|
||||
@@ -2751,6 +2752,7 @@
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
@@ -2761,7 +2763,8 @@
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -2844,25 +2847,19 @@
|
||||
"integrity": "sha512-hebf0ixGPugiZfH6g7HS/hrDzkKmNdJV/pV2jUz5lfoZXFMjE+7aeAr1AqwW6EGNej65WcEP8VUL5YUc3wSCjw=="
|
||||
},
|
||||
"@humanwhocodes/config-array": {
|
||||
"version": "0.10.7",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz",
|
||||
"integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==",
|
||||
"version": "0.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
|
||||
"integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
|
||||
"requires": {
|
||||
"@humanwhocodes/object-schema": "^1.2.1",
|
||||
"debug": "^4.1.1",
|
||||
"minimatch": "^3.0.4"
|
||||
"minimatch": "^3.0.5"
|
||||
}
|
||||
},
|
||||
"@humanwhocodes/gitignore-to-minimatch": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz",
|
||||
"integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA=="
|
||||
},
|
||||
"@humanwhocodes/module-importer": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
|
||||
"integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="
|
||||
},
|
||||
"@humanwhocodes/momoa": {
|
||||
"version": "2.0.4",
|
||||
@@ -4022,26 +4019,26 @@
|
||||
}
|
||||
},
|
||||
"@openstapps/api": {
|
||||
"version": "0.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@openstapps/api/-/api-0.45.0.tgz",
|
||||
"integrity": "sha512-lF1TIxbtqQlRYCvSyS3EDjQiwVK7BmZ3/HQ01MhlUR1ucfvMTk1GyIPx5E8HmrKSi3Pv8shurCObSwStQJjK+Q==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@openstapps/api/-/api-1.0.1.tgz",
|
||||
"integrity": "sha512-M7aBEikw730t+jYIDYrJrdNhNvA0N1y9j6qGz2XAKwXbZN7NwDgs/41BCsPLPJgPPRGDL1bH/PbcbkKCn/vTTg==",
|
||||
"requires": {
|
||||
"@krlwlfrt/async-pool": "0.7.0",
|
||||
"@openstapps/core": "0.72.0",
|
||||
"@openstapps/core-tools": "0.32.0",
|
||||
"@openstapps/core": "1.0.1",
|
||||
"@openstapps/core-tools": "0.34.0",
|
||||
"@openstapps/logger": "1.1.1",
|
||||
"@types/cli-progress": "3.11.0",
|
||||
"@types/express": "4.17.14",
|
||||
"@types/morgan": "1.9.3",
|
||||
"@types/node": "14.18.34",
|
||||
"@types/express": "4.17.17",
|
||||
"@types/morgan": "1.9.4",
|
||||
"@types/node": "14.18.43",
|
||||
"@types/traverse": "0.6.32",
|
||||
"@types/uuid": "8.3.4",
|
||||
"@types/wait-on": "5.3.1",
|
||||
"body-parser": "1.20.1",
|
||||
"cli-progress": "3.11.2",
|
||||
"commander": "9.4.1",
|
||||
"body-parser": "1.20.2",
|
||||
"cli-progress": "3.12.0",
|
||||
"commander": "9.5.0",
|
||||
"express": "4.18.2",
|
||||
"got": "11.8.5",
|
||||
"got": "11.8.6",
|
||||
"json-schema": "0.4.0",
|
||||
"moment": "2.29.4",
|
||||
"morgan": "1.10.0",
|
||||
@@ -4051,164 +4048,200 @@
|
||||
"wait-on": "6.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/express": {
|
||||
"version": "4.17.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz",
|
||||
"integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==",
|
||||
"requires": {
|
||||
"@types/body-parser": "*",
|
||||
"@types/express-serve-static-core": "^4.17.33",
|
||||
"@types/qs": "*",
|
||||
"@types/serve-static": "*"
|
||||
}
|
||||
},
|
||||
"@types/express-serve-static-core": {
|
||||
"version": "4.17.34",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.34.tgz",
|
||||
"integrity": "sha512-fvr49XlCGoUj2Pp730AItckfjat4WNb0lb3kfrLWffd+RLeoGAMsq7UOy04PAPtoL01uKwcp6u8nhzpgpDYr3w==",
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"@types/qs": "*",
|
||||
"@types/range-parser": "*",
|
||||
"@types/send": "*"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "14.18.34",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.34.tgz",
|
||||
"integrity": "sha512-hcU9AIQVHmPnmjRK+XUUYlILlr9pQrsqSrwov/JK1pnf3GTQowVBhx54FbvM0AU/VXGH4i3+vgXS5EguR7fysA=="
|
||||
"version": "14.18.43",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.43.tgz",
|
||||
"integrity": "sha512-n3eFEaoem0WNwLux+k272P0+aq++5o05bA9CfiwKPdYPB5ZambWKdWoeHy7/OJiizMhzg27NLaZ6uzjLTzXceQ=="
|
||||
},
|
||||
"body-parser": {
|
||||
"version": "1.20.2",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
|
||||
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
|
||||
"requires": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.5",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"raw-body": "2.5.2",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
}
|
||||
},
|
||||
"commander": {
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
|
||||
"integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ=="
|
||||
},
|
||||
"content-type": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
|
||||
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"depd": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||
"requires": {
|
||||
"safer-buffer": ">= 2.1.2 < 3"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"raw-body": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
|
||||
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
|
||||
"requires": {
|
||||
"bytes": "3.1.2",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"unpipe": "1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@openstapps/configuration": {
|
||||
"version": "0.33.0",
|
||||
"resolved": "https://registry.npmjs.org/@openstapps/configuration/-/configuration-0.33.0.tgz",
|
||||
"integrity": "sha512-sum9DB8+2r5eXnJhie1UPcQQTPupd0m3Xgsft+D6LVvbjbmt/XCpCMvlZSoM+LE1ZkUdgUmbFJ81mqjWKgCsJA==",
|
||||
"version": "0.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@openstapps/configuration/-/configuration-0.34.0.tgz",
|
||||
"integrity": "sha512-woPn4v3mQMUibtRs84VDpiC0EarowA4HvtpXbzc6ddWcYs8jtPLwA+mSbWSiROhJ2CeRQTJtMK+bJ4yhIRfdKw==",
|
||||
"requires": {
|
||||
"@types/node": "14.18.24",
|
||||
"@types/semver": "7.3.12",
|
||||
"@types/node": "14.18.36",
|
||||
"@types/semver": "7.3.13",
|
||||
"@types/yaml": "1.9.7",
|
||||
"chalk": "4.1.2",
|
||||
"commander": "9.4.0",
|
||||
"semver": "7.3.7",
|
||||
"commander": "9.5.0",
|
||||
"semver": "7.3.8",
|
||||
"yaml": "1.10.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "14.18.36",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.36.tgz",
|
||||
"integrity": "sha512-FXKWbsJ6a1hIrRxv+FoukuHnGTgEzKYGi7kilfMae96AL9UNkPFNWJEEYWzdRI9ooIkbr4AKldyuSTLql06vLQ=="
|
||||
},
|
||||
"@types/semver": {
|
||||
"version": "7.3.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
|
||||
"integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw=="
|
||||
},
|
||||
"commander": {
|
||||
"version": "9.4.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-9.4.0.tgz",
|
||||
"integrity": "sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw=="
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
|
||||
"integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@openstapps/core": {
|
||||
"version": "0.72.0",
|
||||
"resolved": "https://registry.npmjs.org/@openstapps/core/-/core-0.72.0.tgz",
|
||||
"integrity": "sha512-bT22CWKf0Do32FwJLf+rWxbQTHTiPbJEzm3dd3Sk5utGgNTAeFequaNea2csvCOA1dRaVrRVQ7Ed9prVdep9ow==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@openstapps/core/-/core-1.0.1.tgz",
|
||||
"integrity": "sha512-+JlycoMcj+QIaXicOZYlNU07XlDc3zRIydYEoLGueAfkTbKt0ap5FWbNL+Hz8ve3ApQP2Hj+4FuU8H6QyLA0vQ==",
|
||||
"requires": {
|
||||
"@openstapps/core-tools": "0.32.0",
|
||||
"@openstapps/core-tools": "0.34.0",
|
||||
"@types/geojson": "1.0.6",
|
||||
"@types/json-patch": "0.0.30",
|
||||
"@types/json-schema": "7.0.11",
|
||||
"@types/node": "14.18.24",
|
||||
"@types/node": "14.18.36",
|
||||
"fast-deep-equal": "3.1.3",
|
||||
"http-status-codes": "2.2.0",
|
||||
"json-patch": "0.7.0",
|
||||
"json-schema": "0.4.0",
|
||||
"rfdc": "1.3.0",
|
||||
"ts-optchain": "0.1.8"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "14.18.36",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.36.tgz",
|
||||
"integrity": "sha512-FXKWbsJ6a1hIrRxv+FoukuHnGTgEzKYGi7kilfMae96AL9UNkPFNWJEEYWzdRI9ooIkbr4AKldyuSTLql06vLQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@openstapps/core-tools": {
|
||||
"version": "0.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@openstapps/core-tools/-/core-tools-0.32.0.tgz",
|
||||
"integrity": "sha512-PXfb9b3B2uVQUhu+QBi3tlz7I2nHz4hlyTNvfHIxuO8pC0ONaZWY56tjBgqg1Af9BP1ZGq3J3Zg2sWWsYlGFEw==",
|
||||
"version": "0.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@openstapps/core-tools/-/core-tools-0.34.0.tgz",
|
||||
"integrity": "sha512-gCnmBX0Mp1vf9p66i64u2lQAXBTKxI6Lt92ZUxkrMcIv0CmGAEw1mEEgg4hf4nRDm0umBSu0tRfh7DFnuQyOEA==",
|
||||
"requires": {
|
||||
"@openstapps/logger": "1.0.0",
|
||||
"ajv": "8.11.0",
|
||||
"@openstapps/logger": "1.1.1",
|
||||
"ajv": "8.12.0",
|
||||
"better-ajv-errors": "1.2.0",
|
||||
"chai": "4.3.6",
|
||||
"commander": "9.4.0",
|
||||
"deepmerge": "4.2.2",
|
||||
"chai": "4.3.7",
|
||||
"commander": "10.0.0",
|
||||
"deepmerge": "4.3.0",
|
||||
"del": "6.1.1",
|
||||
"eslint": "8.22.0",
|
||||
"flatted": "3.2.6",
|
||||
"eslint": "8.33.0",
|
||||
"flatted": "3.2.7",
|
||||
"fs-extra": "10.1.0",
|
||||
"glob": "8.0.3",
|
||||
"got": "11.8.5",
|
||||
"glob": "8.1.0",
|
||||
"got": "11.8.6",
|
||||
"humanize-string": "3.0.0",
|
||||
"json-schema": "0.4.0",
|
||||
"lodash": "4.17.21",
|
||||
"mustache": "4.2.0",
|
||||
"openapi-types": "12.0.0",
|
||||
"openapi-types": "12.1.0",
|
||||
"plantuml-encoder": "1.4.0",
|
||||
"re2": "1.17.7",
|
||||
"re2": "1.18.0",
|
||||
"toposort": "2.0.2",
|
||||
"ts-json-schema-generator": "1.0.0",
|
||||
"ts-json-schema-generator": "1.2.0",
|
||||
"ts-node": "10.9.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@openstapps/logger": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@openstapps/logger/-/logger-1.0.0.tgz",
|
||||
"integrity": "sha512-ImCfnLJWHWwFJ1W7KCIWgFe7EXI0cAtap0Dznz+758BPAlLZ+hJHSbIbGHWwEAfRNAB53TIABF5npSsKSDq4Sw==",
|
||||
"@eslint/eslintrc": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
|
||||
"integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==",
|
||||
"requires": {
|
||||
"@types/node": "14.18.24",
|
||||
"@types/nodemailer": "6.4.5",
|
||||
"chalk": "4.1.2",
|
||||
"flatted": "3.2.6",
|
||||
"moment": "2.29.4",
|
||||
"nodemailer": "6.7.8"
|
||||
}
|
||||
},
|
||||
"commander": {
|
||||
"version": "9.4.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-9.4.0.tgz",
|
||||
"integrity": "sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw=="
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
|
||||
},
|
||||
"eslint": {
|
||||
"version": "8.22.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.22.0.tgz",
|
||||
"integrity": "sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA==",
|
||||
"requires": {
|
||||
"@eslint/eslintrc": "^1.3.0",
|
||||
"@humanwhocodes/config-array": "^0.10.4",
|
||||
"@humanwhocodes/gitignore-to-minimatch": "^1.0.2",
|
||||
"ajv": "^6.10.0",
|
||||
"chalk": "^4.0.0",
|
||||
"cross-spawn": "^7.0.2",
|
||||
"ajv": "^6.12.4",
|
||||
"debug": "^4.3.2",
|
||||
"doctrine": "^3.0.0",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"eslint-scope": "^7.1.1",
|
||||
"eslint-utils": "^3.0.0",
|
||||
"eslint-visitor-keys": "^3.3.0",
|
||||
"espree": "^9.3.3",
|
||||
"esquery": "^1.4.0",
|
||||
"esutils": "^2.0.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"file-entry-cache": "^6.0.1",
|
||||
"find-up": "^5.0.0",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"glob-parent": "^6.0.1",
|
||||
"globals": "^13.15.0",
|
||||
"globby": "^11.1.0",
|
||||
"grapheme-splitter": "^1.0.4",
|
||||
"espree": "^9.4.0",
|
||||
"globals": "^13.19.0",
|
||||
"ignore": "^5.2.0",
|
||||
"import-fresh": "^3.0.0",
|
||||
"imurmurhash": "^0.1.4",
|
||||
"is-glob": "^4.0.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||
"levn": "^0.4.1",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"minimatch": "^3.1.2",
|
||||
"natural-compare": "^1.4.0",
|
||||
"optionator": "^0.9.1",
|
||||
"regexpp": "^3.2.0",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"strip-json-comments": "^3.1.0",
|
||||
"text-table": "^0.2.0",
|
||||
"v8-compile-cache": "^2.0.3"
|
||||
"strip-json-comments": "^3.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": {
|
||||
@@ -4221,6 +4254,136 @@
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"ajv": {
|
||||
"version": "8.12.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
||||
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"commander": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz",
|
||||
"integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA=="
|
||||
},
|
||||
"deepmerge": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz",
|
||||
"integrity": "sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og=="
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
|
||||
},
|
||||
"eslint": {
|
||||
"version": "8.33.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.33.0.tgz",
|
||||
"integrity": "sha512-WjOpFQgKK8VrCnAtl8We0SUOy/oVZ5NHykyMiagV1M9r8IFpIJX7DduK6n1mpfhlG7T1NLWm2SuD8QB7KFySaA==",
|
||||
"requires": {
|
||||
"@eslint/eslintrc": "^1.4.1",
|
||||
"@humanwhocodes/config-array": "^0.11.8",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@nodelib/fs.walk": "^1.2.8",
|
||||
"ajv": "^6.10.0",
|
||||
"chalk": "^4.0.0",
|
||||
"cross-spawn": "^7.0.2",
|
||||
"debug": "^4.3.2",
|
||||
"doctrine": "^3.0.0",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"eslint-scope": "^7.1.1",
|
||||
"eslint-utils": "^3.0.0",
|
||||
"eslint-visitor-keys": "^3.3.0",
|
||||
"espree": "^9.4.0",
|
||||
"esquery": "^1.4.0",
|
||||
"esutils": "^2.0.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"file-entry-cache": "^6.0.1",
|
||||
"find-up": "^5.0.0",
|
||||
"glob-parent": "^6.0.2",
|
||||
"globals": "^13.19.0",
|
||||
"grapheme-splitter": "^1.0.4",
|
||||
"ignore": "^5.2.0",
|
||||
"import-fresh": "^3.0.0",
|
||||
"imurmurhash": "^0.1.4",
|
||||
"is-glob": "^4.0.0",
|
||||
"is-path-inside": "^3.0.3",
|
||||
"js-sdsl": "^4.1.4",
|
||||
"js-yaml": "^4.1.0",
|
||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||
"levn": "^0.4.1",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"minimatch": "^3.1.2",
|
||||
"natural-compare": "^1.4.0",
|
||||
"optionator": "^0.9.1",
|
||||
"regexpp": "^3.2.0",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"strip-json-comments": "^3.1.0",
|
||||
"text-table": "^0.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"flatted": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
|
||||
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ=="
|
||||
},
|
||||
"glob": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
|
||||
"integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^5.0.1",
|
||||
"once": "^1.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimatch": {
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
|
||||
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
|
||||
"requires": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -4232,10 +4395,13 @@
|
||||
"is-glob": "^4.0.3"
|
||||
}
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
|
||||
"globals": {
|
||||
"version": "13.20.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
|
||||
"integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
|
||||
"requires": {
|
||||
"type-fest": "^0.20.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -4257,23 +4423,10 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.32.tgz",
|
||||
"integrity": "sha512-Y6S38pFr04yb13qqHf8uk1nHE3lXgQ30WZbv1mLliV9pt0NjvqdWttLcrOYLnXbOafknVYRHZGoMSpR9UwfYow=="
|
||||
},
|
||||
"@types/nodemailer": {
|
||||
"version": "6.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.6.tgz",
|
||||
"integrity": "sha512-pD6fL5GQtUKvD2WnPmg5bC2e8kWCAPDwMPmHe/ohQbW+Dy0EcHgZ2oCSuPlWNqk74LS5BVMig1SymQbFMPPK3w==",
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"flatted": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
|
||||
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ=="
|
||||
},
|
||||
"nodemailer": {
|
||||
"version": "6.8.0",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.8.0.tgz",
|
||||
"integrity": "sha512-EjYvSmHzekz6VNkNd12aUqAco+bOkRe3Of5jVhltqKhEsjw/y0PYPJfp83+s9Wzh1dspYAkUW/YNQ350NATbSQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -4327,9 +4480,9 @@
|
||||
}
|
||||
},
|
||||
"@sideway/formula": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz",
|
||||
"integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg=="
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz",
|
||||
"integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg=="
|
||||
},
|
||||
"@sideway/pinpoint": {
|
||||
"version": "2.0.0",
|
||||
@@ -4521,6 +4674,7 @@
|
||||
"version": "4.17.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz",
|
||||
"integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/body-parser": "*",
|
||||
"@types/express-serve-static-core": "^4.17.18",
|
||||
@@ -4532,6 +4686,7 @@
|
||||
"version": "4.17.31",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz",
|
||||
"integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"@types/qs": "*",
|
||||
@@ -4679,9 +4834,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/morgan": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.3.tgz",
|
||||
"integrity": "sha512-BiLcfVqGBZCyNCnCH3F4o2GmDLrpy0HeBVnNlyZG4fo88ZiE9SoiBe3C+2ezuwbjlEyT+PDZ17//TAlRxAn75Q==",
|
||||
"version": "1.9.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.4.tgz",
|
||||
"integrity": "sha512-cXoc4k+6+YAllH3ZHmx4hf7La1dzUk6keTR4bF4b4Sc0mZxU/zK4wO7l+ZzezXm/jkYj/qC+uYGZrarZdIVvyQ==",
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
@@ -4692,9 +4847,9 @@
|
||||
"integrity": "sha512-aJdn8XErcSrfr7k8ZDDfU6/2OgjZcB2Fu9d+ESK8D7Oa5mtsv8Fa8GpcwTA0v60kuZBaalKPzuzun4Ov1YWO/w=="
|
||||
},
|
||||
"@types/nodemailer": {
|
||||
"version": "6.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.5.tgz",
|
||||
"integrity": "sha512-zuP3nBRQHI6M2PkXnGGy1Ww4VB+MyYHGgnfV2T+JR9KLkeWqPJuyVUgLpKXuFnA/b7pZaIDFh2sV4759B7jK1g==",
|
||||
"version": "6.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.6.tgz",
|
||||
"integrity": "sha512-pD6fL5GQtUKvD2WnPmg5bC2e8kWCAPDwMPmHe/ohQbW+Dy0EcHgZ2oCSuPlWNqk74LS5BVMig1SymQbFMPPK3w==",
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
@@ -4750,7 +4905,24 @@
|
||||
"@types/semver": {
|
||||
"version": "7.3.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.12.tgz",
|
||||
"integrity": "sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A=="
|
||||
"integrity": "sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/send": {
|
||||
"version": "0.17.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz",
|
||||
"integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==",
|
||||
"requires": {
|
||||
"@types/mime": "^1",
|
||||
"@types/node": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/mime": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
|
||||
"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@types/serve-index": {
|
||||
"version": "1.9.1",
|
||||
@@ -5494,6 +5666,7 @@
|
||||
"version": "8.11.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
|
||||
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
@@ -6448,13 +6621,13 @@
|
||||
"dev": true
|
||||
},
|
||||
"chai": {
|
||||
"version": "4.3.6",
|
||||
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz",
|
||||
"integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==",
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz",
|
||||
"integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==",
|
||||
"requires": {
|
||||
"assertion-error": "^1.1.0",
|
||||
"check-error": "^1.0.2",
|
||||
"deep-eql": "^3.0.1",
|
||||
"deep-eql": "^4.1.2",
|
||||
"get-func-name": "^2.0.0",
|
||||
"loupe": "^2.3.1",
|
||||
"pathval": "^1.1.1",
|
||||
@@ -6689,9 +6862,9 @@
|
||||
}
|
||||
},
|
||||
"cli-progress": {
|
||||
"version": "3.11.2",
|
||||
"resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.11.2.tgz",
|
||||
"integrity": "sha512-lCPoS6ncgX4+rJu5bS3F/iCz17kZ9MPZ6dpuTtI0KXKABkhyXIdYB3Inby1OpaGti3YlI3EeEkM9AuWpelJrVA==",
|
||||
"version": "3.12.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz",
|
||||
"integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==",
|
||||
"requires": {
|
||||
"string-width": "^4.2.3"
|
||||
}
|
||||
@@ -7827,9 +8000,9 @@
|
||||
}
|
||||
},
|
||||
"deep-eql": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
|
||||
"integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
|
||||
"integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
|
||||
"requires": {
|
||||
"type-detect": "^4.0.0"
|
||||
}
|
||||
@@ -9653,11 +9826,6 @@
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
|
||||
},
|
||||
"functional-red-black-tree": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
|
||||
"integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g=="
|
||||
},
|
||||
"functions-have-names": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
|
||||
@@ -10020,6 +10188,7 @@
|
||||
"version": "13.18.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz",
|
||||
"integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"type-fest": "^0.20.2"
|
||||
}
|
||||
@@ -10038,9 +10207,9 @@
|
||||
}
|
||||
},
|
||||
"got": {
|
||||
"version": "11.8.5",
|
||||
"resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz",
|
||||
"integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==",
|
||||
"version": "11.8.6",
|
||||
"resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz",
|
||||
"integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==",
|
||||
"requires": {
|
||||
"@sindresorhus/is": "^4.0.0",
|
||||
"@szmarczak/http-timer": "^4.0.5",
|
||||
@@ -10646,9 +10815,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"install-artifact-from-github": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/install-artifact-from-github/-/install-artifact-from-github-1.3.1.tgz",
|
||||
"integrity": "sha512-3l3Bymg2eKDsN5wQuMfgGEj2x6l5MCAv0zPL6rxHESufFVlEAKW/6oY9F1aGgvY/EgWm5+eWGRjINveL4X7Hgg=="
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/install-artifact-from-github/-/install-artifact-from-github-1.3.2.tgz",
|
||||
"integrity": "sha512-yCFcLvqk0yQdxx0uJz4t9Z3adDMLAYrcGYv546uRXCSvxE+GqNYhhz/KmrGcUKGI/gVLR9n/e/zM9jX/+ASMJQ=="
|
||||
},
|
||||
"ionic-appauth": {
|
||||
"version": "0.9.0",
|
||||
@@ -11154,22 +11323,21 @@
|
||||
"dev": true
|
||||
},
|
||||
"joi": {
|
||||
"version": "17.7.0",
|
||||
"resolved": "https://registry.npmjs.org/joi/-/joi-17.7.0.tgz",
|
||||
"integrity": "sha512-1/ugc8djfn93rTE3WRKdCzGGt/EtiYKxITMO4Wiv6q5JL1gl9ePt4kBsl1S499nbosspfctIQTpYIhSmHA3WAg==",
|
||||
"version": "17.9.2",
|
||||
"resolved": "https://registry.npmjs.org/joi/-/joi-17.9.2.tgz",
|
||||
"integrity": "sha512-Itk/r+V4Dx0V3c7RLFdRh12IOjySm2/WGPMubBT92cQvRfYZhPM2W0hZlctjj72iES8jsRCwp7S/cRmWBnJ4nw==",
|
||||
"requires": {
|
||||
"@hapi/hoek": "^9.0.0",
|
||||
"@hapi/topo": "^5.0.0",
|
||||
"@sideway/address": "^4.1.3",
|
||||
"@sideway/formula": "^3.0.0",
|
||||
"@sideway/formula": "^3.0.1",
|
||||
"@sideway/pinpoint": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"js-sdsl": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz",
|
||||
"integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ=="
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
@@ -12896,9 +13064,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node-gyp": {
|
||||
"version": "9.3.0",
|
||||
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.0.tgz",
|
||||
"integrity": "sha512-A6rJWfXFz7TQNjpldJ915WFb1LnhO4lIve3ANPbWreuEoLoKlFT3sxIepPBkLhM27crW8YmN+pjlgbasH6cH/Q==",
|
||||
"version": "9.3.1",
|
||||
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.1.tgz",
|
||||
"integrity": "sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==",
|
||||
"requires": {
|
||||
"env-paths": "^2.2.0",
|
||||
"glob": "^7.1.4",
|
||||
@@ -12940,9 +13108,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"nodemailer": {
|
||||
"version": "6.7.8",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.8.tgz",
|
||||
"integrity": "sha512-2zaTFGqZixVmTxpJRCFC+Vk5eGRd/fYtvIR+dl5u9QXLTQWGIf48x/JXvo58g9sa0bU6To04XUv554Paykum3g=="
|
||||
"version": "6.8.0",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.8.0.tgz",
|
||||
"integrity": "sha512-EjYvSmHzekz6VNkNd12aUqAco+bOkRe3Of5jVhltqKhEsjw/y0PYPJfp83+s9Wzh1dspYAkUW/YNQ350NATbSQ=="
|
||||
},
|
||||
"nopt": {
|
||||
"version": "6.0.0",
|
||||
@@ -12967,8 +13135,7 @@
|
||||
"normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
|
||||
},
|
||||
"normalize-range": {
|
||||
"version": "0.1.2",
|
||||
@@ -13203,9 +13370,9 @@
|
||||
}
|
||||
},
|
||||
"openapi-types": {
|
||||
"version": "12.0.0",
|
||||
"resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.0.0.tgz",
|
||||
"integrity": "sha512-6Wd9k8nmGQHgCbehZCP6wwWcfXcvinhybUTBatuhjRsCxUIujuYFZc9QnGeae75CyHASewBtxs0HX/qwREReUw=="
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.0.tgz",
|
||||
"integrity": "sha512-XpeCy01X6L5EpP+6Hc3jWN7rMZJ+/k1lwki/kTmWzbVhdPie3jd5O2ZtedEx8Yp58icJ0osVldLMrTB/zslQXA=="
|
||||
},
|
||||
"opencollective-postinstall": {
|
||||
"version": "2.0.3",
|
||||
@@ -14907,13 +15074,13 @@
|
||||
}
|
||||
},
|
||||
"re2": {
|
||||
"version": "1.17.7",
|
||||
"resolved": "https://registry.npmjs.org/re2/-/re2-1.17.7.tgz",
|
||||
"integrity": "sha512-X8GSuiBoVWwcjuppqSjsIkRxNUKDdjhkO9SBekQbZ2ksqWUReCy7DQPWOVpoTnpdtdz5PIpTTxTFzvJv5UMfjA==",
|
||||
"version": "1.18.0",
|
||||
"resolved": "https://registry.npmjs.org/re2/-/re2-1.18.0.tgz",
|
||||
"integrity": "sha512-MoCYZlJ9YUgksND9asyNF2/x532daXU/ARp1UeJbQ5flMY6ryKNEhrWt85aw3YluzOJlC3vXpGgK2a1jb0b4GA==",
|
||||
"requires": {
|
||||
"install-artifact-from-github": "^1.3.1",
|
||||
"nan": "^2.16.0",
|
||||
"node-gyp": "^9.0.0"
|
||||
"nan": "^2.17.0",
|
||||
"node-gyp": "^9.3.0"
|
||||
}
|
||||
},
|
||||
"read": {
|
||||
@@ -15553,9 +15720,9 @@
|
||||
}
|
||||
},
|
||||
"safe-stable-stringify": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.1.tgz",
|
||||
"integrity": "sha512-dVHE6bMtS/bnL2mwualjc6IxEv1F+OCUpA46pKUj6F8uDbUM0jCCulPqRNPSnWwGNKx5etqMjZYdXtrm5KJZGA=="
|
||||
"version": "2.4.3",
|
||||
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz",
|
||||
"integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g=="
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
@@ -17242,35 +17409,23 @@
|
||||
"dev": true
|
||||
},
|
||||
"ts-json-schema-generator": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-json-schema-generator/-/ts-json-schema-generator-1.0.0.tgz",
|
||||
"integrity": "sha512-F5VofsyMhNSXKII32NDS8/Ur8o2K3Sh5i/U2ke3UgCKf26ybgm2cZeT2x7VJPl1trML/9QLzz/82l0mvzmb3Vw==",
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-json-schema-generator/-/ts-json-schema-generator-1.2.0.tgz",
|
||||
"integrity": "sha512-tUMeO3ZvA12d3HHh7T/AK8W5hmUhDRNtqWRHSMN3ZRbUFt+UmV0oX8k1RK4SA+a+BKNHpmW2v06MS49e8Fi3Yg==",
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"commander": "^9.0.0",
|
||||
"glob": "^7.2.0",
|
||||
"json5": "^2.2.0",
|
||||
"safe-stable-stringify": "^2.3.1",
|
||||
"typescript": "~4.6.2"
|
||||
"@types/json-schema": "^7.0.11",
|
||||
"commander": "^9.4.1",
|
||||
"glob": "^8.0.3",
|
||||
"json5": "^2.2.1",
|
||||
"normalize-path": "^3.0.0",
|
||||
"safe-stable-stringify": "^2.4.1",
|
||||
"typescript": "~4.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"glob": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.1.1",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.6.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
|
||||
"integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg=="
|
||||
"version": "4.9.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
||||
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -17584,7 +17739,8 @@
|
||||
"v8-compile-cache": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
|
||||
"integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA=="
|
||||
"integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
|
||||
"dev": true
|
||||
},
|
||||
"v8-compile-cache-lib": {
|
||||
"version": "3.0.1",
|
||||
@@ -17665,16 +17821,6 @@
|
||||
"lodash": "^4.17.21",
|
||||
"minimist": "^1.2.5",
|
||||
"rxjs": "^7.5.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"rxjs": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.6.0.tgz",
|
||||
"integrity": "sha512-DDa7d8TFNUalGC9VqXvQ1euWNN7sc63TrUCuM9J998+ViviahMIjKSOU7rfcgFOF+FCD71BhDRv4hrFz+ImDLQ==",
|
||||
"requires": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"watchpack": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openstapps/app",
|
||||
"version": "2.0.0",
|
||||
"version": "2.1.1",
|
||||
"description": "The generic app tailored to fulfill needs of German universities, written using Ionic Framework.",
|
||||
"license": "GPL-3.0-only",
|
||||
"author": "Karl-Philipp Wulfert <krlwlfrt@gmail.com>",
|
||||
@@ -19,7 +19,7 @@
|
||||
"build:android": "ionic capacitor build android --no-open && cd android && ./gradlew clean assembleDebug && cd ..",
|
||||
"build:prod": "ng build --configuration=production",
|
||||
"build:stats": "ng build --configuration=production --stats-json",
|
||||
"changelog": "conventional-changelog -p angular -i src/assets/about/CHANGELOG.md -s -r 0 && git add src/assets/about/CHANGELOG.md",
|
||||
"changelog": "conventional-changelog -p angular -i src/assets/about/CHANGELOG.md -s -r 0",
|
||||
"check-configuration": "openstapps-configuration",
|
||||
"cypress:open": "cypress open",
|
||||
"cypress:run": "cypress run",
|
||||
@@ -31,7 +31,7 @@
|
||||
"docker:serve": "sudo docker run -p 8100:8100 -p 35729:35729 -p 53703:53703 -v $PWD:/app -it registry.gitlab.com/openstapps/app bash -c \"npm run start:external\"",
|
||||
"documentation": "compodoc -p tsconfig.json -d docs",
|
||||
"e2e": "ng e2e",
|
||||
"licenses": "license-checker --json > src/assets/about/licenses.json && ts-node ./scripts/accumulate-licenses.ts && git add src/assets/about/licenses.json",
|
||||
"licenses": "license-checker --json > src/assets/about/licenses.json && ts-node ./scripts/accumulate-licenses.ts",
|
||||
"minify-icons": "ts-node scripts/minify-icon-font.ts",
|
||||
"check-icons": "ts-node scripts/check-icon-correctness.ts",
|
||||
"format:check": "prettier --check .",
|
||||
@@ -40,7 +40,7 @@
|
||||
"lint:fix": "eslint --fix -c .eslintrc.json --ignore-path .eslintignore --ext .ts,.html src/",
|
||||
"ng": "ng",
|
||||
"postinstall": "npx jetify",
|
||||
"version": "npm run changelog && npm run licenses && npm run format:fix",
|
||||
"version": "npm run changelog && npm run licenses && npm run format:fix && git add src/assets/about/CHANGELOG.md && git add src/assets/about/licenses.json",
|
||||
"prepublishOnly": "npm ci && npm run build && npm run lint && npm run format:check",
|
||||
"preversion": "npm run prepublishOnly",
|
||||
"push": "git push && git push origin \"v$npm_package_version\"",
|
||||
@@ -86,9 +86,9 @@
|
||||
"@ionic/storage-angular": "3.0.6",
|
||||
"@ngx-translate/core": "14.0.0",
|
||||
"@ngx-translate/http-loader": "7.0.0",
|
||||
"@openstapps/api": "0.45.0",
|
||||
"@openstapps/configuration": "0.33.0",
|
||||
"@openstapps/core": "0.72.0",
|
||||
"@openstapps/api": "1.0.1",
|
||||
"@openstapps/configuration": "0.34.0",
|
||||
"@openstapps/core": "1.0.1",
|
||||
"@transistorsoft/capacitor-background-fetch": "1.0.2",
|
||||
"capacitor-secure-storage-plugin": "0.8.1",
|
||||
"cordova-plugin-calendar": "5.1.6",
|
||||
|
||||
34
frontend/app/src/app/_helpers/rxjs/mutation-observer.ts
Normal file
34
frontend/app/src/app/_helpers/rxjs/mutation-observer.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 {Observable} from 'rxjs';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export function fromMutationObserver(
|
||||
target: Node,
|
||||
options?: MutationObserverInit,
|
||||
): Observable<MutationRecord[]> {
|
||||
return new Observable(subscriber => {
|
||||
const observer = new MutationObserver(mutations => {
|
||||
subscriber.next(mutations);
|
||||
});
|
||||
observer.observe(target, options);
|
||||
return () => {
|
||||
observer.disconnect();
|
||||
};
|
||||
});
|
||||
}
|
||||
20
frontend/app/src/app/animation/easings.ts
Normal file
20
frontend/app/src/app/animation/easings.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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/>.
|
||||
*/
|
||||
|
||||
// these are the ionic values
|
||||
export const iosEasing = 'cubic-bezier(0.32,0.72,0,1)';
|
||||
export const iosDuration = 540;
|
||||
export const mdEasing = 'cubic-bezier(0.36,0.66,0.04,1)';
|
||||
export const mdDuration = 280;
|
||||
83
frontend/app/src/app/animation/fab-expand.ts
Normal file
83
frontend/app/src/app/animation/fab-expand.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 {AnimationBuilder, AnimationController} from '@ionic/angular';
|
||||
import {AnimationOptions} from '@ionic/angular/providers/nav-controller';
|
||||
import {iosDuration, iosEasing, mdDuration, mdEasing} from './easings';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export function fabExpand(animationController: AnimationController): AnimationBuilder {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return (_baseElement: HTMLElement, options: AnimationOptions | any) => {
|
||||
const rootTransition = animationController
|
||||
.create()
|
||||
.duration(options.duration ?? (options.mode === 'ios' ? iosDuration : mdDuration * 1.4))
|
||||
.easing(options.mode === 'ios' ? iosEasing : mdEasing);
|
||||
const back = options.direction === 'back';
|
||||
const fabView = back ? options.enteringEl! : options.leavingEl!;
|
||||
const otherView = back ? options.leavingEl! : options.enteringEl!;
|
||||
|
||||
const fab = fabView.querySelector('ion-fab-button').shadowRoot.querySelector('.button-native');
|
||||
const fabBounds = fab.getBoundingClientRect();
|
||||
const viewBounds = otherView.getBoundingClientRect();
|
||||
|
||||
const useReducedMotion = viewBounds.width > 500;
|
||||
const reducedMotionTransform = `${Math.min(viewBounds.width * 0.3, 200)}px`;
|
||||
const reducedMotionViewBorderRadius = '128px';
|
||||
const reducedMotionFabGrow = '2';
|
||||
const reducedMotionViewShrink = '0.9';
|
||||
|
||||
const viewCenterX = (viewBounds.width - viewBounds.x) / 2;
|
||||
const viewCenterY = (viewBounds.height - viewBounds.y) / 2;
|
||||
|
||||
const viewOnFab = useReducedMotion
|
||||
? `translate(${reducedMotionTransform}, ${reducedMotionTransform}) scale(${reducedMotionViewShrink})`
|
||||
: `translate(${(fabBounds.x - viewBounds.x) / 2}px, ${(fabBounds.y - viewBounds.y) / 2}px) scale(${
|
||||
fabBounds.width / viewBounds.width
|
||||
}, ${fabBounds.height / viewBounds.height})`;
|
||||
const fabOnView = useReducedMotion
|
||||
? `translate(-${reducedMotionTransform}, -${reducedMotionTransform}) scale(${reducedMotionFabGrow})`
|
||||
: `translate(${viewCenterX - fabBounds.x}px, ${viewCenterY - fabBounds.y}px) scale(${
|
||||
viewBounds.width / fabBounds.width
|
||||
}, ${viewBounds.height / fabBounds.height})`;
|
||||
const transformNormal = `translate(0px, 0px) scale(1, 1)`;
|
||||
|
||||
const viewBorderRadius = useReducedMotion ? reducedMotionViewBorderRadius : '50%';
|
||||
|
||||
const fabViewFade = animationController
|
||||
.create()
|
||||
.beforeStyles({zIndex: -1})
|
||||
.fromTo('opacity', '1', '1')
|
||||
.addElement(fabView);
|
||||
const fabGrow = animationController
|
||||
.create()
|
||||
.beforeStyles({transformOrigin: 'center'})
|
||||
.fromTo('transform', back ? fabOnView : transformNormal, back ? transformNormal : fabOnView)
|
||||
.fromTo('opacity', back ? '0' : '1', back ? '1' : '0')
|
||||
.fromTo('borderRadius', back ? '0' : '50%', back ? '50%' : '0')
|
||||
.addElement(fab);
|
||||
const viewGrow = animationController
|
||||
.create()
|
||||
.beforeStyles({zIndex: 200, overflow: 'hidden', transformOrigin: 'center'})
|
||||
.fromTo('transform', back ? transformNormal : viewOnFab, back ? viewOnFab : transformNormal)
|
||||
.fromTo('opacity', back ? '1' : '0', back ? '0' : '1')
|
||||
.fromTo('borderRadius', back ? '0' : viewBorderRadius, back ? viewBorderRadius : '0')
|
||||
.addElement(otherView);
|
||||
|
||||
return rootTransition.addAnimation(fabGrow).addAnimation(viewGrow).addAnimation(fabViewFade);
|
||||
};
|
||||
}
|
||||
@@ -1,3 +1,22 @@
|
||||
<!--
|
||||
~ Copyright (C) 2023 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/>.
|
||||
-->
|
||||
<<<<<<<< HEAD:frontend/app/src/app/util/simple-swiper.html
|
||||
<ng-content></ng-content>
|
||||
========
|
||||
|
||||
<ion-app style="margin-top: env(safe-area-inset-top)">
|
||||
<stapps-navigation></stapps-navigation>
|
||||
</ion-app>
|
||||
>>>>>>>> app/develop:frontend/app/src/app/app.component.html
|
||||
|
||||
@@ -22,10 +22,8 @@
|
||||
<!-- TODO: translation -->
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content class="ion-content-parallax">
|
||||
<div>
|
||||
<div class="about-changelog">
|
||||
<markdown src="assets/about/CHANGELOG.md"></markdown>
|
||||
</div>
|
||||
<ion-content parallax>
|
||||
<div class="about-changelog">
|
||||
<markdown src="assets/about/CHANGELOG.md"></markdown>
|
||||
</div>
|
||||
</ion-content>
|
||||
|
||||
@@ -22,32 +22,30 @@
|
||||
<!-- TODO: translation -->
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content class="ion-content-parallax">
|
||||
<div>
|
||||
<div class="licenses-content">
|
||||
<ion-card
|
||||
*ngFor="let license of licenses"
|
||||
[href]="license.url || license.repository"
|
||||
rel="external"
|
||||
target="_blank"
|
||||
>
|
||||
<ion-card-header>
|
||||
<ion-card-title>
|
||||
{{ license.name }}
|
||||
<ion-icon size="16" weight="300" class="supertext-icon" name="open_in_browser"></ion-icon>
|
||||
</ion-card-title>
|
||||
<ion-content parallax>
|
||||
<div class="licenses-content">
|
||||
<ion-card
|
||||
*ngFor="let license of licenses"
|
||||
[href]="license.url || license.repository"
|
||||
rel="external"
|
||||
target="_blank"
|
||||
>
|
||||
<ion-card-header>
|
||||
<ion-card-title>
|
||||
{{ license.name }}
|
||||
<ion-icon size="16" weight="300" class="supertext-icon" name="open_in_browser"></ion-icon>
|
||||
</ion-card-title>
|
||||
|
||||
<ion-card-subtitle *ngIf="license.authors || license.publisher">
|
||||
{{ license.authors || license.publisher }}
|
||||
</ion-card-subtitle>
|
||||
</ion-card-header>
|
||||
<ion-card-content>
|
||||
<ion-chip (click)="$event.preventDefault(); viewLicense(license)">
|
||||
<ion-icon name="copyright"></ion-icon>
|
||||
<ion-label>{{ license.licenses }} License</ion-label>
|
||||
</ion-chip>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
</div>
|
||||
<ion-card-subtitle *ngIf="license.authors || license.publisher">
|
||||
{{ license.authors || license.publisher }}
|
||||
</ion-card-subtitle>
|
||||
</ion-card-header>
|
||||
<ion-card-content>
|
||||
<ion-chip (click)="$event.preventDefault(); viewLicense(license)">
|
||||
<ion-icon name="copyright"></ion-icon>
|
||||
<ion-label>{{ license.licenses }} License</ion-label>
|
||||
</ion-chip>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
</div>
|
||||
</ion-content>
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
<<<<<<<< HEAD:packages/es-mapping-generator/test/mapping-model/aggregations/src/types.ts
|
||||
/*
|
||||
* Copyright (C) 2020 StApps
|
||||
========
|
||||
/*!
|
||||
* Copyright (C) 2023 StApps
|
||||
>>>>>>>> app/develop:frontend/app/src/app/modules/about/about-licenses.scss
|
||||
* 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.
|
||||
@@ -13,6 +18,17 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
<<<<<<<< HEAD:packages/es-mapping-generator/test/mapping-model/aggregations/src/types.ts
|
||||
export enum ThingType {
|
||||
AggArray = 'agg array',
|
||||
AggGlobal = 'agg global',
|
||||
AggGlobalNested = 'agg global nested',
|
||||
AggNested = 'agg nested',
|
||||
AggInherited = 'agg inherited',
|
||||
AggInheritedGlobal = 'agg inherited global',
|
||||
AggInheritedOverwritten = 'agg inherited overwritten',
|
||||
}
|
||||
========
|
||||
ion-content > div {
|
||||
height: 100%;
|
||||
}
|
||||
@@ -22,7 +38,7 @@ cdk-virtual-scroll-viewport {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
::ng-deep {
|
||||
:host ::ng-deep {
|
||||
.cdk-virtual-scroll-content-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -36,3 +52,4 @@ cdk-virtual-scroll-viewport {
|
||||
vertical-align: text-top;
|
||||
height: 14px;
|
||||
}
|
||||
>>>>>>>> app/develop:frontend/app/src/app/modules/about/about-licenses.scss
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
~ Copyright (C) 2022 StApps
|
||||
~ Copyright (C) 2023 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.
|
||||
@@ -36,7 +36,7 @@
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
<ion-item *ngSwitchCase="'router link'" [routerLink]="content.link">
|
||||
<ion-item *ngSwitchCase="'router link'" [routerLink]="content.link" fill="clear">
|
||||
<ion-icon *ngIf="content.icon" [name]="content.icon" slot="start"></ion-icon>
|
||||
<ion-label>{{ 'title' | translateSimple: content }}</ion-label>
|
||||
</ion-item>
|
||||
|
||||
@@ -24,11 +24,9 @@
|
||||
</ng-template>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content *ngIf="content" class="ion-content-parallax">
|
||||
<div>
|
||||
<ion-text color="light">{{ appName }} v{{ version }}</ion-text>
|
||||
<div class="page-content">
|
||||
<about-page-content *ngFor="let element of content.content" [content]="element"></about-page-content>
|
||||
</div>
|
||||
<ion-content parallax *ngIf="content">
|
||||
<ion-text>{{ appName }} v{{ version }}</ion-text>
|
||||
<div class="page-content">
|
||||
<about-page-content *ngFor="let element of content.content" [content]="element"></about-page-content>
|
||||
</div>
|
||||
</ion-content>
|
||||
|
||||
@@ -62,10 +62,7 @@ ion-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-sm);
|
||||
background: var(--ion-color-primary-contrast);
|
||||
&.licenses-content {
|
||||
background: var(--ion-color-light);
|
||||
}
|
||||
background: var(--ion-item-background);
|
||||
|
||||
padding-block-end: var(--spacing-md);
|
||||
@include border-radius-in-parallax(var(--border-radius-default));
|
||||
@@ -80,7 +77,6 @@ ion-text {
|
||||
@include border-radius-in-parallax(var(--border-radius-default));
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background-color: var(--ion-color-primary-contrast);
|
||||
margin: 0;
|
||||
|
||||
& > ion-thumbnail {
|
||||
@@ -89,3 +85,7 @@ ion-text {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ion-text {
|
||||
color: var(--ion-color-primary-contrast);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
/*!
|
||||
* 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.
|
||||
* Copyright (C) 2023 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.
|
||||
* 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/>.
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.content {
|
||||
height: 100%;
|
||||
padding-inline: 8px;
|
||||
--ion-item-background: var(--ion-background-color);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import {StorageProvider} from '../storage/storage.provider';
|
||||
import {DefaultAuthService} from './default-auth.service';
|
||||
import {PAIAAuthService} from './paia/paia-auth.service';
|
||||
import {SimpleBrowser} from '../../util/browser.factory';
|
||||
import {AlertController} from '@ionic/angular';
|
||||
|
||||
const AUTH_ORIGIN_PATH = 'stapps.auth.origin_path';
|
||||
|
||||
@@ -45,6 +46,7 @@ export class AuthHelperService {
|
||||
private defaultAuth: DefaultAuthService,
|
||||
private paiaAuth: PAIAAuthService,
|
||||
private browser: SimpleBrowser,
|
||||
private alertController: AlertController,
|
||||
) {
|
||||
this.userConfigurationMap = (
|
||||
this.configProvider.getAnyValue('auth') as {
|
||||
@@ -118,11 +120,33 @@ export class AuthHelperService {
|
||||
|
||||
/**
|
||||
* Ends browser session by opening endSessionEndpoint URL of the provider
|
||||
*
|
||||
* @param providerType Type of the provider (e.g. 'default' or 'paia')
|
||||
*/
|
||||
async endBrowserSession(providerType: SCAuthorizationProviderType) {
|
||||
const endSessionEndpoint = (await this.getProvider(providerType).configuration).endSessionEndpoint ?? '';
|
||||
if (endSessionEndpoint.length > 0) {
|
||||
this.browser.open(new URL(endSessionEndpoint).href);
|
||||
const endSessionEndpoint = (await this.getProvider(providerType).configuration).endSessionEndpoint;
|
||||
|
||||
if (endSessionEndpoint) {
|
||||
const alert: HTMLIonAlertElement = await this.alertController.create({
|
||||
header: this.translateService.instant(`auth.messages.${providerType}.log_out_alert.header`),
|
||||
message: this.translateService.instant(`auth.messages.${providerType}.log_out_alert.message`),
|
||||
buttons: [
|
||||
{
|
||||
text: this.translateService.instant('no'),
|
||||
cssClass: 'default',
|
||||
},
|
||||
{
|
||||
text: this.translateService.instant('yes'),
|
||||
role: 'confirm',
|
||||
cssClass: 'preferred',
|
||||
handler: () => {
|
||||
this.browser.open(new URL(endSessionEndpoint).href);
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await alert.present();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*!
|
||||
* Copyright (C) 2022 StApps
|
||||
* Copyright (C) 2023 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.
|
||||
@@ -27,3 +27,7 @@ ion-toolbar.in-toolbar {
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
:host {
|
||||
--ion-item-background: var(--ion-backgrund-color);
|
||||
}
|
||||
|
||||
@@ -117,8 +117,9 @@ export class CatalogComponent implements OnInit, OnDestroy {
|
||||
semester => semester.startDate <= today && semester.endDate > today,
|
||||
);
|
||||
const currentSemesterIndex = semesters.findIndex(semester => semester.uid === currentSemester?.uid);
|
||||
this.availableSemesters = semesters.slice(currentSemesterIndex - 1, currentSemesterIndex + 2).reverse();
|
||||
|
||||
this.availableSemesters = semesters
|
||||
.slice(Math.max(0, currentSemesterIndex - 1), Math.min(currentSemesterIndex + 2, semesters.length))
|
||||
.reverse();
|
||||
if (typeof this.activeSemester !== 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -121,11 +121,11 @@ export class CatalogProvider {
|
||||
arguments: {
|
||||
bounds: {
|
||||
lowerBound: {
|
||||
limit: `${new Date().setFullYear(new Date().getFullYear() - 1)}`,
|
||||
limit: `${new Date(new Date().setFullYear(new Date().getFullYear() - 1)).toISOString()}`,
|
||||
mode: 'inclusive',
|
||||
},
|
||||
upperBound: {
|
||||
limit: `${new Date().setFullYear(new Date().getFullYear() + 1)}`,
|
||||
limit: `${new Date(new Date().setFullYear(new Date().getFullYear() + 1)).toISOString()}`,
|
||||
mode: 'inclusive',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -48,14 +48,18 @@
|
||||
}
|
||||
|
||||
ion-content {
|
||||
--background: var(--ion-color-light);
|
||||
--background: var(--ion-background-color);
|
||||
--padding-bottom: var(--spacing-xl);
|
||||
&::part(inner-scroll) {
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
}
|
||||
|
||||
.schedule {
|
||||
width: 100%;
|
||||
z-index: 3;
|
||||
background: var(--ion-color-primary);
|
||||
color: var(--ion-color-primary-contrast);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: var(--spacing-md);
|
||||
|
||||
@@ -23,7 +23,6 @@ import {MomentModule} from 'ngx-moment';
|
||||
import {DataModule} from '../data/data.module';
|
||||
import {SettingsProvider} from '../settings/settings.provider';
|
||||
import {DashboardComponent} from './dashboard.component';
|
||||
import {EditModalComponent} from './edit-modal/edit-modal.component';
|
||||
import {SearchSectionComponent} from './sections/search-section/search-section.component';
|
||||
import {NewsSectionComponent} from './sections/news-section/news-section.component';
|
||||
import {MensaSectionComponent} from './sections/mensa-section/mensa-section.component';
|
||||
@@ -46,7 +45,6 @@ const catalogRoutes: Routes = [
|
||||
*/
|
||||
@NgModule({
|
||||
declarations: [
|
||||
EditModalComponent,
|
||||
SearchSectionComponent,
|
||||
NewsSectionComponent,
|
||||
MensaSectionComponent,
|
||||
@@ -69,6 +67,5 @@ const catalogRoutes: Routes = [
|
||||
NewsModule,
|
||||
],
|
||||
providers: [SettingsProvider, TranslatePipe],
|
||||
exports: [EditModalComponent],
|
||||
})
|
||||
export class DashboardModule {}
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
<!--
|
||||
~ 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/>.
|
||||
-->
|
||||
|
||||
<ion-header>
|
||||
<ion-toolbar mode="ios">
|
||||
<ion-title>{{ 'modal.settings' | translate | titlecase }}</ion-title>
|
||||
<ion-button fill="clear" slot="start" (click)="dismissModal()">
|
||||
{{ 'modal.DISMISS_CANCEL' | translate }}
|
||||
</ion-button>
|
||||
<ion-button fill="clear" slot="end" (click)="onSaveClick()">
|
||||
<ion-label>{{ 'modal.DISMISS_CONFIRM' | translate }}</ion-label>
|
||||
</ion-button>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ng-container [ngSwitch]="true">
|
||||
<ion-reorder-group
|
||||
*ngSwitchCase="type === types.CHECKBOXES"
|
||||
disabled="false"
|
||||
(ionItemReorder)="doReorder($event)"
|
||||
>
|
||||
<!-- Default reorder icon, end aligned items -->
|
||||
<ion-item *ngFor="let item of items">
|
||||
<ion-reorder slot="start"></ion-reorder>
|
||||
<ion-label>{{ item.labelLocalized }}</ion-label>
|
||||
<ion-toggle slot="end" [checked]="item.active" [(ngModel)]="item.active"></ion-toggle>
|
||||
</ion-item>
|
||||
</ion-reorder-group>
|
||||
|
||||
<ion-radio-group *ngSwitchCase="type === types.RADIOBOXES" [(ngModel)]="selectedValue">
|
||||
<ion-list-header>
|
||||
<ion-label>{{ 'dashboard.canteens.choose_favorite' | translate }}</ion-label>
|
||||
</ion-list-header>
|
||||
<ion-item *ngFor="let item of items">
|
||||
<ion-label>{{ item.labelLocalized }}</ion-label>
|
||||
<ion-radio slot="end" [value]="item.id"></ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
</ng-container>
|
||||
</ion-content>
|
||||
@@ -1,3 +0,0 @@
|
||||
:host {
|
||||
--width: 100vw;
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* 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 {Component, Input, OnInit, ViewChild} from '@angular/core';
|
||||
import {IonReorderGroup, ModalController} from '@ionic/angular';
|
||||
import {ItemReorderEventDetail} from '@ionic/core';
|
||||
import {EditModalItem, EditModalTypeEnum} from './edit-modal-type.enum';
|
||||
|
||||
/**
|
||||
* Shows a modal window to sort and enable/disable menu items
|
||||
*/
|
||||
@Component({
|
||||
selector: 'stapps-dashboard-edit-modal',
|
||||
templateUrl: 'edit-modal.component.html',
|
||||
styleUrls: ['edit-modal.component.scss'],
|
||||
})
|
||||
export class EditModalComponent implements OnInit {
|
||||
@ViewChild(IonReorderGroup) reorderGroup: IonReorderGroup;
|
||||
|
||||
@Input() type: EditModalTypeEnum = EditModalTypeEnum.CHECKBOXES;
|
||||
|
||||
@Input() items: EditModalItem[];
|
||||
|
||||
@Input() selectedValue: string;
|
||||
|
||||
reorderedItems: EditModalItem[];
|
||||
|
||||
types = EditModalTypeEnum;
|
||||
|
||||
constructor(public modalController: ModalController) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.reorderedItems = this.items;
|
||||
}
|
||||
|
||||
ionViewWillLeave() {
|
||||
this.dismissModal();
|
||||
}
|
||||
|
||||
doReorder(event: CustomEvent<ItemReorderEventDetail>) {
|
||||
this.reorderedItems = event.detail.complete(this.reorderedItems);
|
||||
}
|
||||
|
||||
onSaveClick() {
|
||||
this.modalController.dismiss({
|
||||
items: this.reorderedItems,
|
||||
selectedValue: this.selectedValue,
|
||||
});
|
||||
}
|
||||
|
||||
dismissModal() {
|
||||
this.modalController.dismiss();
|
||||
}
|
||||
}
|
||||
19
frontend/app/src/app/modules/dashboard/fade.animation.ts
Normal file
19
frontend/app/src/app/modules/dashboard/fade.animation.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 {animate, style, transition, trigger} from '@angular/animations';
|
||||
|
||||
export const fadeAnimation = trigger('fade', [
|
||||
transition(':enter', [style({opacity: '0'}), animate(250, style({opacity: '1'}))]),
|
||||
]);
|
||||
28
frontend/app/src/app/modules/dashboard/mensa-filters.ts
Normal file
28
frontend/app/src/app/modules/dashboard/mensa-filters.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 {SCBuildingCategories, SCThings, SCThingWithCategories} from '@openstapps/core';
|
||||
|
||||
const mensaCategories = new Set<SCBuildingCategories>(['canteen', 'cafe', 'student canteen', 'restaurant']);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export function isMensaThing(item: SCThings): boolean {
|
||||
return (
|
||||
(item as SCThingWithCategories<string, never>).categories?.some(category =>
|
||||
mensaCategories.has(category as never),
|
||||
) || false
|
||||
);
|
||||
}
|
||||
@@ -17,9 +17,9 @@
|
||||
<ion-button slot="button-end" fill="clear" color="medium" [routerLink]="['/favorites']">
|
||||
<ion-icon slot="icon-only" name="search" size="24"></ion-icon>
|
||||
</ion-button>
|
||||
<simple-swiper *ngIf="(items | async)?.length; else noItems">
|
||||
<simple-swiper *ngIf="items | async as items; else noItems" @fade>
|
||||
<stapps-data-list-item
|
||||
*ngFor="let item of items | async"
|
||||
*ngFor="let item of items"
|
||||
[hideThumbnail]="true"
|
||||
[favoriteButton]="false"
|
||||
[item]="item"
|
||||
|
||||
@@ -12,22 +12,11 @@
|
||||
* 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 {Component, OnInit} from '@angular/core';
|
||||
import {ActivatedRoute, Router} from '@angular/router';
|
||||
import {AlertController, AnimationController} from '@ionic/angular';
|
||||
import {combineLatest} from 'rxjs';
|
||||
import {debounceTime, distinctUntilChanged, startWith, take} from 'rxjs/operators';
|
||||
import {NGXLogger} from 'ngx-logger';
|
||||
import {SCThings} from '@openstapps/core';
|
||||
|
||||
import {DataProvider} from '../../../data/data.provider';
|
||||
import {DataRoutingService} from '../../../data/data-routing.service';
|
||||
import {SearchPageComponent} from '../../../data/list/search-page.component';
|
||||
import {PositionService} from '../../../map/position.service';
|
||||
import {SettingsProvider} from '../../../settings/settings.provider';
|
||||
import {ChangeDetectionStrategy, Component} from '@angular/core';
|
||||
import {filter, map} from 'rxjs/operators';
|
||||
import {FavoritesService} from '../../../favorites/favorites.service';
|
||||
import {ContextMenuService} from '../../../menu/context/context-menu.service';
|
||||
import {ConfigProvider} from '../../../config/config.provider';
|
||||
import {fadeAnimation} from '../../fade.animation';
|
||||
import {isMensaThing} from '../../mensa-filters';
|
||||
|
||||
/**
|
||||
* Shows a section with meals of the chosen mensa
|
||||
@@ -36,95 +25,14 @@ import {ConfigProvider} from '../../../config/config.provider';
|
||||
selector: 'stapps-favorites-section',
|
||||
templateUrl: 'favorites-section.component.html',
|
||||
styleUrls: ['favorites-section.component.scss'],
|
||||
animations: [fadeAnimation],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class FavoritesSectionComponent extends SearchPageComponent implements OnInit {
|
||||
constructor(
|
||||
protected readonly alertController: AlertController,
|
||||
protected dataProvider: DataProvider,
|
||||
protected readonly contextMenuService: ContextMenuService,
|
||||
protected readonly settingsProvider: SettingsProvider,
|
||||
protected readonly logger: NGXLogger,
|
||||
protected dataRoutingService: DataRoutingService,
|
||||
protected router: Router,
|
||||
route: ActivatedRoute,
|
||||
positionService: PositionService,
|
||||
private favoritesService: FavoritesService,
|
||||
configProvider: ConfigProvider,
|
||||
animationController: AnimationController,
|
||||
) {
|
||||
super(
|
||||
alertController,
|
||||
dataProvider,
|
||||
contextMenuService,
|
||||
settingsProvider,
|
||||
logger,
|
||||
dataRoutingService,
|
||||
router,
|
||||
route,
|
||||
positionService,
|
||||
configProvider,
|
||||
animationController,
|
||||
);
|
||||
}
|
||||
export class FavoritesSectionComponent {
|
||||
items = this.favoritesService.favoriteThings$.pipe(
|
||||
map(favorites => favorites.filter(it => !isMensaThing(it))),
|
||||
filter(favorites => favorites.length > 0),
|
||||
);
|
||||
|
||||
async initialize() {
|
||||
this.subscriptions.push(
|
||||
combineLatest([
|
||||
this.queryTextChanged.pipe(
|
||||
debounceTime(this.searchQueryDueTime),
|
||||
distinctUntilChanged(),
|
||||
startWith(this.queryText),
|
||||
),
|
||||
this.favoritesService.favoritesChanged$,
|
||||
]).subscribe(async () => {
|
||||
await this.fetchAndUpdateItems();
|
||||
this.queryChanged.next();
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches/updates the favorites (search page component's method override)
|
||||
*/
|
||||
async fetchAndUpdateItems() {
|
||||
this.favoritesService
|
||||
.search(this.queryText, this.filterQuery, this.sortQuery)
|
||||
.pipe(take(1))
|
||||
.subscribe(result => {
|
||||
this.items = new Promise(resolve => {
|
||||
resolve(result.data && result.data.filter(item => !this.isMensaThing(item)));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function as 'typeof' is not accessible in HTML
|
||||
*
|
||||
* @param item TODO
|
||||
*/
|
||||
isMensaThing(item: SCThings): boolean {
|
||||
return (
|
||||
this.hasCategories(item) &&
|
||||
((item.categories as string[]).includes('canteen') ||
|
||||
(item.categories as string[]).includes('cafe') ||
|
||||
(item.categories as string[]).includes('student canteen') ||
|
||||
(item.categories as string[]).includes('restaurant'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @param item TODO
|
||||
*/
|
||||
hasCategories(item: SCThings): item is SCThings & {categories: string[]} {
|
||||
return typeof (item as {categories: string[]}).categories !== 'undefined';
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit event that an item was selected
|
||||
*/
|
||||
notifySelect(item: SCThings) {
|
||||
this.dataRoutingService.emitChildEvent(item);
|
||||
}
|
||||
constructor(private favoritesService: FavoritesService) {}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
* 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 {Component, Input} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
|
||||
import {SCDish, SCPlace, SCThings} from '@openstapps/core';
|
||||
import {PlaceMensaService} from '../../../data/types/place/special/mensa/place-mensa-service';
|
||||
import {animate, style, transition, trigger} from '@angular/animations';
|
||||
import moment from 'moment';
|
||||
import {fadeAnimation} from '../../fade.animation';
|
||||
|
||||
/**
|
||||
* Shows a section with meals of the chosen mensa
|
||||
@@ -25,11 +25,8 @@ import moment from 'moment';
|
||||
selector: 'stapps-mensa-section-content',
|
||||
templateUrl: 'mensa-section-content.component.html',
|
||||
styleUrls: ['mensa-section-content.component.scss'],
|
||||
animations: [
|
||||
trigger('fade', [
|
||||
transition(':enter', [style({opacity: '0'}), animate('500ms ease', style({opacity: '1'}))]),
|
||||
]),
|
||||
],
|
||||
animations: [fadeAnimation],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class MensaSectionContentComponent {
|
||||
/**
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<ion-item class="nothing-selected" lines="none">
|
||||
<ion-label class="ion-text-wrap">
|
||||
{{ 'dashboard.canteens.no_favorite_prefix' | translate }}
|
||||
<a (click)="onSectionEdit()">{{ 'dashboard.canteens.no_favorite_link' | translate }}</a>
|
||||
<a [routerLink]="['/canteen']">{{ 'dashboard.canteens.no_favorite_link' | translate }}</a>
|
||||
{{ 'dashboard.canteens.no_favorite_suffix' | translate }}
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
@@ -12,23 +12,11 @@
|
||||
* 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 {Component} from '@angular/core';
|
||||
import {ActivatedRoute, Router} from '@angular/router';
|
||||
import {AlertController, AnimationController, ModalController} from '@ionic/angular';
|
||||
import {combineLatest, Subscription} from 'rxjs';
|
||||
import {debounceTime, distinctUntilChanged, startWith, take} from 'rxjs/operators';
|
||||
import {NGXLogger} from 'ngx-logger';
|
||||
import {SCThings} from '@openstapps/core';
|
||||
|
||||
import {DataProvider} from '../../../data/data.provider';
|
||||
import {DataRoutingService} from '../../../data/data-routing.service';
|
||||
import {FoodDataListComponent} from '../../../data/list/food-data-list.component';
|
||||
import {PositionService} from '../../../map/position.service';
|
||||
import {SettingsProvider} from '../../../settings/settings.provider';
|
||||
import {ChangeDetectionStrategy, Component} from '@angular/core';
|
||||
import {map} from 'rxjs/operators';
|
||||
import {FavoritesService} from '../../../favorites/favorites.service';
|
||||
import {ContextMenuService} from '../../../menu/context/context-menu.service';
|
||||
import {ConfigProvider} from '../../../config/config.provider';
|
||||
import {animate, style, transition, trigger} from '@angular/animations';
|
||||
import {fadeAnimation} from '../../fade.animation';
|
||||
import {isMensaThing} from '../../mensa-filters';
|
||||
|
||||
/**
|
||||
* Shows a section with meals of the chosen mensa
|
||||
@@ -37,107 +25,11 @@ import {animate, style, transition, trigger} from '@angular/animations';
|
||||
selector: 'stapps-mensa-section',
|
||||
templateUrl: 'mensa-section.component.html',
|
||||
styleUrls: ['mensa-section.component.scss'],
|
||||
animations: [
|
||||
trigger('fade', [transition(':enter', [style({opacity: '0'}), animate(250, style({opacity: '1'}))])]),
|
||||
],
|
||||
animations: [fadeAnimation],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class MensaSectionComponent extends FoodDataListComponent {
|
||||
sub: Subscription;
|
||||
export class MensaSectionComponent {
|
||||
items = this.favoritesService.favoriteThings$.pipe(map(favorites => favorites.filter(isMensaThing)));
|
||||
|
||||
constructor(
|
||||
protected readonly alertController: AlertController,
|
||||
protected dataProvider: DataProvider,
|
||||
protected readonly contextMenuService: ContextMenuService,
|
||||
protected readonly settingsProvider: SettingsProvider,
|
||||
protected readonly logger: NGXLogger,
|
||||
protected dataRoutingService: DataRoutingService,
|
||||
protected router: Router,
|
||||
route: ActivatedRoute,
|
||||
protected positionService: PositionService,
|
||||
public modalController: ModalController,
|
||||
protected favoritesService: FavoritesService,
|
||||
configProvider: ConfigProvider,
|
||||
animationController: AnimationController,
|
||||
) {
|
||||
super(
|
||||
alertController,
|
||||
dataProvider,
|
||||
contextMenuService,
|
||||
settingsProvider,
|
||||
logger,
|
||||
dataRoutingService,
|
||||
router,
|
||||
route,
|
||||
positionService,
|
||||
configProvider,
|
||||
animationController,
|
||||
);
|
||||
}
|
||||
|
||||
async initialize() {
|
||||
super.initialize();
|
||||
|
||||
this.subscriptions.push(
|
||||
combineLatest([
|
||||
this.queryTextChanged.pipe(
|
||||
debounceTime(this.searchQueryDueTime),
|
||||
distinctUntilChanged(),
|
||||
startWith(this.queryText),
|
||||
),
|
||||
this.favoritesService.favoritesChanged$,
|
||||
]).subscribe(async query => {
|
||||
this.queryText = query[0];
|
||||
this.from = 0;
|
||||
if (typeof this.filterQuery !== 'undefined' || this.queryText?.length > 0 || this.showDefaultData) {
|
||||
await this.fetchAndUpdateItems();
|
||||
this.queryChanged.next();
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches/updates the favorites (search page component's method override)
|
||||
*/
|
||||
async fetchAndUpdateItems() {
|
||||
this.favoritesService
|
||||
.search(this.queryText, this.filterQuery, this.sortQuery)
|
||||
.pipe(take(1))
|
||||
.subscribe(result => {
|
||||
this.items = new Promise(resolve => {
|
||||
resolve(result.data && result.data.filter(item => this.isMensaThing(item)));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function as 'typeof' is not accessible in HTML
|
||||
*
|
||||
* @param item TODO
|
||||
*/
|
||||
isMensaThing(item: SCThings): boolean {
|
||||
return (
|
||||
this.hasCategories(item) &&
|
||||
((item.categories as string[]).includes('canteen') ||
|
||||
(item.categories as string[]).includes('cafe') ||
|
||||
(item.categories as string[]).includes('student canteen') ||
|
||||
(item.categories as string[]).includes('restaurant'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @param item TODO
|
||||
*/
|
||||
hasCategories(item: SCThings): item is SCThings & {categories: string[]} {
|
||||
return typeof (item as {categories: string[]}).categories !== 'undefined';
|
||||
}
|
||||
|
||||
/**
|
||||
* Action when user clicked edit to this section
|
||||
*/
|
||||
onSectionEdit() {
|
||||
void this.router.navigate(['/canteen']);
|
||||
}
|
||||
constructor(protected favoritesService: FavoritesService) {}
|
||||
}
|
||||
|
||||
@@ -13,12 +13,36 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
<<<<<<<< HEAD:frontend/app/src/app/modules/data/list/data-list-item.scss
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
ion-item::part(native) {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ion-text-wrap ::ng-deep ion-label {
|
||||
white-space: normal !important;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3;
|
||||
}
|
||||
|
||||
ion-item {
|
||||
--border-color: transparent;
|
||||
@include border-radius-in-parallax(var(--border-radius-default));
|
||||
overflow: hidden;
|
||||
--inner-padding-end: 0;
|
||||
--padding-start: var(--spacing-sm);
|
||||
margin: var(--spacing-sm);
|
||||
========
|
||||
simple-swiper {
|
||||
--swiper-slide-width: 256px;
|
||||
}
|
||||
>>>>>>>> app/develop:frontend/app/src/app/modules/dashboard/sections/news-section/news-section.component.scss
|
||||
|
||||
.more-news {
|
||||
width: 128px;
|
||||
font-size: var(--font-size-xl);
|
||||
--color: var(--ion-color-medium-tint);
|
||||
|
||||
@@ -43,3 +67,43 @@ simple-swiper {
|
||||
width: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
:host.square ::ng-deep {
|
||||
ion-item {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
ion-row {
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
ion-col {
|
||||
flex-grow: 0;
|
||||
flex-basis: min-content;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: -webkit-box;
|
||||
white-space: break-spaces;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.title-sub {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// fix for Safari
|
||||
stapps-offers-in-list {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
stapps-offers-in-list .place {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,9 @@
|
||||
* 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 {Component} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component} from '@angular/core';
|
||||
import {NewsProvider} from '../../../news/news.provider';
|
||||
import {SCMessage} from '@openstapps/core';
|
||||
import {animate, style, transition, trigger} from '@angular/animations';
|
||||
import {Router} from '@angular/router';
|
||||
import {fadeAnimation} from '../../fade.animation';
|
||||
|
||||
/**
|
||||
* Shows a section with news
|
||||
@@ -25,21 +23,14 @@ import {Router} from '@angular/router';
|
||||
selector: 'stapps-news-section',
|
||||
templateUrl: 'news-section.component.html',
|
||||
styleUrls: ['news-section.component.scss'],
|
||||
animations: [
|
||||
trigger('fade', [
|
||||
transition(':enter', [
|
||||
style({opacity: '0', transform: 'translateX(100px)'}),
|
||||
animate('250ms ease', style({opacity: '1', transform: 'translateX(0)'})),
|
||||
]),
|
||||
]),
|
||||
],
|
||||
animations: [fadeAnimation],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class NewsSectionComponent {
|
||||
news: Promise<SCMessage[]>;
|
||||
news = this.newsProvider
|
||||
.getCurrentFilters()
|
||||
// eslint-disable-next-line unicorn/prefer-top-level-await,unicorn/consistent-function-scoping
|
||||
.then(filters => this.newsProvider.getList(5, 0, filters));
|
||||
|
||||
constructor(readonly newsProvider: NewsProvider, readonly router: Router) {
|
||||
this.news = this.newsProvider
|
||||
.getCurrentFilters()
|
||||
.then(filters => this.newsProvider.getList(5, 0, filters));
|
||||
}
|
||||
constructor(readonly newsProvider: NewsProvider) {}
|
||||
}
|
||||
|
||||
@@ -13,12 +13,24 @@
|
||||
~ this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<<<<<<<< HEAD:frontend/app/src/app/modules/data/list/data-list-item-host-default.html
|
||||
<h2>
|
||||
{{ 'name' | thingTranslate: item }}
|
||||
</h2>
|
||||
<p *ngIf="item.description">
|
||||
<stapps-long-inline-text
|
||||
[text]="'description' | thingTranslate: item"
|
||||
[size]="80"
|
||||
></stapps-long-inline-text>
|
||||
</p>
|
||||
========
|
||||
<stapps-section title="{{ 'dashboard.navigation.item.search' | translate }}">
|
||||
<ion-searchbar
|
||||
[routerLink]="'/search'"
|
||||
[routerLink]="['/search']"
|
||||
[routerAnimation]="routeTransition"
|
||||
class="stapps-searchbar ion-activatable ripple-parent"
|
||||
>
|
||||
<ion-ripple-effect></ion-ripple-effect>
|
||||
</ion-searchbar>
|
||||
</stapps-section>
|
||||
>>>>>>>> app/develop:frontend/app/src/app/modules/dashboard/sections/search-section/search-section.component.html
|
||||
|
||||
@@ -13,10 +13,7 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Component} from '@angular/core';
|
||||
import {Router} from '@angular/router';
|
||||
import {Capacitor} from '@capacitor/core';
|
||||
import {Keyboard} from '@capacitor/keyboard';
|
||||
import {AnimationBuilder, AnimationController} from '@ionic/angular';
|
||||
import {AnimationController} from '@ionic/angular';
|
||||
import {homePageSearchTransition} from './search-route-transition';
|
||||
|
||||
/**
|
||||
@@ -28,29 +25,7 @@ import {homePageSearchTransition} from './search-route-transition';
|
||||
styleUrls: ['search-section.component.scss'],
|
||||
})
|
||||
export class SearchSectionComponent {
|
||||
searchTerm = '';
|
||||
routeTransition = homePageSearchTransition(this.animationController);
|
||||
|
||||
routeTransition: AnimationBuilder;
|
||||
|
||||
constructor(private router: Router, private animationController: AnimationController) {
|
||||
this.routeTransition = homePageSearchTransition(this.animationController);
|
||||
}
|
||||
|
||||
/**
|
||||
* User submits search
|
||||
*/
|
||||
onSubmitSearch() {
|
||||
this.router
|
||||
.navigate(['/search'], {queryParams: {query: this.searchTerm}})
|
||||
.then(() => this.hideKeyboard());
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides keyboard in native app environments
|
||||
*/
|
||||
hideKeyboard() {
|
||||
if (Capacitor.isNativePlatform()) {
|
||||
Keyboard.hide();
|
||||
}
|
||||
}
|
||||
constructor(private animationController: AnimationController) {}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
~ Copyright (C) 2022 StApps
|
||||
~ Copyright (C) 2023 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.
|
||||
@@ -26,14 +26,12 @@
|
||||
<ion-label>{{ label | translate }}</ion-label>
|
||||
<stapps-edit-modal #editModal (save)="selection.save()">
|
||||
<ng-template>
|
||||
<ion-content class="ion-padding modal-content">
|
||||
<div>
|
||||
<stapps-edit-event-selection
|
||||
#selection
|
||||
[items]="associatedDateSeries"
|
||||
(modified)="editModal.pendingChanges = true"
|
||||
></stapps-edit-event-selection>
|
||||
</div>
|
||||
<ion-content parallax [parallaxSize]="160" class="ion-padding modal-content">
|
||||
<stapps-edit-event-selection
|
||||
#selection
|
||||
[items]="associatedDateSeries"
|
||||
(modified)="editModal.pendingChanges = true"
|
||||
></stapps-edit-event-selection>
|
||||
</ion-content>
|
||||
<ion-footer mode="ios">
|
||||
<ion-toolbar color="light">
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
* 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 'src/theme/common/ion-content-parallax';
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
padding: var(--spacing-sm);
|
||||
@@ -35,10 +33,7 @@
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
--background: var(--ion-color-primary);
|
||||
--color: var(--ion-color-primary-contrast);
|
||||
|
||||
@include ion-content-parallax($content-size: 160px);
|
||||
}
|
||||
|
||||
ion-footer > ion-toolbar {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
~ Copyright (C) 2022 StApps
|
||||
~ Copyright (C) 2023 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.
|
||||
@@ -38,20 +38,39 @@
|
||||
*ngFor="let date of frequency.children"
|
||||
(click)="modified.emit(); date.selected = !date.selected; frequency.notifyChildChanged()"
|
||||
>
|
||||
<ion-label *ngIf="date.item.dates.length > 1; else single_event" class="ion-text-wrap">
|
||||
{{ date.item.duration | amDuration: 'hours' }}
|
||||
{{ 'data.chips.add_events.popover.AT' | translate }}
|
||||
{{ date.item.dates[0] | amDateFormat: 'HH:mm ddd' }}
|
||||
{{ 'data.chips.add_events.popover.UNTIL' | translate }}
|
||||
{{ date.item.dates[date.item.dates.length - 1] | amDateFormat: 'll' }}
|
||||
<ion-label>
|
||||
<ng-container *ngIf="date.item.dates.length > 1; else single_event">
|
||||
<ion-text>
|
||||
{{ date.item.dates[0] | amDateFormat: 'dddd, LT' }} -
|
||||
{{ date.item.dates[0] | amAdd: date.item.duration | amDateFormat: 'LT' }}
|
||||
</ion-text>
|
||||
<br />
|
||||
<ion-text>
|
||||
{{ date.item.dates[0] | amDateFormat: 'LL' }} -
|
||||
{{ date.item.dates[date.item.dates.length - 1] | amDateFormat: 'LL' }}
|
||||
</ion-text>
|
||||
</ng-container>
|
||||
<ng-template #single_event>
|
||||
<ion-text *ngIf="date.item.dates[0] as time; else noDates">
|
||||
{{ time | amDateFormat: 'LL, LT' }} -
|
||||
{{ time | amAdd: date.item.duration | amDateFormat: 'LT' }}
|
||||
</ion-text>
|
||||
<ng-template #noDates>
|
||||
<ion-text color="danger">{{ 'data.chips.add_events.popover.DATA_ERROR' | translate }}</ion-text>
|
||||
<br />
|
||||
<ion-text *ngFor="let id of date.item.identifiers | keyvalue">
|
||||
{{ id.key }}: {{ id.value }}
|
||||
</ion-text>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
<ng-container class="ion-align-items-center" *ngIf="date.item.inPlace">
|
||||
<br />
|
||||
<ion-text color="medium" class="place">
|
||||
<ion-icon name="pin_drop"></ion-icon>
|
||||
<span> {{ 'inPlace.name' | thingTranslate: date.item }}</span>
|
||||
</ion-text>
|
||||
</ng-container>
|
||||
</ion-label>
|
||||
<ng-template #single_event>
|
||||
<ion-label class="ion-text-wrap">
|
||||
{{ date.item.duration | amDuration: 'hours' }}
|
||||
{{ 'data.chips.add_events.popover.AT' | translate }}
|
||||
{{ date.item.dates[date.item.dates.length - 1] | amDateFormat: 'll, HH:mm' }}
|
||||
</ion-label>
|
||||
</ng-template>
|
||||
<ion-checkbox slot="end" [checked]="date.selected"> </ion-checkbox>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*!
|
||||
* Copyright (C) 2022 StApps
|
||||
* Copyright (C) 2023 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.
|
||||
@@ -42,3 +42,8 @@ ion-item-divider.ios > ion-checkbox {
|
||||
ion-list.md {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.place {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@@ -95,10 +95,11 @@ import {BookDetailContentComponent} from './types/book/book-detail-content.compo
|
||||
import {BookListItemComponent} from './types/book/book-list-item.component';
|
||||
import {PeriodicalListItemComponent} from './types/periodical/periodical-list-item.component';
|
||||
import {PeriodicalDetailContentComponent} from './types/periodical/periodical-detail-content.component';
|
||||
import {SCThingListItemVirtualScrollStrategyDirective} from './list/sc-thing-list-item-virtual-scroll-strategy.directive';
|
||||
import {DataListItemHostDirective} from './list/data-list-item-host.directive';
|
||||
import {DataListItemHostDefaultComponent} from './list/data-list-item-host-default.component';
|
||||
import {browserFactory, SimpleBrowser} from '../../util/browser.factory';
|
||||
import {DishCharacteristicsComponent} from './types/dish/dish-characteristics.component';
|
||||
import {SkeletonListComponent} from './list/skeleton-list.component';
|
||||
|
||||
/**
|
||||
* Module for handling data
|
||||
@@ -111,6 +112,7 @@ import {browserFactory, SimpleBrowser} from '../../util/browser.factory';
|
||||
AddressDetailComponent,
|
||||
CatalogDetailContentComponent,
|
||||
CatalogListItemComponent,
|
||||
DishCharacteristicsComponent,
|
||||
DataDetailComponent,
|
||||
DataDetailContentComponent,
|
||||
DataIconPipe,
|
||||
@@ -126,6 +128,7 @@ import {browserFactory, SimpleBrowser} from '../../util/browser.factory';
|
||||
EventListItemComponent,
|
||||
FavoriteButtonComponent,
|
||||
FavoriteDetailContentComponent,
|
||||
SkeletonListComponent,
|
||||
FavoriteListItemComponent,
|
||||
FoodDataListComponent,
|
||||
LocateActionChipComponent,
|
||||
@@ -145,7 +148,6 @@ import {browserFactory, SimpleBrowser} from '../../util/browser.factory';
|
||||
PlaceListItemComponent,
|
||||
PlaceMensaDetailComponent,
|
||||
SearchPageComponent,
|
||||
SCThingListItemVirtualScrollStrategyDirective,
|
||||
SemesterDetailContentComponent,
|
||||
SemesterListItemComponent,
|
||||
DataListItemHostDirective,
|
||||
@@ -207,7 +209,6 @@ import {browserFactory, SimpleBrowser} from '../../util/browser.factory';
|
||||
},
|
||||
],
|
||||
exports: [
|
||||
SCThingListItemVirtualScrollStrategyDirective,
|
||||
DataDetailComponent,
|
||||
DataDetailContentComponent,
|
||||
DataIconPipe,
|
||||
|
||||
@@ -38,7 +38,7 @@ stapps-origin-detail {
|
||||
position: relative;
|
||||
margin-block-start: calc((var(--header-spacing-bottom) - var(--spacing-xl)) * -1);
|
||||
margin-block-end: var(--spacing-xl);
|
||||
background-color: var(--ion-color-primary-contrast);
|
||||
background-color: var(--ion-card-background);
|
||||
@include content-padding();
|
||||
|
||||
& > ion-thumbnail {
|
||||
@@ -73,7 +73,6 @@ stapps-origin-detail {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
ion-card-header {
|
||||
color: var(--ion-color-dark);
|
||||
padding-top: 8px;
|
||||
padding-bottom: 4px;
|
||||
font-weight: bold;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
~ Copyright (C) 2022 StApps
|
||||
~ Copyright (C) 2023 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.
|
||||
@@ -30,8 +30,8 @@
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ng-content select="[header]"></ng-content>
|
||||
<ion-content class="ion-no-padding ion-content-parallax">
|
||||
<div [ngSwitch]="true">
|
||||
<ion-content parallax class="ion-no-padding">
|
||||
<ng-container [ngSwitch]="true">
|
||||
<ng-container *ngSwitchCase="!item && (isDisconnected | async)">
|
||||
<div class="centeredMessageContainer">
|
||||
<ion-icon name="signal_disconnected"></ion-icon>
|
||||
@@ -59,5 +59,5 @@
|
||||
[contentTemplateRef]="contentTemplateRef"
|
||||
></stapps-data-detail-content>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ion-content>
|
||||
|
||||
@@ -12,10 +12,21 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.crumb-label {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
ion-breadcrumb {
|
||||
color: var(--ion-color-primary-contrast);
|
||||
|
||||
&::part(separator) {
|
||||
color: var(--ion-color-primary-contrast);
|
||||
}
|
||||
|
||||
&::part(collapsed-indicator) {
|
||||
background: var(--ion-color-primary-contrast);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +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.
|
||||
~ Copyright (C) 2023 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.
|
||||
~ 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/>.
|
||||
~ You should have received a copy of the GNU General Public License along with
|
||||
~ this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<<<<<<<< HEAD:frontend/app/src/app/modules/dashboard/sections/search-section/search-section.component.html
|
||||
<stapps-section title="{{ 'dashboard.navigation.item.search' | translate }}">
|
||||
<ion-searchbar
|
||||
[routerLink]="'/search'"
|
||||
[routerAnimation]="routeTransition"
|
||||
class="stapps-searchbar ion-activatable ripple-parent"
|
||||
>
|
||||
<ion-ripple-effect></ion-ripple-effect>
|
||||
</ion-searchbar>
|
||||
</stapps-section>
|
||||
========
|
||||
<ion-button (click)="toggle($event)" color="medium" size="small" fill="clear">
|
||||
<ion-icon
|
||||
slot="icon-only"
|
||||
@@ -21,3 +32,4 @@
|
||||
name="grade"
|
||||
></ion-icon>
|
||||
</ion-button>
|
||||
>>>>>>>> app/develop:frontend/app/src/app/modules/data/elements/favorite-button.component.html
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*!
|
||||
* Copyright (C) 2022 StApps
|
||||
* Copyright (C) 2023 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.
|
||||
@@ -27,6 +27,7 @@
|
||||
}
|
||||
|
||||
.selected {
|
||||
// TODO
|
||||
color: #fbc02d;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,17 +14,17 @@
|
||||
-->
|
||||
|
||||
<div>
|
||||
<ion-text *ngIf="price && !soldOut">
|
||||
<ion-text *ngIf="price && !soldOut" style="white-space: nowrap">
|
||||
<h2>
|
||||
{{ price | currency: 'EUR':'symbol':undefined:'de' }}
|
||||
</h2>
|
||||
</ion-text>
|
||||
<ion-text *ngIf="soldOut" color="danger">
|
||||
<ion-text *ngIf="soldOut" color="danger" class="sold-out" style="white-space: nowrap">
|
||||
<h2>
|
||||
{{ 'data.detail.offers.sold_out' | translate }}
|
||||
</h2>
|
||||
</ion-text>
|
||||
<p *ngIf="_offers[0].inPlace && !soldOut" class="place">
|
||||
<p *ngIf="_offers[0].inPlace && !soldOut" class="place" style="white-space: nowrap">
|
||||
<ion-icon name="pin_drop"></ion-icon>{{ _offers[0].inPlace.name
|
||||
}}<span *ngIf="_offers.length > 1">...</span>
|
||||
</p>
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
<ion-button
|
||||
expand="full"
|
||||
fill="clear"
|
||||
color="light"
|
||||
*ngIf="item.description && buttonShown"
|
||||
(click)="toggleDescriptionAccordion()"
|
||||
>
|
||||
|
||||
@@ -39,10 +39,14 @@ ion-card {
|
||||
padding: 0 0 var(--header-spacing-bottom);
|
||||
|
||||
.description * {
|
||||
color: var(--ion-color-light);
|
||||
color: var(--ion-color-primary-contrast);
|
||||
}
|
||||
.openingHours {
|
||||
color: var(--ion-color-light);
|
||||
color: var(--ion-color-primary-contrast);
|
||||
}
|
||||
}
|
||||
|
||||
ion-button {
|
||||
--color: var(--ion-color-primary-contrast);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,19 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
<<<<<<<< HEAD:frontend/app/src/app/util/simple-swiper.component.ts
|
||||
import {Component, ContentChildren, ElementRef, ViewContainerRef} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'simple-swiper',
|
||||
templateUrl: 'simple-swiper.html',
|
||||
styleUrls: ['simple-swiper.scss'],
|
||||
})
|
||||
export class SimpleSwiperComponent {
|
||||
constructor(readonly viewContainerRef: ViewContainerRef) {}
|
||||
|
||||
@ContentChildren('*') children: ElementRef<unknown>;
|
||||
========
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {SCThings} from '@openstapps/core';
|
||||
|
||||
@@ -22,4 +35,5 @@ import {SCThings} from '@openstapps/core';
|
||||
})
|
||||
export class DataListItemHostDefaultComponent {
|
||||
@Input() item: SCThings;
|
||||
>>>>>>>> app/develop:frontend/app/src/app/modules/data/list/data-list-item-host-default.component.ts
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
@import 'src/theme/util/_mixins.scss';
|
||||
@import 'src/theme/common/_helper.scss';
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
@@ -44,17 +43,13 @@ ion-item {
|
||||
|
||||
ion-label {
|
||||
width: 100%;
|
||||
margin-right: 0;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
::ng-deep {
|
||||
ion-note {
|
||||
@extend %horizontal-list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:host.square ::ng-deep {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* Copyright (C) 2023 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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 {CdkVirtualScrollViewport} from '@angular/cdk/scrolling';
|
||||
import {
|
||||
Component,
|
||||
ContentChild,
|
||||
@@ -29,6 +28,7 @@ import {
|
||||
} from '@angular/core';
|
||||
import {SCThings} from '@openstapps/core';
|
||||
import {BehaviorSubject, Observable, Subscription} from 'rxjs';
|
||||
import {IonInfiniteScroll} from '@ionic/angular';
|
||||
|
||||
export interface DataListContext<T> {
|
||||
$implicit: T;
|
||||
@@ -43,11 +43,6 @@ export interface DataListContext<T> {
|
||||
styleUrls: ['data-list.scss'],
|
||||
})
|
||||
export class DataListComponent implements OnChanges, OnInit, OnDestroy {
|
||||
/**
|
||||
* Amount of list items left to show (in percent) that should trigger a data reload
|
||||
*/
|
||||
private readonly reloadThreshold = 0.2;
|
||||
|
||||
/**
|
||||
* All SCThings to display
|
||||
*/
|
||||
@@ -86,7 +81,7 @@ export class DataListComponent implements OnChanges, OnInit, OnDestroy {
|
||||
*/
|
||||
subscriptions: Subscription[] = [];
|
||||
|
||||
@ViewChild(CdkVirtualScrollViewport) viewPort: CdkVirtualScrollViewport;
|
||||
@ViewChild(IonInfiniteScroll) infiniteScroll: IonInfiniteScroll;
|
||||
|
||||
/**
|
||||
* Signalizes that the data is being loaded
|
||||
@@ -113,6 +108,7 @@ export class DataListComponent implements OnChanges, OnInit, OnDestroy {
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (Array.isArray(this.items) && typeof changes.items !== 'undefined') {
|
||||
this.itemStream.next(this.items);
|
||||
this.infiniteScroll.complete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +123,7 @@ export class DataListComponent implements OnChanges, OnInit, OnDestroy {
|
||||
if (typeof this.resetToTop !== 'undefined') {
|
||||
this.subscriptions.push(
|
||||
this.resetToTop.subscribe(() => {
|
||||
this.viewPort.scrollToIndex(0);
|
||||
// this.viewPort.scrollToIndex(0);
|
||||
}),
|
||||
);
|
||||
}
|
||||
@@ -139,18 +135,4 @@ export class DataListComponent implements OnChanges, OnInit, OnDestroy {
|
||||
notifyLoadMore() {
|
||||
this.loadMore.emit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to call whenever scroll view visible range changed
|
||||
*/
|
||||
scrolled(index: number) {
|
||||
if (
|
||||
// first condition prevents "load more" to be executed even before scrolling
|
||||
index > 0 &&
|
||||
(this.items?.length ?? 0) - this.viewPort.getRenderedRange().end <=
|
||||
(this.items?.length ?? 0) * this.reloadThreshold
|
||||
) {
|
||||
this.notifyLoadMore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,29 +15,23 @@
|
||||
|
||||
<ng-container *ngIf="itemStream | async as items">
|
||||
<ng-content select="[header]"></ng-content>
|
||||
<cdk-virtual-scroll-viewport
|
||||
scThingListItemVirtualScrollStrategy
|
||||
[style.display]="items && items.length ? 'block' : 'none'"
|
||||
(loadMore)="notifyLoadMore()"
|
||||
>
|
||||
<ng-container *cdkVirtualFor="let item of items; trackBy: identifyItem">
|
||||
<ion-list [style.display]="items && items.length ? 'block' : 'none'">
|
||||
<ng-container *ngFor="let item of items">
|
||||
<ng-container
|
||||
*ngTemplateOutlet="listItemTemplateRef || defaultListItem; context: {$implicit: item}"
|
||||
></ng-container>
|
||||
</ng-container>
|
||||
</cdk-virtual-scroll-viewport>
|
||||
<ion-infinite-scroll (ionInfinite)="notifyLoadMore()">
|
||||
<ion-infinite-scroll-content></ion-infinite-scroll-content>
|
||||
</ion-infinite-scroll>
|
||||
</ion-list>
|
||||
</ng-container>
|
||||
<div [style.display]="!loading && items && items.length === 0 ? 'block' : 'none'">
|
||||
<ion-label class="centeredMessageContainer">
|
||||
{{ 'search.nothing_found' | translate | titlecase }}
|
||||
</ion-label>
|
||||
</div>
|
||||
<ion-list [style.display]="loading ? 'block' : 'none'">
|
||||
<stapps-skeleton-list-item
|
||||
[hideThumbnail]="singleType"
|
||||
*ngFor="let skeleton of [].constructor(skeletonItems)"
|
||||
></stapps-skeleton-list-item>
|
||||
</ion-list>
|
||||
<skeleton-list [style.display]="loading ? 'block' : 'none'"></skeleton-list>
|
||||
|
||||
<ng-template let-item #defaultListItem>
|
||||
<stapps-data-list-item [item]="item" [hideThumbnail]="singleType"></stapps-data-list-item>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*!
|
||||
* Copyright (C) 2022 StApps
|
||||
* Copyright (C) 2023 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.
|
||||
@@ -12,18 +12,14 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
<<<<<<<< HEAD:frontend/app/src/app/modules/settings/item/settings-item.scss
|
||||
========
|
||||
|
||||
cdk-virtual-scroll-viewport {
|
||||
ion-list {
|
||||
background: none;
|
||||
}
|
||||
|
||||
skeleton-list {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
::ng-deep {
|
||||
.cdk-virtual-scroll-content-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.virtual-scroll-expander {
|
||||
clear: both;
|
||||
}
|
||||
>>>>>>>> app/develop:frontend/app/src/app/modules/data/list/data-list.scss
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* Copyright (C) 2023 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.
|
||||
@@ -12,10 +12,11 @@
|
||||
* 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 {Component} from '@angular/core';
|
||||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||
import {MapPosition} from '../../map/position.service';
|
||||
import {SearchPageComponent} from './search-page.component';
|
||||
import {Geolocation} from '@capacitor/geolocation';
|
||||
import {Subscription} from 'rxjs';
|
||||
|
||||
/**
|
||||
* Presents a list of places for eating/drinking
|
||||
@@ -24,15 +25,19 @@ import {Geolocation} from '@capacitor/geolocation';
|
||||
templateUrl: 'search-page.html',
|
||||
styleUrls: ['../../data/list/search-page.scss'],
|
||||
})
|
||||
export class FoodDataListComponent extends SearchPageComponent {
|
||||
export class FoodDataListComponent extends SearchPageComponent implements OnInit, OnDestroy {
|
||||
title = 'canteens.title';
|
||||
|
||||
showNavigation = false;
|
||||
|
||||
locationWatch?: Subscription;
|
||||
|
||||
/**
|
||||
* Sets the forced filter to present only places for eating/drinking
|
||||
*/
|
||||
initialize() {
|
||||
ngOnInit() {
|
||||
this.locationWatch?.unsubscribe();
|
||||
this.locationWatch = this.createLocationWatch();
|
||||
this.showDefaultData = true;
|
||||
|
||||
this.sortQuery = [
|
||||
@@ -92,29 +97,36 @@ export class FoodDataListComponent extends SearchPageComponent {
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
super.ngOnInit();
|
||||
}
|
||||
|
||||
private createLocationWatch(): Subscription {
|
||||
return this.positionService
|
||||
.watchCurrentLocation(this.constructor.name, {enableHighAccuracy: false, maximumAge: 1000})
|
||||
.subscribe({
|
||||
next: (position: MapPosition) => {
|
||||
this.positionService.position = position;
|
||||
},
|
||||
error: async _error => {
|
||||
this.positionService.position = undefined;
|
||||
await Geolocation.checkPermissions();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async ionViewWillEnter() {
|
||||
await super.ionViewWillEnter();
|
||||
this.subscriptions.push(
|
||||
this.positionService
|
||||
.watchCurrentLocation(this.constructor.name, {enableHighAccuracy: false, maximumAge: 1000})
|
||||
.subscribe({
|
||||
next: (position: MapPosition) => {
|
||||
this.positionService.position = position;
|
||||
},
|
||||
error: async _error => {
|
||||
this.positionService.position = undefined;
|
||||
await Geolocation.checkPermissions();
|
||||
},
|
||||
}),
|
||||
);
|
||||
this.locationWatch?.unsubscribe();
|
||||
this.locationWatch = this.createLocationWatch();
|
||||
}
|
||||
|
||||
ionViewWillLeave() {
|
||||
void this.positionService.clearWatcher(this.constructor.name);
|
||||
for (const sub of this.subscriptions) {
|
||||
sub.unsubscribe();
|
||||
}
|
||||
this.locationWatch?.unsubscribe();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
super.ngOnDestroy();
|
||||
this.locationWatch?.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,13 @@ import {searchPageSwitchAnimation} from './search-page-switch-animation';
|
||||
providers: [ContextMenuService],
|
||||
})
|
||||
export class SearchPageComponent implements OnInit, OnDestroy {
|
||||
title = 'search.title';
|
||||
@Input() title = 'search.title';
|
||||
|
||||
@Input() placeholder = 'search.search_bar.placeholder';
|
||||
|
||||
@Input() searchInstruction = 'search.instruction';
|
||||
|
||||
@Input() backUrl?: string;
|
||||
|
||||
isHebisAvailable = false;
|
||||
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
|
||||
<stapps-context contentId="data-list"></stapps-context>
|
||||
<ion-header>
|
||||
<ion-toolbar color="primary" mode="ios" *ngIf="showDrawer">
|
||||
<ion-toolbar color="primary" mode="ios" *ngIf="showDrawer && showTopToolbar">
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button></ion-back-button>
|
||||
<ion-back-button [defaultHref]="backUrl"></ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title>{{ title | translate }}</ion-title>
|
||||
</ion-toolbar>
|
||||
@@ -28,12 +28,12 @@
|
||||
(search)="hideKeyboard()"
|
||||
[(ngModel)]="queryText"
|
||||
showClearButton="always"
|
||||
placeholder="{{ 'search.search_bar.placeholder' | translate }}"
|
||||
placeholder="{{ placeholder | translate }}"
|
||||
mode="md"
|
||||
type="search"
|
||||
enterkeyhint="search"
|
||||
class="filterable"
|
||||
autofocus
|
||||
[autofocus]="!showDefaultData"
|
||||
>
|
||||
<ion-menu-button menu="context" auto-hide="false">
|
||||
<ion-icon name="tune"></ion-icon>
|
||||
@@ -56,9 +56,12 @@
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="content">
|
||||
<div [style.display]="!showDefaultData && !items && !loading ? 'block' : 'none'">
|
||||
<div
|
||||
[class.no-results]="!showDefaultData && !items && !loading"
|
||||
[style.display]="!showDefaultData && !items && !loading ? 'block' : 'none'"
|
||||
>
|
||||
<ion-label class="centeredMessageContainer">
|
||||
{{ 'search.instruction' | translate }}
|
||||
{{ searchInstruction | translate }}
|
||||
</ion-label>
|
||||
</div>
|
||||
<stapps-data-list
|
||||
|
||||
@@ -37,7 +37,7 @@ ion-toolbar:first-of-type {
|
||||
}
|
||||
|
||||
ion-content {
|
||||
--background: var(--ion-color-light);
|
||||
--background: var(--ion-background-color);
|
||||
}
|
||||
|
||||
.content > div {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 {Component, Input} from '@angular/core';
|
||||
import {SCThings} from '@openstapps/core';
|
||||
|
||||
@Component({
|
||||
<<<<<<<< HEAD:frontend/app/src/app/modules/data/list/data-list-item-host-default.component.ts
|
||||
selector: 'data-list-item-host-default',
|
||||
templateUrl: 'data-list-item-host-default.html',
|
||||
})
|
||||
export class DataListItemHostDefaultComponent {
|
||||
@Input() item: SCThings;
|
||||
}
|
||||
========
|
||||
selector: 'skeleton-list',
|
||||
templateUrl: 'skeleton-list.html',
|
||||
styleUrls: ['skeleton-list.scss'],
|
||||
})
|
||||
export class SkeletonListComponent {}
|
||||
>>>>>>>> app/develop:frontend/app/src/app/modules/data/list/skeleton-list.component.ts
|
||||
43
frontend/app/src/app/modules/data/list/skeleton-list.html
Normal file
43
frontend/app/src/app/modules/data/list/skeleton-list.html
Normal file
@@ -0,0 +1,43 @@
|
||||
<!--
|
||||
~ Copyright (C) 2023 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/>.
|
||||
-->
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<pattern id="list-item" width="100%" height="75" patternUnits="userSpaceOnUse">
|
||||
<rect width="100%" height="67" class="item"></rect>
|
||||
<mask id="label-mask">
|
||||
<rect rx="8" x="24" y="24" width="36" height="36" fill="white"></rect>
|
||||
<rect rx="6" x="72" y="24" width="180" height="12" fill="white"></rect>
|
||||
<rect rx="6" x="72" y="48" width="92" height="12" fill="white"></rect>
|
||||
</mask>
|
||||
<g mask="url(#label-mask)">
|
||||
<rect class="label" width="100%" height="100%"></rect>
|
||||
<rect fill="white" width="16" height="100%" style="filter: blur(8px)">
|
||||
<animateTransform
|
||||
attributeName="transform"
|
||||
attributeType="XML"
|
||||
type="translate"
|
||||
from="0 0"
|
||||
to="1000 0"
|
||||
dur="2s"
|
||||
repeatCount="indefinite"
|
||||
></animateTransform>
|
||||
</rect>
|
||||
</g>
|
||||
</pattern>
|
||||
</defs>
|
||||
|
||||
<rect width="100%" height="100%" fill="url(#list-item)"></rect>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
34
frontend/app/src/app/modules/data/list/skeleton-list.scss
Normal file
34
frontend/app/src/app/modules/data/list/skeleton-list.scss
Normal file
@@ -0,0 +1,34 @@
|
||||
/*!
|
||||
* Copyright (C) 2023 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/>.
|
||||
*/
|
||||
svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
$item-height: 92;
|
||||
$gap: 4;
|
||||
|
||||
.label {
|
||||
fill: var(--ion-color-medium);
|
||||
opacity: 0.1;
|
||||
}
|
||||
|
||||
.item {
|
||||
rx: var(--border-radius-default);
|
||||
fill: var(--ion-item-background, var(--ion-background-color, #fff));
|
||||
x: var(--spacing-sm);
|
||||
y: var(--spacing-sm);
|
||||
width: calc(100% - var(--spacing-sm) * 2);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 {Component, Input} from '@angular/core';
|
||||
import {SCDish} from '@openstapps/core';
|
||||
|
||||
@Component({
|
||||
selector: 'stapps-dish-characteristics',
|
||||
templateUrl: 'dish-characteristics.html',
|
||||
styleUrls: ['dish-characteristics.scss'],
|
||||
})
|
||||
export class DishCharacteristicsComponent {
|
||||
@Input() item: SCDish;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
~ Copyright (C) 2022 StApps
|
||||
~ Copyright (C) 2023 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.
|
||||
@@ -12,22 +12,17 @@
|
||||
~ You should have received a copy of the GNU General Public License along with
|
||||
~ this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<ion-toolbar color="primary" mode="ios">
|
||||
<ion-title>{{ 'schedule.addEventModal.addEvent' | translate | titlecase }}</ion-title>
|
||||
<ion-buttons slot="end">
|
||||
<ion-button fill="clear" (click)="modalController.dismiss()">
|
||||
<ion-label>{{ 'modal.DISMISS' | translate }}</ion-label>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
|
||||
<ion-card-content>
|
||||
<stapps-search-page
|
||||
[showDrawer]="false"
|
||||
[forcedFilter]="filter"
|
||||
[itemRouting]="false"
|
||||
[showTopToolbar]="false"
|
||||
[showNavigation]="false"
|
||||
></stapps-search-page>
|
||||
</ion-card-content>
|
||||
<ion-note>
|
||||
<ng-container *ngIf="item.characteristics">
|
||||
<ng-container *ngFor="let characteristic of 'characteristics' | thingTranslate: item">
|
||||
<!-- Abbr tag shows the actual name on hover -->
|
||||
<abbr
|
||||
[style.--background-url]="'url(' + characteristic.image + ')'"
|
||||
[title]="characteristic.name | titlecase"
|
||||
></abbr>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
<ion-label>
|
||||
{{ 'categories' | thingTranslate: item | join: ', ' | titlecase }}
|
||||
</ion-label>
|
||||
</ion-note>
|
||||
@@ -0,0 +1,38 @@
|
||||
/*!
|
||||
* Copyright (C) 2023 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/>.
|
||||
*/
|
||||
ion-note {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
abbr {
|
||||
width: 16px;
|
||||
aspect-ratio: 1;
|
||||
|
||||
background: var(--ion-color-medium);
|
||||
|
||||
mask-image: var(--background-url);
|
||||
mask-repeat: no-repeat;
|
||||
mask-position: center;
|
||||
mask-size: contain;
|
||||
mask-mode: alpha;
|
||||
|
||||
+ ion-label::after {
|
||||
content: '•';
|
||||
margin-inline: var(--spacing-xs);
|
||||
}
|
||||
}
|
||||
@@ -13,31 +13,7 @@
|
||||
~ this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<ion-card *ngIf="item.categories">
|
||||
<ion-card-header>
|
||||
{{ 'categories' | thingTranslate: item | join: ', ' | titlecase }}
|
||||
</ion-card-header>
|
||||
</ion-card>
|
||||
</ion-col>
|
||||
<ion-col>
|
||||
<ion-card *ngIf="item.characteristics">
|
||||
<ion-card-header class="no-padding-inline-start vertical-list">
|
||||
<ul>
|
||||
<li>
|
||||
<ng-container *ngFor="let characteristic of 'characteristics' | thingTranslate: item">
|
||||
<img [src]="characteristic.image" [alt]="characteristic.name | titlecase" />
|
||||
</ng-container>
|
||||
</li>
|
||||
</ul>
|
||||
</ion-card-header>
|
||||
</ion-card>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
|
||||
<stapps-dish-characteristics *ngIf="item.characteristics" [item]="item"></stapps-dish-characteristics>
|
||||
<stapps-offers-detail *ngIf="item.offers" [offers]="item.offers"></stapps-offers-detail>
|
||||
<!-- unwanted by swffm
|
||||
<ion-card *ngIf="item.nutrition">
|
||||
@@ -92,7 +68,7 @@
|
||||
-->
|
||||
<stapps-simple-card
|
||||
*ngIf="item.additives"
|
||||
[title]="'additives' | propertyNameTranslate: item"
|
||||
[title]="$any('additives' | propertyNameTranslate: item) | titlecase"
|
||||
[content]="'additives' | thingTranslate: item | join: ', '"
|
||||
>
|
||||
</stapps-simple-card>
|
||||
|
||||
@@ -12,10 +12,7 @@
|
||||
* 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 'src/theme/common/_helper.scss';
|
||||
.vertical-list {
|
||||
ul li img {
|
||||
filter: unset;
|
||||
}
|
||||
stapps-dish-characteristics {
|
||||
margin: var(--spacing-lg);
|
||||
margin-block-end: var(--spacing-sm);
|
||||
}
|
||||
|
||||
@@ -14,28 +14,17 @@
|
||||
-->
|
||||
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<ion-row class="ion-justify-content-between">
|
||||
<ion-col size="11" size-sm="10">
|
||||
<div class="ion-text-wrap">
|
||||
<ion-label class="title">{{ 'name' | thingTranslate: item }}</ion-label>
|
||||
<p class="title-sub ion-hide-sm-down">
|
||||
{{ 'description' | thingTranslate: item }}
|
||||
</p>
|
||||
<ion-note>
|
||||
<ul>
|
||||
<li>
|
||||
{{ 'categories' | thingTranslate: item | join: ', ' | titlecase }}
|
||||
</li>
|
||||
<li *ngIf="item.characteristics">
|
||||
<ng-container *ngFor="let characteristic of 'characteristics' | thingTranslate: item">
|
||||
<img [src]="characteristic.image" [alt]="characteristic.name | titlecase" />
|
||||
</ng-container>
|
||||
</li>
|
||||
</ul>
|
||||
</ion-note>
|
||||
<stapps-dish-characteristics [item]="item"></stapps-dish-characteristics>
|
||||
</div>
|
||||
</ion-col>
|
||||
<ion-col width-10 text-right>
|
||||
<ion-col>
|
||||
<div class="ion-text-end">
|
||||
<stapps-offers-in-list *ngIf="item.offers" [offers]="item.offers"></stapps-offers-in-list>
|
||||
</div>
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
<p *ngIf="item.academicTerms" class="title-sub">
|
||||
{{ 'name' | thingTranslate: item.academicTerms[0] }}
|
||||
</p>
|
||||
<ion-note *ngIf="!item.categories">{{ 'type' | thingTranslate: item }}</ion-note>
|
||||
<ion-note *ngIf="!item.categories">{{ 'type' | thingTranslate: item | titlecase }}</ion-note>
|
||||
<ion-note *ngIf="item.categories">
|
||||
{{ 'categories' | thingTranslate: item | join: ', ' }}
|
||||
{{ 'categories' | thingTranslate: item | join: ', ' | titlecase }}
|
||||
</ion-note>
|
||||
</div>
|
||||
</ion-col>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
~ Copyright (C) 2022 StApps
|
||||
~ Copyright (C) 2023 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.
|
||||
@@ -40,9 +40,8 @@
|
||||
</div>
|
||||
|
||||
<ng-template #news>
|
||||
<ion-thumbnail>
|
||||
<ion-thumbnail *ngIf="item.image" style="background-image: url('{{ item.image }}')">
|
||||
<ion-img
|
||||
*ngIf="item.image"
|
||||
src="{{ item.image }}"
|
||||
(ionError)="$event.target.nextSibling.style.display = 'none'"
|
||||
alt="{{ item.name }}"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2021 StApps
|
||||
/*!
|
||||
* Copyright (C) 2023 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.
|
||||
@@ -15,17 +15,24 @@
|
||||
|
||||
:host {
|
||||
ion-thumbnail {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
img {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
// Show smaller image on a desktop
|
||||
@media (min-width: 992px) {
|
||||
ion-thumbnail {
|
||||
width: 60%;
|
||||
margin: 0 auto;
|
||||
margin-inline: auto;
|
||||
overflow: hidden;
|
||||
background-size: contain;
|
||||
background-position: center;
|
||||
transform: scaleX(-1);
|
||||
|
||||
ion-img {
|
||||
backdrop-filter: blur(32px);
|
||||
|
||||
&::part(image) {
|
||||
transform: scaleX(-1);
|
||||
max-width: 16cm;
|
||||
object-fit: contain;
|
||||
margin-inline: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* Copyright (C) 2023 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.
|
||||
@@ -12,10 +12,13 @@
|
||||
* 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 {Component, Input, OnInit} from '@angular/core';
|
||||
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
|
||||
import {SCBuilding, SCFloor, SCPointOfInterest, SCRoom, SCThings} from '@openstapps/core';
|
||||
import {DataProvider} from '../../data.provider';
|
||||
import {hasValidLocation, isSCFloor} from './place-types';
|
||||
import {DataRoutingService} from '../../data-routing.service';
|
||||
import {Router} from '@angular/router';
|
||||
import {Subscription} from 'rxjs';
|
||||
|
||||
/**
|
||||
* TODO
|
||||
@@ -26,7 +29,7 @@ import {hasValidLocation, isSCFloor} from './place-types';
|
||||
selector: 'stapps-place-detail-content',
|
||||
templateUrl: 'place-detail-content.html',
|
||||
})
|
||||
export class PlaceDetailContentComponent implements OnInit {
|
||||
export class PlaceDetailContentComponent implements OnInit, OnDestroy {
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
@@ -39,6 +42,8 @@ export class PlaceDetailContentComponent implements OnInit {
|
||||
*/
|
||||
hasValidLocation = false;
|
||||
|
||||
itemRouting: Subscription;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
@@ -63,7 +68,17 @@ export class PlaceDetailContentComponent implements OnInit {
|
||||
);
|
||||
}
|
||||
|
||||
constructor(dataRoutingService: DataRoutingService, router: Router) {
|
||||
this.itemRouting = dataRoutingService.itemSelectListener().subscribe(item => {
|
||||
void router.navigate(['/data-detail', item.uid]);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.hasValidLocation = !isSCFloor(this.item) && hasValidLocation(this.item);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.itemRouting.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +35,7 @@
|
||||
{{ 'inPlace' | propertyNameTranslate: item | titlecase }}
|
||||
</ion-card-header>
|
||||
<ion-card-content>
|
||||
<ion-icon name="pin_drop"></ion-icon>
|
||||
<a [routerLink]="['/data-detail', item.inPlace.uid]">{{ 'name' | thingTranslate: item.inPlace }}</a>
|
||||
<stapps-data-list-item [item]="item.inPlace"></stapps-data-list-item>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
</ng-container>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* Copyright (C) 2023 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.
|
||||
@@ -14,7 +14,7 @@
|
||||
*/
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {PositionService} from '../../../map/position.service';
|
||||
import {Subscription, interval} from 'rxjs';
|
||||
import {interval, Subscription} from 'rxjs';
|
||||
import {hasValidLocation, isSCFloor, PlaceTypes, PlaceTypesWithDistance} from './place-types';
|
||||
|
||||
/**
|
||||
@@ -23,6 +23,7 @@ import {hasValidLocation, isSCFloor, PlaceTypes, PlaceTypesWithDistance} from '.
|
||||
@Component({
|
||||
selector: 'stapps-place-list-item',
|
||||
templateUrl: 'place-list-item.html',
|
||||
styleUrls: ['place-list-item.scss'],
|
||||
})
|
||||
export class PlaceListItemComponent {
|
||||
/**
|
||||
|
||||
@@ -26,28 +26,24 @@
|
||||
</p>
|
||||
<p>
|
||||
<ion-note *ngIf="item.categories && item.type !== 'building'; else onlyType">
|
||||
<ul>
|
||||
<li>
|
||||
{{ 'categories' | thingTranslate: item | join: ', ' | titlecase }}
|
||||
</li>
|
||||
<li *ngIf="distance">
|
||||
<ion-icon name="directions_walk"></ion-icon>
|
||||
{{ distance | metersLocalized }}
|
||||
</li>
|
||||
</ul>
|
||||
<ion-label>
|
||||
{{ 'categories' | thingTranslate: item | join: ', ' | titlecase }}
|
||||
</ion-label>
|
||||
<ion-label *ngIf="distance" class="distance">
|
||||
<ion-icon name="directions_walk"></ion-icon>
|
||||
{{ distance | metersLocalized }}
|
||||
</ion-label>
|
||||
</ion-note>
|
||||
</p>
|
||||
<ng-template #onlyType>
|
||||
<ion-note>
|
||||
<ul>
|
||||
<li>
|
||||
{{ 'type' | thingTranslate: item }}
|
||||
</li>
|
||||
<li *ngIf="distance">
|
||||
<ion-icon name="directions_walk"></ion-icon>
|
||||
{{ distance | metersLocalized }}
|
||||
</li>
|
||||
</ul>
|
||||
<ion-label>
|
||||
{{ 'type' | thingTranslate: item | titlecase }}
|
||||
</ion-label>
|
||||
<ion-label *ngIf="distance" class="distance">
|
||||
<ion-icon name="directions_walk"></ion-icon>
|
||||
{{ distance | metersLocalized }}
|
||||
</ion-label>
|
||||
</ion-note>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
@@ -56,10 +52,11 @@
|
||||
</p>
|
||||
</div>
|
||||
</ion-col>
|
||||
<div *ngIf="item.type !== 'building'">
|
||||
<ion-col width-20 text-right *ngIf="item.inPlace">
|
||||
<ion-icon name="pin_drop"></ion-icon>{{ 'name' | thingTranslate: item.inPlace }}
|
||||
<ng-container *ngIf="item.type !== 'building'">
|
||||
<ion-col size="auto" class="in-place" *ngIf="item.inPlace">
|
||||
<ion-icon name="pin_drop"></ion-icon
|
||||
><ion-label>{{ 'name' | thingTranslate: item.inPlace }}</ion-label>
|
||||
</ion-col>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*!
|
||||
* Copyright (C) 2023 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/>.
|
||||
*/
|
||||
|
||||
ion-note {
|
||||
display: flex;
|
||||
|
||||
> ion-label {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
ion-label + ion-label.distance::before {
|
||||
content: '•';
|
||||
margin-inline: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.in-place {
|
||||
display: flex;
|
||||
|
||||
justify-content: end;
|
||||
align-items: center;
|
||||
}
|
||||
@@ -51,6 +51,8 @@ export class FavoritesService {
|
||||
// using debounce time 0 allows change detection to run through async suspension
|
||||
favoritesChanged$ = this.favorites.pipe(debounceTime(0));
|
||||
|
||||
favoriteThings$ = this.favoritesChanged$.pipe(map(favorite => [...favorite.values()].map(it => it.data)));
|
||||
|
||||
static getDataFromFavorites(items: SCFavorite[]) {
|
||||
return items.map(item => item.data);
|
||||
}
|
||||
|
||||
@@ -21,107 +21,105 @@
|
||||
<ion-title>{{ 'feedback.page.TITLE' | translate }}</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content class="ion-content-parallax">
|
||||
<div>
|
||||
<div class="feedback-content">
|
||||
<ion-card>
|
||||
<form #feedbackForm="ngForm" (ngSubmit)="onSubmit()">
|
||||
<ion-item>
|
||||
<ion-label position="stacked">{{ 'feedback.form.name.label' | translate }}</ion-label>
|
||||
<ion-input
|
||||
placeholder="{{ 'feedback.form.name.placeholder' | translate }}"
|
||||
[(ngModel)]="author.name"
|
||||
name="name"
|
||||
></ion-input>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label position="stacked">{{ 'feedback.form.type.label' | translate }}</ion-label>
|
||||
<ion-select
|
||||
[(ngModel)]="message.name"
|
||||
value="comment"
|
||||
name="title"
|
||||
interface="popover"
|
||||
required="true"
|
||||
>
|
||||
<ion-select-option value="Comment">{{
|
||||
'feedback.form.type.values.comment' | translate
|
||||
}}</ion-select-option>
|
||||
<ion-select-option value="Bug">{{
|
||||
'feedback.form.type.values.bug' | translate
|
||||
}}</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label position="stacked">{{ 'feedback.form.email.label' | translate }}</ion-label>
|
||||
<ion-input
|
||||
placeholder="{{ 'feedback.form.email.placeholder' | translate }}"
|
||||
[(ngModel)]="author.email"
|
||||
type="email"
|
||||
name="email"
|
||||
ngModel
|
||||
email
|
||||
></ion-input>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label position="stacked">{{ 'feedback.form.message.label' | translate }}</ion-label>
|
||||
<ion-textarea
|
||||
[(ngModel)]="message.messageBody"
|
||||
placeholder="{{
|
||||
'feedback.form.message.placeholder' | translate: {number: MINIMUM_MESSAGE_SIZE}
|
||||
}}"
|
||||
name="message"
|
||||
required="true"
|
||||
minlength="{{ MINIMUM_MESSAGE_SIZE }}"
|
||||
autoGrow="true"
|
||||
></ion-textarea>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label class="ion-text-wrap">{{ 'feedback.form.termsAgree.0' | translate }} </ion-label>
|
||||
<ion-checkbox
|
||||
color="primary"
|
||||
slot="start"
|
||||
[(ngModel)]="termsAgree"
|
||||
name="termsAgree"
|
||||
></ion-checkbox>
|
||||
</ion-item>
|
||||
<ion-item lines="none">
|
||||
<ion-label
|
||||
><a style="display: contents" [routerLink]="['/about/privacy']">{{
|
||||
'feedback.form.termsAgree.1' | translate
|
||||
}}</a></ion-label
|
||||
>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label class="ion-text-wrap">{{ 'feedback.form.protocolDataAgree' | translate }}</ion-label>
|
||||
<ion-checkbox
|
||||
color="primary"
|
||||
slot="start"
|
||||
[(ngModel)]="protocolDataAgree"
|
||||
name="protocolDataAgree"
|
||||
></ion-checkbox>
|
||||
</ion-item>
|
||||
<ion-card>
|
||||
<ion-card-title>
|
||||
<ion-button expand="block" fill="clear" (click)="toggleShowMetaData()">
|
||||
<ng-container *ngIf="!showMetaData; else hide">{{
|
||||
'feedback.form.protocolData.show' | translate
|
||||
}}</ng-container>
|
||||
<ng-template #hide>{{ 'feedback.form.protocolData.hide' | translate }}</ng-template>
|
||||
</ion-button>
|
||||
</ion-card-title>
|
||||
<ion-card-content *ngIf="metaData && showMetaData">
|
||||
<pre>{{ metaData | json }}</pre>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
<ion-button
|
||||
type="submit"
|
||||
color="primary"
|
||||
expand="block"
|
||||
[disabled]="!feedbackForm.valid || !termsAgree || submitSuccess"
|
||||
>{{ 'feedback.form.submit' | translate }}</ion-button
|
||||
<ion-content parallax>
|
||||
<div class="feedback-content">
|
||||
<ion-card>
|
||||
<form #feedbackForm="ngForm" (ngSubmit)="onSubmit()">
|
||||
<ion-item>
|
||||
<ion-label position="stacked">{{ 'feedback.form.name.label' | translate }}</ion-label>
|
||||
<ion-input
|
||||
placeholder="{{ 'feedback.form.name.placeholder' | translate }}"
|
||||
[(ngModel)]="author.name"
|
||||
name="name"
|
||||
></ion-input>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label position="stacked">{{ 'feedback.form.type.label' | translate }}</ion-label>
|
||||
<ion-select
|
||||
[(ngModel)]="message.name"
|
||||
value="comment"
|
||||
name="title"
|
||||
interface="popover"
|
||||
required="true"
|
||||
>
|
||||
</form>
|
||||
</ion-card>
|
||||
</div>
|
||||
<ion-select-option value="Comment">{{
|
||||
'feedback.form.type.values.comment' | translate
|
||||
}}</ion-select-option>
|
||||
<ion-select-option value="Bug">{{
|
||||
'feedback.form.type.values.bug' | translate
|
||||
}}</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label position="stacked">{{ 'feedback.form.email.label' | translate }}</ion-label>
|
||||
<ion-input
|
||||
placeholder="{{ 'feedback.form.email.placeholder' | translate }}"
|
||||
[(ngModel)]="author.email"
|
||||
type="email"
|
||||
name="email"
|
||||
ngModel
|
||||
email
|
||||
></ion-input>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label position="stacked">{{ 'feedback.form.message.label' | translate }}</ion-label>
|
||||
<ion-textarea
|
||||
[(ngModel)]="message.messageBody"
|
||||
placeholder="{{
|
||||
'feedback.form.message.placeholder' | translate: {number: MINIMUM_MESSAGE_SIZE}
|
||||
}}"
|
||||
name="message"
|
||||
required="true"
|
||||
minlength="{{ MINIMUM_MESSAGE_SIZE }}"
|
||||
autoGrow="true"
|
||||
></ion-textarea>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label class="ion-text-wrap">{{ 'feedback.form.termsAgree.0' | translate }} </ion-label>
|
||||
<ion-checkbox
|
||||
color="primary"
|
||||
slot="start"
|
||||
[(ngModel)]="termsAgree"
|
||||
name="termsAgree"
|
||||
></ion-checkbox>
|
||||
</ion-item>
|
||||
<ion-item lines="none">
|
||||
<ion-label
|
||||
><a style="display: contents" [routerLink]="['/about/privacy']">{{
|
||||
'feedback.form.termsAgree.1' | translate
|
||||
}}</a></ion-label
|
||||
>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label class="ion-text-wrap">{{ 'feedback.form.protocolDataAgree' | translate }}</ion-label>
|
||||
<ion-checkbox
|
||||
color="primary"
|
||||
slot="start"
|
||||
[(ngModel)]="protocolDataAgree"
|
||||
name="protocolDataAgree"
|
||||
></ion-checkbox>
|
||||
</ion-item>
|
||||
<ion-card>
|
||||
<ion-card-title>
|
||||
<ion-button expand="block" fill="clear" (click)="toggleShowMetaData()">
|
||||
<ng-container *ngIf="!showMetaData; else hide">{{
|
||||
'feedback.form.protocolData.show' | translate
|
||||
}}</ng-container>
|
||||
<ng-template #hide>{{ 'feedback.form.protocolData.hide' | translate }}</ng-template>
|
||||
</ion-button>
|
||||
</ion-card-title>
|
||||
<ion-card-content *ngIf="metaData && showMetaData">
|
||||
<pre>{{ metaData | json }}</pre>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
<ion-button
|
||||
type="submit"
|
||||
color="primary"
|
||||
expand="block"
|
||||
[disabled]="!feedbackForm.valid || !termsAgree || submitSuccess"
|
||||
>{{ 'feedback.form.submit' | translate }}</ion-button
|
||||
>
|
||||
</form>
|
||||
</ion-card>
|
||||
</div>
|
||||
</ion-content>
|
||||
|
||||
@@ -57,7 +57,7 @@ ion-button {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-sm);
|
||||
background: var(--ion-color-light);
|
||||
background: var(--ion-item-background);
|
||||
@include border-radius-in-parallax(var(--border-radius-default));
|
||||
|
||||
& > * {
|
||||
@@ -70,7 +70,6 @@ ion-button {
|
||||
@include border-radius-in-parallax(var(--border-radius-default));
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background-color: var(--ion-color-primary-contrast);
|
||||
margin: 0;
|
||||
|
||||
& > ion-thumbnail {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*!
|
||||
* Copyright (C) 2022 StApps
|
||||
* Copyright (C) 2023 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.
|
||||
@@ -87,18 +87,10 @@ div.map-buttons {
|
||||
ion-button {
|
||||
margin: 4px;
|
||||
// important for iOS
|
||||
// TODO: find an option that is better suited for the iOS theme
|
||||
--box-shadow: var(--map-box-shadow);
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
ion-button::part(native) {
|
||||
background: white;
|
||||
}
|
||||
|
||||
ion-button::part(native):hover,
|
||||
ion-button::part(native):focus {
|
||||
background: whitesmoke;
|
||||
}
|
||||
}
|
||||
|
||||
div.map-buttons.above {
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/*!
|
||||
* Copyright (C) 2023 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/>.
|
||||
*/
|
||||
|
||||
div.map-container {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* Copyright (C) 2023 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.
|
||||
@@ -159,6 +159,11 @@ describe('ContextMenuComponent', async () => {
|
||||
{
|
||||
field: 'type',
|
||||
buckets: [{count: 10, key: 'date series', checked: true}],
|
||||
info: {
|
||||
onlyOnType: SCThingType.AcademicEvent,
|
||||
field: 'date series',
|
||||
sortOrder: 0,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -210,7 +215,7 @@ function getFilterContextType(): FilterContext {
|
||||
compact: false,
|
||||
options: facetsMock
|
||||
.filter(facet => facet.buckets.length > 0)
|
||||
.map(facet => {
|
||||
.map((facet, i) => {
|
||||
return {
|
||||
buckets: facet.buckets.map(bucket => {
|
||||
return {
|
||||
@@ -222,6 +227,11 @@ function getFilterContextType(): FilterContext {
|
||||
compact: false,
|
||||
field: facet.field,
|
||||
onlyOnType: facet.onlyOnType,
|
||||
info: {
|
||||
onlyOnType: facet.onlyOnType,
|
||||
field: facet.field,
|
||||
sortOrder: i,
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* Copyright (C) 2023 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.
|
||||
@@ -17,7 +17,7 @@ import {LangChangeEvent, TranslateService} from '@ngx-translate/core';
|
||||
import {SCLanguage, SCThingTranslator, SCThingType, SCTranslations} from '@openstapps/core';
|
||||
import {Subscription} from 'rxjs';
|
||||
import {ContextMenuService} from './context-menu.service';
|
||||
import {FilterContext, SortContext, SortContextOption} from './context-type';
|
||||
import {FilterContext, FilterFacet, SortContext, SortContextOption} from './context-type';
|
||||
|
||||
/**
|
||||
* The context menu
|
||||
@@ -49,6 +49,19 @@ export class ContextMenuComponent implements OnDestroy {
|
||||
*/
|
||||
filterOption: FilterContext;
|
||||
|
||||
/**
|
||||
* Picks facets based on the compact filter option and sorts
|
||||
* them based on
|
||||
*
|
||||
* No specific type => Type name alphabetically => Bucket count
|
||||
*/
|
||||
get facets(): FilterFacet[] {
|
||||
const options = this.filterOption.compact
|
||||
? this.filterOption.options.slice(0, this.compactFilterOptionCount)
|
||||
: this.filterOption.options;
|
||||
return options.filter(it => it.buckets.length > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Possible languages to be used for translation
|
||||
*/
|
||||
@@ -102,18 +115,6 @@ export class ContextMenuComponent implements OnDestroy {
|
||||
this.contextMenuService.contextFilterChanged(this.filterOption);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns translated property name
|
||||
*/
|
||||
getTranslatedPropertyName(property: string, onlyForType?: SCThingType): string {
|
||||
return (
|
||||
this.translator.translatedPropertyNames(
|
||||
onlyForType ?? SCThingType.AcademicEvent,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
) as any
|
||||
)[property];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns translated property value
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
~ Copyright (C) 2022 StApps
|
||||
~ Copyright (C) 2023 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.
|
||||
@@ -41,7 +41,7 @@
|
||||
<ion-icon *ngIf="!sortOption.reversed" name="arrow_upward"></ion-icon>
|
||||
</span>
|
||||
</ion-label>
|
||||
<ion-radio slot="end" [value]="i"> </ion-radio>
|
||||
<ion-radio slot="end" [value]="i"></ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
</ion-list>
|
||||
@@ -55,31 +55,17 @@
|
||||
</ion-button>
|
||||
</ion-list-header>
|
||||
|
||||
<ion-list
|
||||
class="filter-group"
|
||||
*ngFor="
|
||||
let facet of !filterOption.compact
|
||||
? filterOption.options.slice(0, compactFilterOptionCount)
|
||||
: filterOption.options
|
||||
"
|
||||
>
|
||||
<div *ngIf="!facet.field.includes('.')">
|
||||
<ion-list class="filter-group" *ngFor="let facet of facets">
|
||||
<div>
|
||||
<ion-list-header class="h3">
|
||||
<ion-label>
|
||||
{{
|
||||
(facet.onlyOnType
|
||||
? getTranslatedPropertyName(facet.field, facet.onlyOnType)
|
||||
: getTranslatedPropertyName(facet.field)
|
||||
) | titlecase
|
||||
}}
|
||||
{{
|
||||
facet.onlyOnType
|
||||
? ' | ' + (getTranslatedPropertyValue(facet.onlyOnType, 'type') | titlecase)
|
||||
: ''
|
||||
}}
|
||||
<span *ngIf="facet.info.onlyOnType"
|
||||
><b>{{ facet.info.onlyOnType | titlecase }}</b> /
|
||||
</span>
|
||||
{{ facet.info.field | titlecase }}
|
||||
</ion-label>
|
||||
</ion-list-header>
|
||||
<div *ngIf="facet.buckets.length > 0">
|
||||
<div>
|
||||
<ion-item
|
||||
*ngFor="
|
||||
let bucket of !facet.compact
|
||||
|
||||
@@ -1,14 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 {TestBed} from '@angular/core/testing';
|
||||
|
||||
import {ContextMenuService} from './context-menu.service';
|
||||
import {SCFacet} from '@openstapps/core';
|
||||
import {FilterContext, SortContext} from './context-type';
|
||||
import {ThingTranslateModule} from '../../../translation/thing-translate.module';
|
||||
import {TranslateModule} from '@ngx-translate/core';
|
||||
|
||||
describe('ContextMenuService', () => {
|
||||
let service: ContextMenuService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [ThingTranslateModule.forRoot(), TranslateModule.forRoot()],
|
||||
providers: [ContextMenuService],
|
||||
});
|
||||
service = TestBed.inject(ContextMenuService);
|
||||
@@ -123,6 +141,10 @@ const filterContext: FilterContext = {
|
||||
},
|
||||
],
|
||||
field: 'type',
|
||||
info: {
|
||||
field: 'type',
|
||||
sortOrder: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -13,9 +13,19 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Injectable} from '@angular/core';
|
||||
import {SCFacet, SCSearchFilter, SCSearchSort, SCThingType} from '@openstapps/core';
|
||||
import {
|
||||
SCFacet,
|
||||
SCSearchFilter,
|
||||
SCSearchSort,
|
||||
SCThingTranslator,
|
||||
SCThingType,
|
||||
SCTranslations,
|
||||
} from '@openstapps/core';
|
||||
import {Subject} from 'rxjs';
|
||||
import {FilterBucket, FilterContext, FilterFacet, SortContext} from './context-type';
|
||||
import {FilterBucket, FilterContext, FilterFacet, SortContext, TransformedFacet} from './context-type';
|
||||
import {TranslateService} from '@ngx-translate/core';
|
||||
import {ThingTranslateService} from '../../../translation/thing-translate.service';
|
||||
import {transformFacets} from './facet-filter';
|
||||
|
||||
/**
|
||||
* ContextMenuService provides bidirectional communication of context menu options and search queries
|
||||
@@ -72,6 +82,11 @@ export class ContextMenuService {
|
||||
*/
|
||||
sortQueryChanged$ = this.sortQuery.asObservable();
|
||||
|
||||
constructor(
|
||||
private readonly translate: TranslateService,
|
||||
private readonly thingTranslate: ThingTranslateService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Returns SCSearchFilter if filterContext value is set, undefined otherwise
|
||||
*
|
||||
@@ -178,18 +193,9 @@ export class ContextMenuService {
|
||||
* Updates the filter context options from given facets
|
||||
*/
|
||||
updateContextFilter(facets: SCFacet[]) {
|
||||
// arrange facet field "type" to first position
|
||||
facets.sort((a: SCFacet, b: SCFacet) => {
|
||||
if (a.field === 'type') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (b.field === 'type') {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
const language = this.translate.currentLang as keyof SCTranslations<unknown>;
|
||||
const translator = new SCThingTranslator(language);
|
||||
const transformedFacets = transformFacets(facets, language, this.thingTranslate, translator);
|
||||
|
||||
if (!this.contextFilter) {
|
||||
this.contextFilter = {
|
||||
@@ -198,23 +204,24 @@ export class ContextMenuService {
|
||||
};
|
||||
}
|
||||
|
||||
this.updateContextFilterOptions(this.contextFilter, facets);
|
||||
this.updateContextFilterOptions(this.contextFilter, transformedFacets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates context filter with new facets.
|
||||
* It preserves the checked status of existing filter options
|
||||
*/
|
||||
updateContextFilterOptions = (contextFilter: FilterContext, facets: SCFacet[]) => {
|
||||
updateContextFilterOptions = (contextFilter: FilterContext, facets: TransformedFacet[]) => {
|
||||
const newFilterOptions: FilterFacet[] = [];
|
||||
|
||||
// iterate new facets
|
||||
for (const facet of facets) {
|
||||
for (const {facet, info} of facets) {
|
||||
if (facet.buckets.length > 0) {
|
||||
const newFilterFacet: FilterFacet = {
|
||||
buckets: [],
|
||||
field: facet.field,
|
||||
onlyOnType: facet.onlyOnType,
|
||||
info,
|
||||
};
|
||||
newFilterOptions.push(newFilterFacet);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2020 StApps
|
||||
* Copyright (C) 2023 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.
|
||||
@@ -12,7 +12,7 @@
|
||||
* 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 {SCFacet, SCFacetBucket} from '@openstapps/core';
|
||||
import {SCFacet, SCFacetBucket, SCThingType} from '@openstapps/core';
|
||||
|
||||
export type ContextType = FilterContext | SortContext;
|
||||
|
||||
@@ -84,6 +84,21 @@ export interface FilterFacet extends SCFacet {
|
||||
* Compact view of the option buckets
|
||||
*/
|
||||
compact?: boolean;
|
||||
/**
|
||||
* Translated information about the facet
|
||||
*/
|
||||
info: FacetInfo;
|
||||
}
|
||||
|
||||
export interface FacetInfo {
|
||||
onlyOnType?: SCThingType;
|
||||
field: string;
|
||||
sortOrder: number;
|
||||
}
|
||||
|
||||
export interface TransformedFacet {
|
||||
facet: SCFacet;
|
||||
info: FacetInfo;
|
||||
}
|
||||
|
||||
export interface FilterBucket extends SCFacetBucket {
|
||||
|
||||
70
frontend/app/src/app/modules/menu/context/facet-filter.ts
Normal file
70
frontend/app/src/app/modules/menu/context/facet-filter.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 {TransformedFacet} from './context-type';
|
||||
import {SCFacet, SCThingTranslator, SCThingType, SCTranslations} from '@openstapps/core';
|
||||
import {searchFilters} from '../../../../config/search-filter';
|
||||
import {ThingTranslateService} from '../../../translation/thing-translate.service';
|
||||
|
||||
const filterConfig = Object.entries(searchFilters).map(([pattern, entries]) => {
|
||||
return {
|
||||
typePattern: new RegExp(`^${pattern}$`),
|
||||
facetFilter: Object.entries(entries).map(([pattern, facet]) => ({
|
||||
pattern: new RegExp(`^${pattern}$`),
|
||||
...facet,
|
||||
})),
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Transforms facets to
|
||||
*
|
||||
* 1. only include facets that are allowed in the options
|
||||
* 2. translates all fields
|
||||
* 3. sorts the facets according to the config
|
||||
*/
|
||||
export function transformFacets(
|
||||
facets: SCFacet[],
|
||||
language: keyof SCTranslations<unknown>,
|
||||
thingTranslate: ThingTranslateService,
|
||||
translator: SCThingTranslator,
|
||||
): TransformedFacet[] {
|
||||
return facets
|
||||
.map(facet => ({
|
||||
facet,
|
||||
info: filterConfig
|
||||
.filter(({typePattern}) => typePattern.test((facet.onlyOnType as string) || ''))
|
||||
.flatMap(({facetFilter}) =>
|
||||
facetFilter
|
||||
.filter(({pattern}) => pattern.test(facet.field))
|
||||
.map(it => ({
|
||||
onlyOnType: facet.onlyOnType
|
||||
? (translator.translatedPropertyValue(facet.onlyOnType, 'type') as SCThingType)
|
||||
: undefined,
|
||||
field:
|
||||
it.translations && it.name
|
||||
? it.translations[language]?.name || it.name
|
||||
: thingTranslate.getPropertyName(
|
||||
facet.onlyOnType || SCThingType.AcademicEvent,
|
||||
facet.field,
|
||||
),
|
||||
sortOrder: it.sortOrder,
|
||||
})),
|
||||
)
|
||||
.sort(({sortOrder: a}, {sortOrder: b}) => a - b)[0],
|
||||
}))
|
||||
.filter(({info}) => !!info)
|
||||
.sort(({info: {sortOrder: a}}, {info: {sortOrder: b}}) => a - b);
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
-->
|
||||
|
||||
<stapps-offline-notice></stapps-offline-notice>
|
||||
<ion-split-pane contentId="main" when="lg">
|
||||
<ion-split-pane contentId="main" when="xl">
|
||||
<ion-menu menuId="main" contentId="main" type="overlay" side="start" swipe-gesture="false">
|
||||
<ion-header>
|
||||
<ion-toolbar color="primary" mode="ios">
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
@import '../../../../theme/util/mixins';
|
||||
|
||||
stapps-navigation-tabs {
|
||||
@include ion-lg-up {
|
||||
@include ion-xl-up {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ stapps-offline-notice.is-offline ~ ion-split-pane {
|
||||
margin-left: var(--navigation-rail-width);
|
||||
}
|
||||
|
||||
@include ion-lg-up {
|
||||
@include ion-xl-up {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ stapps-offline-notice.is-offline ~ ion-split-pane {
|
||||
}
|
||||
|
||||
ion-router-outlet {
|
||||
background: white;
|
||||
background: var(--ion-background-color);
|
||||
}
|
||||
|
||||
.menu-category {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* Copyright (C) 2023 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
* 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 {Directive, ElementRef, Input, OnDestroy, OnInit, Renderer2} from '@angular/core';
|
||||
import {AnimationController, NavController} from '@ionic/angular';
|
||||
import {Router, RouterEvent} from '@angular/router';
|
||||
@@ -46,6 +45,12 @@ export class RootLinkDirective implements OnInit, OnDestroy {
|
||||
ngOnInit() {
|
||||
const animation = tabsTransition(this.animationController);
|
||||
this.renderer.setAttribute(this.element.nativeElement, 'button', '');
|
||||
if (document.querySelector('#main')?.childNodes.length === 1) {
|
||||
if (this.router.url === this.rootLink) {
|
||||
this.setActive();
|
||||
}
|
||||
this.needsInit = false;
|
||||
}
|
||||
|
||||
this.subscriptions.push(
|
||||
this.router.events.subscribe(event => {
|
||||
|
||||
@@ -23,7 +23,7 @@ ion-card::part(native) {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
height: 100%;
|
||||
background: linear-gradient(to top, var(--ion-color-dark), transparent);
|
||||
background: linear-gradient(to top, #0e0e0e, transparent);
|
||||
}
|
||||
|
||||
.card {
|
||||
@@ -38,10 +38,10 @@ ion-card-title {
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
font-size: var(--font-size-xl);
|
||||
--color: var(--ion-color-dark-contrast);
|
||||
--color: var(--ion-text-color-dark, white);
|
||||
max-lines: 3;
|
||||
}
|
||||
|
||||
ion-card-subtitle {
|
||||
--color: var(--ion-color-dark-contrast);
|
||||
--color: var(--ion-text-color-dark, white);
|
||||
}
|
||||
|
||||
@@ -22,41 +22,39 @@
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-content-parallax" (elementSizeChange)="calcPageSize($event)">
|
||||
<div>
|
||||
<ion-refresher slot="fixed" (ionRefresh)="refresh($event.target)">
|
||||
<ion-refresher-content
|
||||
pullingIcon="chevron-down-outline"
|
||||
pullingText="{{ 'data.REFRESH_ACTION' | translate }}"
|
||||
refreshingText="{{ 'data.REFRESHING' | translate }}"
|
||||
refreshingSpinner="crescent"
|
||||
>
|
||||
</ion-refresher-content>
|
||||
</ion-refresher>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col size="12">
|
||||
<stapps-news-settings-filter
|
||||
*ngIf="settings"
|
||||
[settings]="settings"
|
||||
(filtersChanged)="toggleFilter($event)"
|
||||
></stapps-news-settings-filter>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
<div class="news-grid">
|
||||
<ng-container *ngIf="!news">
|
||||
<stapps-skeleton-news-item *ngFor="let skeleton of [1, 2, 3, 4, 5]"></stapps-skeleton-news-item>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="news.length > 0">
|
||||
<stapps-news-item *ngFor="let item of news" [item]="item"></stapps-news-item>
|
||||
</ng-container>
|
||||
</div>
|
||||
<ion-label *ngIf="news.length === 0" class="centeredMessageContainer">
|
||||
{{ 'search.nothing_found' | translate | titlecase }}
|
||||
</ion-label>
|
||||
<ion-infinite-scroll id="infinite-scroll" threshold="20%" (ionInfinite)="loadMore($event.target)">
|
||||
<ion-infinite-scroll-content loading-spinner="crescent"> </ion-infinite-scroll-content>
|
||||
</ion-infinite-scroll>
|
||||
<ion-content parallax (elementSizeChange)="calcPageSize($event)">
|
||||
<ion-refresher slot="fixed" (ionRefresh)="refresh($event.target)">
|
||||
<ion-refresher-content
|
||||
pullingIcon="chevron-down-outline"
|
||||
pullingText="{{ 'data.REFRESH_ACTION' | translate }}"
|
||||
refreshingText="{{ 'data.REFRESHING' | translate }}"
|
||||
refreshingSpinner="crescent"
|
||||
>
|
||||
</ion-refresher-content>
|
||||
</ion-refresher>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col size="12">
|
||||
<stapps-news-settings-filter
|
||||
*ngIf="settings"
|
||||
[settings]="settings"
|
||||
(filtersChanged)="toggleFilter($event)"
|
||||
></stapps-news-settings-filter>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
<div class="news-grid">
|
||||
<ng-container *ngIf="!news">
|
||||
<stapps-skeleton-news-item *ngFor="let skeleton of [1, 2, 3, 4, 5]"></stapps-skeleton-news-item>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="news.length > 0">
|
||||
<stapps-news-item *ngFor="let item of news" [item]="item"></stapps-news-item>
|
||||
</ng-container>
|
||||
</div>
|
||||
<ion-label *ngIf="news.length === 0" class="centeredMessageContainer">
|
||||
{{ 'search.nothing_found' | translate | titlecase }}
|
||||
</ion-label>
|
||||
<ion-infinite-scroll id="infinite-scroll" threshold="20%" (ionInfinite)="loadMore($event.target)">
|
||||
<ion-infinite-scroll-content loading-spinner="crescent"> </ion-infinite-scroll-content>
|
||||
</ion-infinite-scroll>
|
||||
</ion-content>
|
||||
|
||||
@@ -14,13 +14,11 @@
|
||||
*/
|
||||
|
||||
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
|
||||
import {SCSection} from './sections';
|
||||
import {SCSection} from '../../../../config/profile-page-sections';
|
||||
import {AuthHelperService} from '../../auth/auth-helper.service';
|
||||
import {Observable, Subscription} from 'rxjs';
|
||||
import {SCAuthorizationProviderType} from '@openstapps/core';
|
||||
import Swiper from 'swiper';
|
||||
import {AlertController} from '@ionic/angular';
|
||||
import {TranslateService} from '@ngx-translate/core';
|
||||
|
||||
@Component({
|
||||
selector: 'stapps-profile-page-section',
|
||||
@@ -55,11 +53,7 @@ export class ProfilePageSectionComponent implements OnInit, OnDestroy {
|
||||
},
|
||||
};
|
||||
|
||||
constructor(
|
||||
private authHelper: AuthHelperService,
|
||||
private alertController: AlertController,
|
||||
private translateService: TranslateService,
|
||||
) {}
|
||||
constructor(private authHelper: AuthHelperService) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.item.authProvider) {
|
||||
@@ -100,27 +94,7 @@ export class ProfilePageSectionComponent implements OnInit, OnDestroy {
|
||||
|
||||
async signOut(providerType: SCAuthorizationProviderType) {
|
||||
await this.authHelper.getProvider(providerType).signOut();
|
||||
|
||||
const alert: HTMLIonAlertElement = await this.alertController.create({
|
||||
header: this.translateService.instant(`auth.messages.${providerType}.log_out_alert.header`),
|
||||
message: this.translateService.instant(`auth.messages.${providerType}.log_out_alert.message`),
|
||||
buttons: [
|
||||
{
|
||||
text: this.translateService.instant('no'),
|
||||
cssClass: 'default',
|
||||
},
|
||||
{
|
||||
text: this.translateService.instant('yes'),
|
||||
role: 'confirm',
|
||||
cssClass: 'preferred',
|
||||
handler: () => {
|
||||
this.authHelper.endBrowserSession(providerType);
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await alert.present();
|
||||
await this.authHelper.endBrowserSession(providerType);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
*ngFor="let link of item.links"
|
||||
[routerLink]="link.link"
|
||||
[disabled]="link.needsAuth && !isLoggedIn"
|
||||
[detail]="false"
|
||||
>
|
||||
<div>
|
||||
<ion-icon [name]="link.icon" size="36" color="dark"></ion-icon>
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
@use 'sass:math';
|
||||
|
||||
$width: 108px;
|
||||
|
||||
simple-swiper {
|
||||
@@ -22,7 +24,7 @@ simple-swiper {
|
||||
@each $i in 7, 6, 5, 4, 3, 2, 1 {
|
||||
$max: #{($width + 8px) * $i};
|
||||
@container (inline-size < #{$max}) {
|
||||
--swiper-slide-width: #{100cqi / $i};
|
||||
--swiper-slide-width: #{math.div(100cqi, $i)};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,6 +52,7 @@ ion-item {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: var(--font-size-sm);
|
||||
padding: 0 var(--spacing-xs) 0 var(--spacing-xs);
|
||||
}
|
||||
|
||||
&::part(native) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user