Compare commits

...

276 Commits

Author SHA1 Message Date
Nino Righi
41b985c8ee Bugs behoben, Scroll position folgt mit nächsten Commit 2022-07-07 16:25:34 +02:00
Andreas Schickinger
83c0a20d61 Warenausgabe Tabwechsel Bugfix 2022-07-06 17:47:39 +02:00
Andreas Schickinger
a4de2391e9 Merged PR 1310: #3262 WA Loader wird nicht angezeigt
#3262 WA Loader wird nicht angezeigt

Related work items: #3262
2022-07-06 14:58:22 +00:00
Andreas Schickinger
732566eacd Merged PR 1311: #3263 WA Details API calls angepasst
#3263 WA Details API calls angepasst

Related work items: #3263
2022-07-06 14:48:37 +00:00
Andreas Schickinger
2c98128531 Merged PR 1309: #3264 WA QueryParam aktualisieren mit debounce
#3264 WA QueryParam aktualisieren mit debounce

Related work items: #3264
2022-07-06 14:38:56 +00:00
Nino Righi
9a45823bdb Merged PR 1308: #3256 Abholfachremissionsvorschau Create Toas with Dialog Text or Fallback Me...
#3256 Abholfachremissionsvorschau Create Toas with Dialog Text or Fallback Message if Dialog is not available
2022-07-06 14:38:35 +00:00
Andreas Schickinger
fa43a08831 Merged PR 1305: Warenbegleitscheine Rechtschreibfehler fix
Warenbegleitscheine Rechtschreibfehler fix
2022-07-04 11:25:51 +00:00
Nino Righi
6fb8bdaff1 Merged PR 1304: Merge Develop -> Release/2.0
Merge Develop -> Release/2.0

Related work items: #905, #2737, #2790, #3040, #3150, #3157, #3158, #3175, #3179, #3189, #3212, #3234
2022-06-29 12:48:45 +00:00
Andreas Schickinger
35e6d60ac0 Merged PR 1301: #3234 Remission Artikel hinzufügen Teilmengen Bugfix
#3234 Remission Artikel hinzufügen Teilmengen Bugfix

Related work items: #3234
2022-06-29 08:37:58 +00:00
Nino Righi
ecfc241fb5 Merged PR 1303: #2953 Fix Zubuchen CompartmentCode
#2953 Fix Zubuchen CompartmentCode
2022-06-29 08:37:25 +00:00
Nino Righi
866a5100b9 Merged PR 1299: #2953 Updated QR Code Print Data
#2953 Updated QR Code Print Data
2022-06-28 13:31:47 +00:00
Andreas Schickinger
3d972fd740 Merged PR 1298: #3234 Bugfix Remission Artikel hinzufügen Menge falsch
#3234 Bugfix Remission Artikel hinzufügen Menge falsch

Related work items: #3234
2022-06-28 08:14:39 +00:00
Nino Righi
59c9275cc4 Merged PR 1297: #2953 Updated PRINT_PRICEDIFFQRCODELABEL compartmentCode and compartmentInfo
#2953 Updated PRINT_PRICEDIFFQRCODELABEL compartmentCode and compartmentInfo
2022-06-27 15:33:10 +00:00
Lorenz Hilpert
3ada83efff #3091 - Meldung bei nicht remittierbaren Artikel 2022-06-27 14:46:12 +02:00
Lorenz Hilpert
e263048a35 gen:swagger:remi - Regenerate remi api 2022-06-27 10:24:41 +02:00
Lorenz Hilpert
63980298b6 #3149 Query Filter Keep Changes Whitput Applying 2022-06-27 10:19:04 +02:00
Lorenz Hilpert
b904e94156 Merged PR 1296: Merge Release into Develop
Related work items: #905, #2737, #2790, #3040, #3150, #3157, #3158, #3175, #3179, #3189, #3212
2022-06-24 15:06:23 +00:00
Lorenz Hilpert
78f91b937f Merged PR 1295: Merge Develop into Release2.0
Related work items: #905, #3040, #3175, #3179, #3189, #3212
2022-06-24 14:54:23 +00:00
Andreas Schickinger
1ecd08d053 Merged PR 1293: #3212 Remission Stapel aktualisieren bugfix
#3212 Remission Stapel aktualisieren bugfix

Related work items: #3212
2022-06-24 14:06:41 +00:00
Andreas Schickinger
8c03accae7 Merged PR 1294: #3224 Remission Artikel hinzufügen Breadcrumb
#3224 Remission Artikel hinzufügen Breadcrumb
2022-06-24 14:05:51 +00:00
Andreas Schickinger
456d3f2f3a Merged PR 1290: #905 Remission WBS Leistung Dummy entfernt
#905 Remission WBS Leistung Dummy entfernt

Related work items: #905
2022-06-24 09:05:39 +00:00
Andreas Schickinger
fa2838ea5c Merged PR 1289: #3212 Remission Stapel aktualisieren fix
#3212 Remission Stapel aktualisieren fix
2022-06-24 09:04:58 +00:00
Andreas Schickinger
e228490812 Merged PR 1288: #3212 Remission Stapel Stock aktualisieren anhand EAN
#3212 Remission Stapel Stock aktualisieren anhand EAN

Related work items: #3212
2022-06-23 15:38:44 +00:00
Nino Righi
13d0ac0cbd Merged PR 1287: #3222 Remission Fix Trigger Init Search after Filter gets loaded, relocated u...
#3222 Remission Fix Trigger Init Search after Filter gets loaded, relocated update Cache function
2022-06-23 15:38:10 +00:00
Nino Righi
09bed1456e Merged PR 1284: #3216 Customer Order Details Display All Subset Items
#3216 Customer Order Details Display All Subset Items
2022-06-23 15:34:11 +00:00
Andreas Schickinger
c6827e499e Merged PR 1286: #3040 Logik zum Entfernen von Duplikaten angepasst
#3040 Logik zum Entfernen von Duplikaten angepasst

Related work items: #3040
2022-06-23 13:03:34 +00:00
Nino Righi
d54cc7a2fd Merged PR 1278: #3204 Platform Detection and Scrollbars
#3204 Platform Detection and Scrollbars
2022-06-23 07:28:14 +00:00
Andreas Schickinger
67dae94524 Merged PR 1283: #3040 Remission SilentReload entfernt und Ladelogik angepasst
#3040 Remission SilentReload entfernt und Ladelogik angepasst

Related work items: #3189
2022-06-22 14:05:11 +00:00
Nino Righi
3273a21246 Merged PR 1282: #3215 Config Produktbilder Changes
#3215 Config Produktbilder Changes
2022-06-22 13:18:40 +00:00
Nino Righi
b40b61a46c Merged PR 1281: #3215 Hotfix Update Configs Production Staging
#3215 Hotfix Update Configs Production Staging
2022-06-22 12:46:57 +00:00
Nino Righi
813f611843 Merged PR 1279: #3206 Hide Supplier if Supplier Count is <= 1 and Disable Logic if click on a...
#3206 Hide Supplier if Supplier Count is <= 1 and Disable Logic if click on already activated Supplier or Source
2022-06-21 13:12:16 +00:00
Lorenz Hilpert
1abacb75be debugger entfernt 2022-06-21 15:11:31 +02:00
Lorenz Hilpert
42028a2777 #3040 Remission - Fehler bei nicht gefunden stehen 2022-06-21 15:11:07 +02:00
Lorenz Hilpert
0a25eeadbe Merged PR 1277: #3149 Process Change and Caching
#3149 Process Change and Caching
2022-06-20 15:39:00 +00:00
Lorenz Hilpert
70a4451f90 #3189 Remission - Artikel entfernen von WBS landen nicht wieder auf Remi-Liste 2022-06-20 12:21:11 +02:00
Lorenz Hilpert
d859395f50 #3160 Spelling 2022-06-20 11:44:02 +02:00
Andreas Schickinger
97948df14e Merged PR 1276: #3175 Remission kein Refresh bei Wechsel von Warenbegleitschein
#3175 Remission kein Refresh bei Wechsel von Warenbegleitschein
#3189 Remission Artikel entfernen Refresh

Related work items: #3175
2022-06-17 09:20:16 +00:00
Lorenz Hilpert
dc84efb3ef #3160 Remission - im Abteilungremission Ladeanimation ohne Filter 2022-06-15 11:26:21 +02:00
Andreas Schickinger
12676a4314 Merged PR 1275: #3179 Refactoring Remission Warenbegleitschein eröffnen Rechtschreibfehler
#3179 Refactoring Remission Warenbegleitschein eröffnen Rechtschreibfehler

Related work items: #3179
2022-06-13 14:05:18 +00:00
Lorenz Hilpert
3aafb9f8e7 #3173 Remission - Single-Selection bei Abteilungsremission - Abteilungen 2022-06-13 16:04:32 +02:00
Lorenz Hilpert
4518db2bdd Merged PR 1274: Merge Dev => Release
Related work items: #2737, #2790, #3150, #3157, #3158
2022-06-10 13:16:11 +00:00
Andreas Schickinger
2cb161b62e Merged PR 1272: #3150 Scroll Arrows in UiSlider nur anzeigen wenn Scrollbar
#3150 Scroll Arrows in UiSlider nur anzeigen wenn Scrollbar

Related work items: #3150
2022-06-10 09:22:34 +00:00
Lorenz Hilpert
9d052284be #3040 - Remission - Fehler bei nicht gefunden stehen 2022-06-10 11:21:43 +02:00
Nico Hanus
98d9029dde remove single build for develop and enabled batch trigger 2022-06-09 12:41:42 +00:00
Lorenz Hilpert
040c67215e Merged PR 1271: #3040 Remission - Fehler bei nicht gefunden stehen
#3040 Remission - Fehler bei nicht gefunden stehen
2022-06-09 11:47:42 +00:00
Andreas Schickinger
d577312b24 Merged PR 1269: #3158 UiSpinner anstatt leerer Warenkorb Meldung beim Laden
#3158 UiSpinner anstatt leerer Warenkorb Meldung beim Laden

Related work items: #3158
2022-06-09 08:54:31 +00:00
Andreas Schickinger
fa10bc9c30 Merged PR 1268: #3157 AHF Routing und Item wählen anhand OrderItemSubsetId
#3157 AHF Routing und Item wählen anhand OrderItemSubsetId

Related work items: #3157
2022-06-09 08:53:45 +00:00
Andreas Schickinger
055339956a Merged PR 1270: #2790 Benachrichtigungskanäle bei Weiter zum Warenkorb nicht überschreiben
#2790 Benachrichtigungskanäle bei Weiter zum Warenkorb nicht überschreiben, wenn der Kunde bereits ausgewhält ist

Related work items: #2790
2022-06-09 08:34:04 +00:00
Lorenz Hilpert
6cffa53ea9 #3062 Remission Footer 2022-06-08 11:21:12 +02:00
Lorenz Hilpert
fe83ef56ea Fix core-application unit tests 2022-06-07 17:12:22 +02:00
Lorenz Hilpert
abd1cacdc0 #3149 Warenausgabe kann mehrmals in einem Vorgang geöffnet werden 2022-06-07 16:49:58 +02:00
Nino Righi
85b448ab85 Merged PR 1267: #3145 Checkout Summary Changes
#3145 Bugfix Artikellink hat keinen neuen Prozess eröffnet sondern einen bestehenden überschrieben,
Wenn neue Bestellung getätigt wird, wird die alte Bestellbestätigung removed
2022-06-07 08:31:07 +00:00
Nico Hanus
5749f0018c add batching in azurepipeline
https://docs.microsoft.com/en-us/azure/devops/pipelines/repos/azure-repos-git?view=azure-devops&tabs=yaml#batching-ci-runs
2022-06-03 11:42:43 +00:00
Lorenz Hilpert
b65d2c5ff3 #3156 Login Test 2022-06-02 11:45:08 +02:00
Lorenz Hilpert
348b2c4aca #3156 manuelles Login mit Username und Passwort nicht möglich 2022-06-02 10:55:53 +02:00
Nino Righi
dfc3f32086 Merged PR 1266: #3147 Fix IPAD 6 Styling Issue inside Availabilities Modal
#3147 Fix IPAD 6 Styling Issue inside Availabilities Modal
2022-06-02 08:26:33 +00:00
Nino Righi
68d331864d Merged PR 1264: #3145 Updated Order Checkout Process
#3145 Updated Order Checkout Process
2022-06-01 08:19:14 +00:00
Lorenz Hilpert
24a008b20d Merged PR 1263: Cleanup 2022-05-31 12:56:41 +00:00
Nino Righi
0e5c35fae4 Merged PR 1262: #3146 Slide Current Active Process Tab Into View after Activating It
#3146 Slide Current Active Process Tab Into View after Activating It
2022-05-31 08:06:08 +00:00
Nino Righi
4d4b989dcd Merged PR 1261: #3082 Improved Error Handling on PDP
#3082 Improved Error Handling on PDP
2022-05-30 15:38:59 +00:00
Andreas Schickinger
2983d5a068 Merged PR 1260: #2737 Bei Zubuchen kein Abholfachzettel ausdrucken
#2737 Bei Zubuchen kein Abholfachzettel ausdrucken

Related work items: #2737
2022-05-30 08:37:19 +00:00
Nino Righi
efdc365b90 Merged PR 1259: #3022 ISA File Caching Improvements
#3022 ISA File Caching Improvements
2022-05-27 07:51:24 +00:00
Nino Righi
c4a8e3eb96 Merged PR 1258: Merge release into develop
Merge release into develop
2022-05-25 13:48:01 +00:00
Nino Righi
8cb3c98b8d Merged PR 1256: #3133 Changed Service Worker Update Implementation to Angular v12 and Fixed U...
#3133 Changed Service Worker Update Implementation to Angular v12 and Fixed Unit Tests
2022-05-24 16:19:25 +00:00
Nino Righi
9c12eda210 #3133 Changed Service Worker Update Implementation to Angular v12 and Fixed Unit Tests 2022-05-24 18:14:58 +02:00
Lorenz Hilpert
90afcc008d Disable check for update with interval 2022-05-24 17:44:19 +02:00
Lorenz Hilpert
7409d096fe Update Check Disabled 2022-05-24 17:43:24 +02:00
Lorenz Hilpert
a4c4a3c0c8 Merged PR 1255: Merge release 2.0 into develop 2022-05-24 14:29:50 +00:00
Lorenz Hilpert
2148af7b63 Merge branch 'develop' into release/2.0 2022-05-24 16:14:19 +02:00
Andreas Schickinger
d984bc04ec Merged PR 1250: #3109 Produktbilder in der Artikeltrefferliste mit ImageId laden
#3109 Produktbilder in der Artikeltrefferliste mit ImageId laden

Related work items: #3109
2022-05-23 14:46:51 +00:00
Andreas Schickinger
1b7dfcc3ac Merged PR 1249: #3127 iPad Zoom deaktivieren
#3127 iPad Zoom deaktivieren

Related work items: #3127
2022-05-23 14:46:26 +00:00
Andreas Schickinger
c762871cce Merged PR 1248: #2877 Preisunterschied Menge wird pro Item übergeben
#2877 Preisunterschied Menge wird pro Item übergeben

Related work items: #2877
2022-05-23 09:14:24 +00:00
Andreas Schickinger
007ea92bd5 Merged PR 1247: #3128 Wareneingang Warenausgang Breadcrumb wurde nicht immer richtig aktualis...
#3128 Wareneingang Warenausgang Breadcrumb wurde nicht immer richtig aktualisiert

Related work items: #3128
2022-05-23 09:13:44 +00:00
Nino Righi
688b758da2 Merged PR 1245: #3022 Unit Test Fix
#3022 Unit Test Fix
2022-05-19 08:38:09 +00:00
Nino Righi
39147d7afa Merged PR 1244: #3022 ISA File Caching
#3022 ISA File Caching
2022-05-19 08:29:30 +00:00
Andreas Schickinger
50cc17a44b Merged PR 1243: #2877 Preisunterschied Popup: Bei Close/Backdrop Click nicht mehr die Sekundä...
#2877 Preisunterschied Popup: Bei Close/Backdrop Click nicht mehr die Sekundär Action ausführen

Related work items: #2877
2022-05-19 08:29:00 +00:00
Andreas Schickinger
73f592df74 Merged PR 1241: #3116 Bei B2B Kunden war der Weiter Button immer disabled
#3116 Bei B2B Kunden war der Weiter Button immer disabled

Related work items: #3116
2022-05-17 14:18:49 +00:00
Lorenz Hilpert
821042d8b6 App Start - leistung verbessert und statusanzeige 2022-05-17 16:17:26 +02:00
Nino Righi
7123f6cc15 Merged PR 1242: #3124 Toast Message Adjusted Width and Height Values
#3124 Toast Message Adjusted Width and Height Values
2022-05-17 12:56:36 +00:00
Andreas Schickinger
6c2e9906b0 Merged PR 1240: #3117 Prozess Scrollpfeile sollte am iPad nicht sichtbar sein
#3117 Prozess Scrollpfeile sollte am iPad nicht sichtbar sein

Related work items: #3117
2022-05-16 13:59:18 +00:00
Andreas Schickinger
37648b79c3 Merged PR 1238: #3116 Weiter Button in den Kundendetails disabled, wenn noch keine Adressen geladen wurden
#3116 Weiter Button in den Kundendetails disabled, wenn noch keine Adressen geladen wurden

Related work items: #3116
2022-05-16 13:55:06 +00:00
Nino Righi
6b00c2c81a Merged PR 1239: #3093 ISA Offline Message Fix
#3093 ISA Offline Message Fix#3093 ISA Offline Message Fix
2022-05-16 13:24:22 +00:00
Andreas Schickinger
cd5599ff1c Merged PR 1237: #2981 Preisunterschied Action und Popup
#2981 Preisunterschied Action und Popup

Related work items: #2877, #2981
2022-05-16 09:51:40 +00:00
Andreas Schickinger
e870eb241b Merged PR 1236: #3122 Warenausgabe Endpoints angepasst
#3122 Warenausgabe Endpoints angepasst

Related work items: #3122
2022-05-16 09:32:52 +00:00
Andreas Schickinger
fbf8c282e8 Merged PR 1235: #3108 Remission Remi Grund nur anzeigen, wenn vor dem remittieren schon vorha...
#3108 Remission Remi Grund nur anzeigen, wenn vor dem remittieren schon vorhanden

Related work items: #3108
2022-05-16 08:19:23 +00:00
Nico Hanus
811e363dd4 increase cpu and ram limits for better performance 2022-05-13 10:55:36 +02:00
Nino Righi
d206ba1606 Merged PR 1234: #3118 Fixed Process nummeration
#3118 Fixed Process nummeration
2022-05-12 14:56:23 +00:00
Nino Righi
c529134cd2 Merged PR 1233: #3093 Improved Offline Handling
#3093 Improved Offline Handling
2022-05-12 14:21:43 +00:00
Andreas Schickinger
dafb1d335e Merged PR 1232: #3113 Bei Klick auf Abbrechen auf der Login Seite erneut zur Login Seite leiten
#3113 Bei Klick auf Abbrechen auf der Login Seite erneut zur Login Seite leiten

Related work items: #3113
2022-05-12 12:48:37 +00:00
Nino Righi
445899e731 Merged PR 1231: #3115 Fix WE WA Multi Search Request
#3115 Fix WE WA Multi Search Request
2022-05-12 08:18:05 +00:00
Andreas Schickinger
b21fbc974c Merged PR 1230: #2995 Kundensuche doppelter Request im Filter behoben
#2995 Kundensuche doppelter Request im Filter behoben

Related work items: #2995
2022-05-11 15:14:29 +00:00
Andreas Schickinger
4c98a73204 Merged PR 1229: #3108 Remission Restmenge nach dem remittieren angepasst
#3108 Remission Restmenge nach dem remittieren angepasst

Related work items: #3108
2022-05-11 14:41:08 +00:00
Nino Righi
e99d669086 Merged PR 1228: #3104 Improved Error Handling of Removing Items from Shipping Document
#3104 Improved Error Handling of Removing Items from Shipping Document
2022-05-10 15:12:34 +00:00
Andreas Schickinger
913ffbda97 Merged PR 1227: #1058 Remission abschließen Breadcrumb wird entfernt
#1058 Remission abschließen Breadcrumb wird entfernt

Related work items: #1058
2022-05-10 13:31:26 +00:00
Nino Righi
ec2bd0bd5d Merged PR 1226: #3061 Remission List Performance
#3061 Remission List Performance
2022-05-09 15:31:47 +00:00
Andreas Schickinger
08fefb1c4b Merged PR 1225: #3094 Remission mehrfach abschließen Fehlermeldung angepasst
#3094 Remission mehrfach abschließen Fehlermeldung angepasst

Related work items: #3094
2022-05-09 15:18:36 +00:00
Andreas Schickinger
e7f20bc553 Merged PR 1224: #3088 Remission Fehlermeldung bei gleichzeitigem entfernen und Liste Reload a...
#3088 Remission Fehlermeldung bei gleichzeitigem entfernen und Liste Reload auch bei Fehler

Related work items: #3088
2022-05-09 15:17:39 +00:00
Andreas Schickinger
f5993ca5c4 Merged PR 1223: #3087 Bei Error Status 409 Custom Fehlermeldung und Liste auch bei Fehler neu...
#3087 Bei Error Status 409 Custom Fehlermeldung und Liste auch bei Fehler neu laden

Related work items: #3087
2022-05-09 15:17:15 +00:00
Nino Righi
9f0c81c20f Merged PR 1215: #3062 #3051 Remission Breadcrumbs contain the correct queryParams, Remission Process Remembers Filters if Remission is started
#3062 #3051 Remission Breadcrumbs contain the correct queryParams, Remission Process Remembers Filters if Remission is started. Always load available Remission
2022-05-09 11:41:50 +00:00
Nino Righi
42199c8cda Merged PR 1222: #3097 #3089 Shell Process Tabs UI Changes
#3097 #3089 Shell Process Tabs UI Changes
2022-05-09 10:02:51 +00:00
Nino Righi
bc525fbffc Merged PR 1218: #3067 #3056 #2685 Toast Notifications
#3067 #3056 #2685 Toast Notifications
2022-05-09 09:45:54 +00:00
Nino Righi
dd6821642f Merged PR 1220: #3092 Remission Empty List Message
#3092 Remission Empty List Message
2022-05-09 09:43:20 +00:00
Nino Righi
b2dd96f044 Merged PR 1219: #3041 If no supplier selected inside create remission, Blank gets selected an...
#3041 If no supplier selected inside create remission, Blank gets selected and changed navigation inside goods in remission preview
2022-05-09 09:33:49 +00:00
Nino Righi
0ca8a1fabf Merged PR 1221: #3095 Remission Disable Remit Button if Quantity < 1
#3095 Remission Disable Remit Button if Quantity < 1
2022-05-09 09:23:14 +00:00
Nino Righi
d46643cf8c Merged PR 1217: #3084 Remission Added Loader to WBS on deleting Items
#3084 Remission Added Loader to WBS on deleting Items
2022-05-09 08:59:59 +00:00
Nino Righi
fc3bea28e8 Merged PR 1216: #2967 Remission Remit PopUp Wording Fix
#2967 Remission Remit PopUp Wording Fix
2022-05-09 08:57:05 +00:00
Nino Righi
b29323864e Updated Isa-App Config Files 2022-05-03 11:38:41 +02:00
Michael Auer
c4cad5d56f Merge branch 'develop' into release/2.0 2022-05-03 10:52:36 +02:00
Nino Righi
1d83c82919 Merged PR 1214: #3083 Adjusted File Memory Budgets for Production Build
#3083 Adjusted File Memory Budgets for Production Build
2022-05-02 12:05:51 +00:00
Andreas Schickinger
1228698fcf Merged PR 1212: #3069 Fehlende Icons in der Remission
#3069 Fehlende Icons in der Remission

Related work items: #3069
2022-05-02 08:26:38 +00:00
Andreas Schickinger
d1eba5f1e2 Merged PR 1213: #2575 AHF Remi Buttons
#2575 AHF Remi Buttons

Related work items: #2575
2022-05-02 08:24:20 +00:00
Michael Auer
08ac71dc1b Merge tag '1.7' into develop 2022-05-02 10:10:39 +02:00
Michael Auer
da579ecc3a Merge branch 'release/1.7' 2022-05-02 09:37:27 +02:00
Andreas Schickinger
f286dd1e1b Merged PR 1211: #3080 Bei Remittieren mit Menge 0 wird nun "Nicht gefunden" ausgelöst
#3080 Bei Remittieren mit Menge 0 wird nun "Nicht gefunden" ausgelöst

Related work items: #3080
2022-04-28 14:39:28 +00:00
Nino Righi
0c5aedfee8 Merged PR 1210: #3081 #3051 Remember Filter Settings on continuing Remission and Remission start
#3081 #3051 Remember Filter Settings on continuing Remission and Remission start
2022-04-28 14:24:24 +00:00
Andreas Schickinger
b7d7c88fc6 Merged PR 1209: #3069 Fehlende Icons hinzugefügt. Anzeige nur, wenn Icon vorhanden
#3069 Fehlende Icons hinzugefügt. Anzeige nur, wenn Icon vorhanden

Related work items: #3069
2022-04-28 14:12:29 +00:00
Nico Hanus
8c2671e2fb limit unittests build for develop 2022-04-28 14:08:29 +00:00
Nico Hanus
b281f7c25b limit builds for develop branch 2022-04-28 13:59:47 +00:00
Nino Righi
750caa522e Merged PR 1208: #3074 Added Spacer inside WBS View
#3074 Added Spacer inside WBS View
2022-04-28 12:56:45 +00:00
Nino Righi
62ed8affb1 Merged PR 1207: #3076 Changed PopUp Wording and Form Validation Error Message
#3076 Changed PopUp Wording and Form Validation Error Message
2022-04-28 12:33:18 +00:00
Nino Righi
92e0e90120 Merged PR 1206: #3075 Remission Option to open Filter Overlay during a search
#3075 Remission Option to open Filter Overlay during a search
2022-04-28 12:32:33 +00:00
Andreas Schickinger
9b0dea213e Merged PR 1205: #3070 TK Fotoabschluss Spinner
#3070 TK Fotoabschluss Spinner

Related work items: #3070
2022-04-28 11:56:13 +00:00
Andreas Schickinger
a73acfa4e8 Merged PR 1204: #3063 Remission unnötiger Return Aufruf bei Wechsel zu gestarteter Remi über...
#3063 Remission unnötiger Return Aufruf bei Wechsel zu gestarteter Remi über den Footer

Related work items: #3063
2022-04-28 11:55:44 +00:00
Nino Righi
833542f303 Merged PR 1203: #3062 Clear Items Cache If Navigate to Remission
#3062 Clear Items Cache If Navigate to Remission
2022-04-27 14:05:53 +00:00
Nino Righi
b666e4b38c Merged PR 1202: #3051 Fix Remission Routing after Remission Completed
#3051 Fix Remission Routing after Remission Completed
2022-04-27 13:51:21 +00:00
Nino Righi
32f2fd0754 Merged PR 1201: #3058 Fix Show Start Remission CTA only if Hits > 0
#3058 Fix Show Start Remission CTA only if Hits > 0
2022-04-27 12:41:15 +00:00
Nino Righi
04cd5e9437 Merged PR 1196: #3028 #3040 #3049 Bugfixes Remission
#3028 #3040 #3049 Bugfixes Remission
2022-04-27 10:53:48 +00:00
Nino Righi
3785ad614f Merged PR 1200: #3050 Customer Online Email Adress Validation Fix
#3050 Customer Online Email Adress Validation Fix
2022-04-27 10:39:01 +00:00
Nino Righi
4e9b4064a6 Merged PR 1199: #3053 Fix Reservieren In Andere Filiale
#3053 Fix Reservieren In Andere Filiale
2022-04-27 09:45:06 +00:00
Nino Righi
319d8b96bb Merged PR 1197: #3054 Hotfix Release 1.7 TK PDF Viewer Removed Zoom Scaling to fit the page c...
#3054 Hotfix Release 1.7 TK PDF Viewer Removed Zoom Scaling to fit the page correctly
2022-04-26 13:58:02 +00:00
Nino Righi
272824e236 Merged PR 1198: #3036 Fix NativeContainer
#3036 Fix NativeContainer
2022-04-26 13:31:18 +00:00
Nino Righi
4b3e80cadb #3036 Added Try Catch 2022-04-26 15:27:31 +02:00
Nino Righi
f6675b67e8 #3036 Fix NativeContainer 2022-04-26 15:22:24 +02:00
Nino Righi
6974324c9b #3054 Hotfix Release 1.7 TK PDF Viewer Removed Zoom Scaling to fit the page correctly 2022-04-26 14:21:39 +02:00
Andreas Schickinger
c805106759 Merged PR 1194: #2774 AHF Coveranzeige Abfrage ohne alle Filialen und Archiv
#2774 AHF Coveranzeige Abfrage ohne alle Filialen und Archiv

Related work items: #2774
2022-04-25 10:55:49 +00:00
Andreas Schickinger
5448ac034b Merged PR 1195: #3049 Remission beim Wechsel zwischen Remi Liste und Warenbegleitscheine blei...
#3049 Remission beim Wechsel zwischen Remi Liste und Warenbegleitscheine bleiben die Filter erhalten

Related work items: #3049
2022-04-25 10:55:10 +00:00
Nino Righi
79667ae4b6 Merged PR 1192: #2983 Remission List Trigger Loading instantly After Filter, Source or Suppli...
#2983 Remission List Trigger Loading instantly After Filter, Source or Supplier changes
2022-04-22 08:26:37 +00:00
Andreas Schickinger
336a98e576 Merged PR 1193: #3035 AHF Coveranzeige Refresh bei Statuswechsel
#3035 AHF Coveranzeige Refresh bei Statuswechsel

Related work items: #3035
2022-04-21 13:41:46 +00:00
Andreas Schickinger
4e4dc47ad6 Merged PR 1190: #3024 Links in der Bestellbestätigung verwenden nicht die aktive Prozess ID
#3024 Links in der Bestellbestätigung verwenden nicht die aktive Prozess ID

Related work items: #3024
2022-04-21 13:40:46 +00:00
Andreas Schickinger
ee02e89fa7 Merged PR 1191: #3030 AHF Zubuchen - letzter Zusatz wird übernommen
#3030 AHF Zubuchen - letzter Zusatz wird übernommen

Related work items: #3030
2022-04-21 13:35:28 +00:00
Nino Righi
7e6f5a7837 Merged PR 1189: #2982 Remission Resul List Design Changes
#2982 Remission Resul List Design Changes
2022-04-21 12:54:05 +00:00
Nino Righi
7b824bd13b Merged PR 1188: #3033 Check if Process is available
#3033 Check if Process is available
2022-04-21 12:51:37 +00:00
Andreas Schickinger
146ad7b20a Merged PR 1186: #3032 AHF Routing Fix
#3032 AHF Routing Fix

Related work items: #3032
2022-04-20 16:54:11 +00:00
Nino Righi
f657a088d4 Merged PR 1185: #2982 #2983 #3028 #3031 Remission Liste Caching, Scrollposition, Loader, Virtual Scroll Viewport
#2982 #2983 #3028 #3031 Remission Liste Caching, Scrollposition, Loader, Virtual Scroll Viewport
2022-04-20 16:36:27 +00:00
Nino Righi
c4ed8d0648 Merged PR 1187: #3033 Fix TK Article List Search Routing and changed EAN Copy Seperator
#3033 Fix TK Article List Search Routing and changed EAN Copy Seperator
2022-04-20 14:24:01 +00:00
Andreas Schickinger
810a7d0a8f Merged PR 1184: #2992 TK PDF Viewer kein horizontales Scrollen von Hochformat Dokumenten auf...
#2992 TK PDF Viewer kein horizontales Scrollen von Hochformat Dokumenten auf dem iPad

Related work items: #2992
2022-04-19 13:46:41 +00:00
Andreas Schickinger
25d5f183c5 Merged PR 1183: #3030 AHF Zubuchen mit Zusatz
#3030 AHF Zubuchen mit Zusatz

Related work items: #3030
2022-04-19 13:32:04 +00:00
Andreas Schickinger
9052fe25db Merged PR 1182: #2756 WE WA Edit Anmerkungsfeld mehrzeilig
#2756 WE WA Edit Anmerkungsfeld mehrzeilig

Related work items: #2756
2022-04-14 08:26:45 +00:00
Andreas Schickinger
776115fbed Merged PR 1181: #3023 Remission Required Capacities Department wird mitgegeben
#3023 Remission Required Capacities Department wird mitgegeben

Related work items: #3023
2022-04-13 15:29:13 +00:00
Andreas Schickinger
962f0bc2c6 Merged PR 1180: #3005 AHF Zubuchen innerhalb einer Kundennummer
#3005 AHF Zubuchen innerhalb einer Kundennummer

Related work items: #3005
2022-04-12 15:36:44 +00:00
Lorenz Hilpert
c184df717d #3021 - Remission offene WBS werden nicht angezeigt 2022-04-12 16:07:38 +02:00
Lorenz Hilpert
26a7348d25 Dashboard Styling 2022-04-12 14:55:59 +02:00
Lorenz Hilpert
cf5052cbe5 Merge branch 'develop' of https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend into develop 2022-04-12 14:48:02 +02:00
Lorenz Hilpert
be848123a1 Dashboard Product Navigation 2022-04-12 14:47:53 +02:00
Lorenz Hilpert
04232b85a7 Dasboard Product Navigation 2022-04-12 14:47:39 +02:00
Nino Righi
09bb84c34e Merged PR 1173: #2992 TK Fix PDF Viewer Content Sizing on Mobile
#2992 TK Fix PDF Viewer Content Sizing on Mobile
2022-04-12 08:21:36 +00:00
Lorenz Hilpert
4449992442 Scanner Fix Test 2022-04-11 17:06:45 +02:00
Andreas Schickinger
39c40f2e13 Merged PR 1179: #2742 AHF Zubuchen Button mit Zusatz anzeigen
#2742 AHF Zubuchen Button mit Zusatz anzeigen

Related work items: #2742
2022-04-11 13:37:50 +00:00
Nino Righi
9813575584 Merged PR 1178: #3004 Fix Ui Slider Show Scroll Arrow
#3004 Fix Ui Slider Show Scroll Arrow
2022-04-11 13:35:53 +00:00
Andreas Schickinger
b0af718cbc Merged PR 1176: #3001 Remission Grund Dropdown über Popup legen
#3001 Remission Grund Dropdown über Popup legen

Related work items: #3001
2022-04-11 06:53:51 +00:00
Andreas Schickinger
550544cbe4 Merged PR 1177: #972 Vorgang schließen Styling angepasst und Rechtschreibfehler behoben
#972 Vorgang schließen Styling angepasst und Rechtschreibfehler behoben

Related work items: #972
2022-04-11 06:53:22 +00:00
Andreas Schickinger
3ec3cf0e5b Merged PR 1175: Merge release in develop
Merge release in develop

Related work items: #2666, #2927, #2928, #2979, #2996
2022-04-07 14:06:57 +00:00
Nino Righi
0b79464e52 Merged PR 1174: #2999 Fix Customer Search Box Display Hint
#2999 Fix Customer Search Box Display Hint
2022-04-07 14:05:10 +00:00
Andreas Schickinger
a1642c5749 Merged PR 1172: #2996 Hotfix Listenbestellung Checkboxen bei Filialwechsel
#2996 Hotfix Listenbestellung Checkboxen bei Filialwechsel

Related work items: #2996
2022-04-06 16:22:41 +00:00
Andreas Schickinger
148aab1495 Merged PR 1171: #2928 Listenbestellung Download CanAdd Prüfung
#2928 Listenbestellung Download CanAdd Prüfung

Related work items: #2928
2022-04-06 14:18:20 +00:00
Lorenz Hilpert
2f78f2685f Prozessid aus Navigation für Artikelsuche und Kunden entfernt 2022-04-06 15:59:30 +02:00
Nino Righi
6dde5682a9 Merged PR 1170: #2995 Build Error Fix
#2995 Build Error Fix
2022-04-06 11:59:57 +00:00
Lorenz Hilpert
af8a3d89af Merged PR 1167: #2989 Scanner Refactoring
#2989  Scanner Refactoring
2022-04-06 10:18:20 +00:00
Lorenz Hilpert
ec97d1e84a CI Fix 2022-04-06 11:12:36 +02:00
Lorenz Hilpert
eea412abd3 #2993 WA WE - ORD: in Breadcrumb 2022-04-06 09:58:03 +02:00
Nino Righi
cf65ba3e6b Merged PR 1168: #2988 Fix Remission Close Add Product Modal if quantity changed to 0
#2988 Fix Remission Close Add Product Modal if quantity changed to 0
2022-04-06 07:39:00 +00:00
Nino Righi
3d4445bb46 Merged PR 1169: #2990 Fix Customer Search Cache Filter Settings
#2990 Fix Customer Search Cache Filter Settings
2022-04-06 07:37:12 +00:00
Andreas Schickinger
94753ceac4 Merged PR 1166: #2666 Hotfix Listenbestellung CanAddItems angepasst
#2666 Hotfix Listenbestellung CanAddItems angepasst

Related work items: #2666
2022-04-05 15:12:34 +00:00
Nino Righi
af16542ce5 Merged PR 1165: #2971 Fix Remission unique WBS
#2971 Fix Remission unique WBS
2022-04-05 15:12:08 +00:00
Lorenz Hilpert
e4c82441b8 #2987 Remission - Fehler bei Artikel hinzufügen 2022-04-05 16:05:00 +02:00
Lorenz Hilpert
8783802483 #1025 Schatten um Action-Button 2022-04-05 08:45:37 +02:00
Nino Righi
8ad28a16b0 Merged PR 1164: #2974 Fix CanSetCustomer - Customer Search Setting Filter from Route
#2974 Fix CanSetCustomer - Customer Search Setting Filter from Route
2022-04-04 16:14:21 +00:00
Andreas Schickinger
f9403649e6 Merged PR 1163: #626 Remission Hinweis Farbe bei Artikel hinzufügen
#626 Remission Hinweis Farbe bei Artikel hinzufügen

Related work items: #626
2022-04-04 15:51:18 +00:00
Andreas Schickinger
698af2ecc3 Merged PR 1162: #2666 Listenbestellung Sichtbarkeit der Radio-Buttons angepasst
#2666 Listenbestellung Sichtbarkeit der Radio-Buttons angepasst

Related work items: #2666
2022-04-04 14:39:53 +00:00
Nino Righi
c92649a8d4 Merged PR 1157: #2977 Fix Clear Cart after Process gets closed and reopened via Footer Proces...
#2977 Fix Clear Cart after Process gets closed and reopened via Footer Process generation
2022-04-04 12:30:41 +00:00
Nino Righi
dfd1847a2d Merged PR 1160: #2984 Added Card Feature To Navigation
#2984 Added Card Feature To Navigation
2022-04-04 12:30:03 +00:00
Andreas Schickinger
eeaafec80a Merged PR 1161: #2979 Hotfix Listenbestellung Fehlermeldung und Anpassungen
#2979 Listenbestellung Fehlermeldung und Anpassungen

Related work items: #2979
2022-04-04 12:19:37 +00:00
Nino Righi
896e91d4d9 Merged PR 1159: #2954 Fix Remission Result List no longer horizontally scrollable
#2954 Fix Remission Result List no longer horizontally scrollable
2022-04-04 11:46:06 +00:00
Nino Righi
d6507b428f Merged PR 1158: #2976 Added Option to Reset Filter Settings to TK, Customer and Remission Area
#2976 Added Option to Reset Filter Settings to TK, Customer and Remission Area
2022-04-04 11:44:39 +00:00
Lorenz Hilpert
6ff4d204c2 #2962 IPAd Login Fix 2022-04-04 13:43:17 +02:00
Nino Righi
8145436d1d Merged PR 1156: #2972 Fix Remission Start Remission Popup Updated if supplier is ZL
#2972 Fix Remission Start Remission Popup Updated if supplier is ZL
2022-03-30 11:34:09 +00:00
Nino Righi
25f22b46c5 Merged PR 1155: #2967 Fix Remission Placementtype Wording inside remit Popup
#2967 Fix Remission Placementtype Wording inside remit Popup
2022-03-30 11:33:42 +00:00
Nino Righi
558d846812 Merged PR 1154: #2969 Fix Remission IPAD Scan Popup Navigation
#2969 Fix Remission IPAD Scan Popup Navigation
2022-03-30 10:37:48 +00:00
Nino Righi
05916031ad Merged PR 1153: #2970 Fix Remission Display CTAs on List Elements
#2970 Fix Remission Display CTAs on List Elements
2022-03-30 10:08:51 +00:00
Andreas Schickinger
ffad6aa939 Merged PR 1152: #2755 OLA Nachbestellen Grund
#2755 OLA Nachbestellen Grund

Related work items: #2755
2022-03-30 10:02:35 +00:00
Nino Righi
cb22a39ffc Merged PR 1151: #2912 Ipad Reset Focus Changes
#2912 Ipad Reset Focus Changes
2022-03-29 16:21:20 +00:00
Nino Righi
c6130dcffb Merged PR 1150: #2912 Focus
#2912 Focus
2022-03-29 15:49:30 +00:00
Nino Righi
c9f4143204 Merged PR 1149: #2912 IPADs Fix Autofocus Searchbox
#2912 IPADs Fix Autofocus Searchbox
2022-03-29 15:19:11 +00:00
Nino Righi
fa0e1d7d60 Merged PR 1148: Code auskommentiert der zur Anmelde Dauerschleife auf den Ipads führt
Code auskommentiert der zur Anmelde Dauerschleife auf den Ipads führt
2022-03-29 15:04:09 +00:00
Andreas Schickinger
621b545e34 Merged PR 1143: #2666 Hotfix Listenbestellung Hindernismeldung
#2666 Hotfix Listenbestellung Hindernismeldung

Related work items: #2666, #2927
2022-03-29 14:59:34 +00:00
Nino Righi
53e3d90064 Merged PR 1147: #2962 #2956 Ipad Keycard Login Fix
#2962 #2956 Ipad Keycard Login Fix
2022-03-29 14:09:44 +00:00
Nino Righi
c175826fd3 Merged PR 1146: #2962 Keycard Ipad Login Fix
#2962 Keycard Ipad Login Fix
2022-03-29 13:42:20 +00:00
Nino Righi
c6b584d637 Merged PR 1145: #2962 Fix Keycard
#2962 Fix Keycard
2022-03-29 13:26:54 +00:00
Nino Righi
d992ce87a9 Merged PR 1144: #2962 Keycard Login Fix
#2962 Keycard Login Fix
2022-03-29 13:11:25 +00:00
Nino Righi
a87072e542 Merged PR 1142: #2962 Zwischencommit
#2962 Zwischencommit
2022-03-29 12:32:54 +00:00
Nino Righi
eff0388b8f Merged PR 1141: #2962 2956 Keycard Login IPAD Fix
#2962 2956 Keycard Login IPAD Fix
2022-03-29 12:02:34 +00:00
Nino Righi
9c517810ba Merged PR 1140: #2963 Remission Close Filter Overlay After Hitting Apply Filter Settings
#2963 Remission Close Filter Overlay After Hitting Apply Filter Settings
2022-03-29 11:21:47 +00:00
Nino Righi
882cbddec0 Merged PR 1139: #2912 Autofocus on Input
#2912 Autofocus on Input
2022-03-28 16:03:54 +00:00
Nino Righi
d188272cbf Merged PR 1138: #2912 setTimeout on focus event
#2912 setTimeout on focus event
2022-03-28 15:46:44 +00:00
Nino Righi
72b3688365 Merged PR 1137: #2951 Fix Scanner PopUp
#2951 Fix Scanner PopUp
2022-03-28 14:48:35 +00:00
Andreas Schickinger
0f81914875 Merged PR 1135: #2774 AHF Cover Zusatz
#2774 AHF Cover Zusatz

Related work items: #2774
2022-03-28 13:04:37 +00:00
Nino Righi
e8e895d7b1 Merged PR 1136: #2951 Updated Test Config files and disabled login scanner popup
#2951 Updated Test Config files and disabled login scanner popup
2022-03-28 12:44:59 +00:00
Nino Righi
f0cc76f180 Merged PR 1134: Merge ISA 2.0 into Develop
Merge ISA 2.0 into Develop

Related work items: #1098, #2592, #2630, #2633, #2635, #2639, #2706, #2707, #2813, #2818, #2825, #2843, #2846, #2847, #2848, #2851, #2852, #2853, #2897, #2900
2022-03-28 10:12:12 +00:00
Lorenz Hilpert
91b3f44c1e Merge branch 'release/1.7' into develop 2022-03-28 09:14:12 +08:00
Lorenz Hilpert
43859599f0 Merge branch 'develop' into release/1.7 2022-03-28 09:13:33 +08:00
Andreas Schickinger
4dff0b1e6a Merged PR 1133: #2931 DIG Lieferzeitfenster Punkt fehlt
#2931 DIG Lieferzeitfenster Punkt fehlt

Related work items: #2931
2022-03-25 09:44:33 +00:00
Andreas Schickinger
f5fcee4e4a Merged PR 1132: Merge release in develop
Merge release in develop

Related work items: #2756, #2864, #2872, #2878, #2889, #2890, #2901, #2903, #2904, #2910
2022-03-24 13:21:09 +00:00
Andreas Schickinger
9ffb0b9a97 Merged PR 1131: Merge develop in release
Merge develop in release

Related work items: #2756, #2901, #2903, #2904, #2910
2022-03-24 13:06:34 +00:00
Andreas Schickinger
34698aca5e Merged PR 1130: #2910 Listenbestellung WK iPad Layout
#2910 Listenbestellung WK iPad Layout

Related work items: #2910
2022-03-23 12:57:13 +00:00
Lorenz Hilpert
4fcf9fabbf #2915 Trefferliste - klickbarer Bereich um Bullet-Checkbox 2022-03-23 20:09:47 +08:00
Nino Righi
fd907cf0cc Merged PR 1128: #2921 Listenbestellung B2B Orders Fix availabilities null for canAdd Request
#2921 Listenbestellung B2B Orders Fix availabilities null for canAdd Request
2022-03-23 11:49:34 +00:00
Nino Righi
cb543c7c98 Merged PR 1129: #2054 Checkout Summary Enable Print Button on B2B Order
#2054 Checkout Summary Enable Print Button on B2B Order
2022-03-23 11:44:09 +00:00
Andreas Schickinger
02ee730080 Merged PR 1126: #2901 Listenbestellung Sortierung
#2901 Listenbestellung Sortierung

Related work items: #2901
2022-03-22 14:25:55 +00:00
Nino Righi
5cccc5fedd Merged PR 1125: #2911 Bugfix Cart Font Size on Action CTAs
#2911 Bugfix Cart Font Size on Action CTAs
2022-03-21 17:33:55 +00:00
Andreas Schickinger
9b6f4d1ecf Merged PR 1124: #2756 Anmerkungsfeld mehrzeilig
#2756 Anmerkungsfeld mehrzeilig

Related work items: #2756
2022-03-21 16:57:15 +00:00
Nino Righi
022e8e9e73 Merged PR 1121: #2744 WA WE Order Item Details Display ssc and sscText
#2744 WA WE Order Item Details Display ssc and sscText
2022-03-21 14:43:07 +00:00
Andreas Schickinger
a81581e67f Merged PR 1119: #2904 Listenbestellung ipad 6 Mengen Dropdown Styling
#2904 Listenbestellung ipad 6 Mengen Dropdown Styling

Related work items: #2904
2022-03-21 12:58:25 +00:00
Andreas Schickinger
5823f57e03 Merged PR 1118: #2903 Listenbestellung Preis verschwindet bei Mengenänderung
#2903 Listenbestellung Preis verschwindet bei Mengenänderung

Related work items: #2903
2022-03-21 12:54:50 +00:00
Nico Hanus
96f2233421 add resource limits to helm files 2022-03-18 14:01:32 +01:00
Andreas Schickinger
ac1a772b21 Merged PR 1116: Merge develop into release/1.7
Merge develop into release

Related work items: #2864, #2872, #2878, #2889, #2890
2022-03-18 11:39:56 +00:00
Andreas Schickinger
04851dbe39 Merged PR 1114: #2890 Listenbestellung ipad Anpassungen
#2890 Listenbestellung ipad Anpassungen

Related work items: #2890
2022-03-17 14:44:56 +00:00
Andreas Schickinger
29181469db Merged PR 1113: #2872 Listenbestellung Warenkorb Abhol- und Lieferdatum anzeigen
#2872 Listenbestellung Warenkorb Abhol- und Lieferdatum anzeigen

Related work items: #2872
2022-03-17 13:13:39 +00:00
Andreas Schickinger
cb447e13f9 Merged PR 1112: #2889 Listenbestellung weitere ipad fixes
#2889 Listenbestellung weitere ipad fixes

Related work items: #2889
2022-03-17 12:27:52 +00:00
Andreas Schickinger
04a3b1767a Merged PR 1111: Listenbestellung ipad Modal Layout
Listenbestellung ipad Modal Layout
2022-03-17 10:59:51 +00:00
Andreas Schickinger
20f1a5c77e Merged PR 1110: #2878 Listenbestellung Bugfix endlos Loading, Spinner bei Übernehmen, Caching...
#2878 Listenbestellung Bugfix endlos Loading, Spinner bei Übernehmen, Caching für Logistician Request

Related work items: #2878
2022-03-16 16:36:37 +00:00
Andreas Schickinger
c979b48592 Merged PR 1108: #2846 Bei requestStatusCode 32 wird nun altAt angezeigt
#2846 Bei requestStatusCode 32 wird nun altAt angezeigt

Related work items: #2864
2022-03-15 17:09:45 +00:00
Michael Auer
88ebc39d65 Merge tag '1.6' into develop 2022-03-15 17:05:53 +01:00
Michael Auer
9aa3820e95 Merge branch 'release/1.6' 2022-03-15 17:05:46 +01:00
Andreas Schickinger
722ed6ade6 Merged PR 1105: #2773 Listenbestellung derzeit nicht bestellbar Farbe angepasst
#2773 Listenbestellung derzeit nicht Bestellbar Farbe angepasst

Related work items: #2773
2022-03-15 10:17:02 +00:00
Andreas Schickinger
8f7448a095 Merged PR 1102: #2643 DIG Lieferzeitfenster Kaufoptionen
#2643 DIG Lieferzeitfenster Kaufoptionen

Related work items: #2643
2022-03-15 10:12:22 +00:00
Andreas Schickinger
5e9b3b56d4 Merged PR 1101: #2843 Listenbestellung Autorenlink schwarz
#2843 Listenbestellung Autorenlink schwarz

Related work items: #2843
2022-03-15 09:48:19 +00:00
Andreas Schickinger
95656b20d7 Merged PR 1103: #2793 Listenbestellung QuantityDropdown für Rücklage begrenzen
#2793 Listenbestellung QuantityDropdown für Rücklage begrenzen

Related work items: #2793
2022-03-15 09:45:21 +00:00
Andreas Schickinger
12fe8b46c3 Merged PR 1104: #2662 Listenbestellung Download OLA im Warenkorb bei Bestellen Klick
#2662 Listenbestellung Download OLA im Warenkorb bei Bestellen Klick

Related work items: #2662
2022-03-15 09:00:12 +00:00
Nino Righi
92958f4b22 Merged PR 1097: #2782 TK Remove Color Indicator inside Calendar and List View for Items with...
#2782 TK Remove Color Indicator inside Calendar and List View for Items with an Updated Item
2022-03-10 14:39:50 +00:00
Andreas Schickinger
05a3bbef7a Merged PR 1096: #2843 Listenbestellung Warenkorb Verlinkung für Artikeldetails und Autorsuche
#2843 Listenbestellung Warenkorb Verlinkung für Artikeldetails und Autorsuche

Related work items: #2843
2022-03-10 14:33:15 +00:00
Nino Righi
03467fcb83 Merged PR 1091: #2841 TK removed hours and minutes inside task info taskDate range
#2841 TK removed hours and minutes inside task info taskDate range
2022-03-09 13:29:03 +00:00
Nino Righi
e96c98e344 Merged PR 1089: #2796 #2795 List Order Changed Order of displayed purchasing options and show...
#2796 #2795 List Order Changed Order of displayed purchasing options and show instock if take away is available
2022-03-08 14:08:49 +00:00
Michael Auer
c660c5626d ~ Version Bump: 1.7 2022-03-08 14:18:57 +01:00
Nino Righi
b443c7a5de Merged PR 1088: Merge Listenbestellung into Develop
Merge Listenbestellung into Develop

Related work items: #2560, #2655, #2656, #2699, #2745, #2746, #2747, #2749, #2752, #2760, #2789
2022-03-08 12:25:32 +00:00
Lorenz Hilpert
578f3fee7a Merge branch 'release/1.6' into develop 2022-03-01 10:45:56 +01:00
Lorenz Hilpert
caddcd0e2b Merge branch 'develop' into release/1.6 2022-03-01 10:45:02 +01:00
Michael Auer
cce810d4e3 ~ Version Bump: 1.6 2022-03-01 10:27:31 +01:00
Lorenz Hilpert
2f060e6209 #2783 Nullabfrage auf quantity 2022-02-28 17:25:06 +01:00
Lorenz Hilpert
df94c1ab59 #2783 Teilabholung - mehrere Exemplare von einem Artikel nicht nacheinander abholbar 2022-02-28 13:15:22 +01:00
Nino Righi
9c2ed96331 Merged PR 1075: #2729 Article Details Show Archiv Article Badge with matching text if article...
#2729 Article Details Show Archiv Article Badge with matching text if article is Available or not
2022-02-24 17:45:49 +00:00
Andreas Schickinger
b462e39a51 Merged PR 1073: #2628 HFI Lieferschein drucken
#2628 HFI Lieferschein drucken

Related work items: #2628
2022-02-23 14:01:36 +00:00
Nino Righi
8340649292 Merged PR 1059: #2733 Bugfix WK Notification, select checkbox SMS after input of mobilenumber
#2733 Bugfix WK Notification, select checkbox SMS after input of mobilenumber
2022-02-17 17:02:18 +00:00
Nino Righi
1d2df695d3 Merged PR 1056: #2696 Upgrade of p4mUser is now possible
#2696 Upgrade of p4mUser is now possible
2022-02-15 00:26:58 +00:00
Nino Righi
f46ef394d9 Merged PR 1054: #2671 Article Negative Price
#2671 Article Negative Price
2022-02-15 00:24:11 +00:00
Nino Righi
fcf016ea85 Merged PR 1053: #2689 Take RetailPrice if no catalog Price available for take-away option. Sh...
#2689 Take RetailPrice if no catalog Price available for take-away option. Show RetailPrice in Article Details View for the same case
2022-02-15 00:23:09 +00:00
Andreas Schickinger
e2ebba9f9f Merged PR 1051: #2668 Hotfix - Kubi leere Trefferliste bei Dialog
#2668 Hotfix - Kubi leere Trefferliste bei Dialog

Related work items: #2668
2022-02-09 16:20:57 +00:00
Nino Righi
d9460df0ca Merged PR 1045: #2688 WK Updated Show Custom Price Function
#2688 WK Updated Show Custom Price Function
2022-02-08 14:40:05 +00:00
Nino Righi
9d988e18be Merged PR 1044: #2604 ipad detection
#2604 ipad detection
2022-02-07 17:02:56 +00:00
Nino Righi
949ee7da6e Merged PR 1043: #2604 Hotfix ipad mini 6 detection
#2604 Hotfix ipad mini 6 detection
2022-02-07 16:53:19 +00:00
Nino Righi
736f402179 Merged PR 1042: #2604 Hotfix ipad mini 6 detection
#2604 Hotfix ipad mini 6 detection
2022-02-07 16:45:02 +00:00
Nino Righi
e5c4eb6a8e Merged PR 1041: #2604 Hotfix ipad 6
#2604 Hotfix ipad 6
2022-02-07 16:33:04 +00:00
Nino Righi
c93233674b Merged PR 1040: #2604 Hotfix Ipad 6 Remission Artikel Hinzufügen CTA
#2604 Hotfix Ipad 6 Remission Artikel Hinzufügen CTA
2022-02-07 16:29:29 +00:00
Nino Righi
02abf0852e Merged PR 1039: #2619 Customer Searchbox Placeholder Wording and Resizing
#2619 Customer Searchbox Placeholder Wording and Resizing
2022-02-07 14:58:57 +00:00
Nino Righi
cf3e5ce9a3 Merged PR 1038: #2604 Hotfix Ipad 6 Remission Artikel Hinzufügen CTA
#2604 Hotfix Ipad 6 Remission Artikel Hinzufügen CTA
2022-02-07 14:24:06 +00:00
Lorenz Hilpert
da71454070 Merged PR 1035: #2504 Remivorschau-ChangeStatus-removed
#2504 Remivorschau-ChangeStatus-removed
2022-02-02 15:52:23 +00:00
Lorenz Hilpert
08a8575025 Benamung von tags fue unit tests 2022-02-01 13:45:33 +01:00
Lorenz Hilpert
a99494b6ea Data Attribute für e2e tests hinzugefuegt 2022-01-28 11:00:33 +01:00
Andreas Schickinger
52ab4fccbd Merged PR 1024: #2504 Remissionsvorschau Navigation in Details
#2504 Remissionsvorschau Navigation in Details

Related work items: #2504
2022-01-19 09:39:09 +00:00
Nino Righi
2ab1599fa3 Merged PR 1021: #2504 AHF Remissionsvorschau
#2504 AHF Remissionsvorschau
2022-01-13 15:21:07 +00:00
Michael Auer
f220dde3b2 Merge tag '1.5' into develop 2021-12-22 11:26:38 +01:00
Michael Auer
d027df8856 Merge branch 'release/1.5' 2021-12-22 11:26:36 +01:00
Michael Auer
1dc979baaf merge branch 'release/1.5' 2021-12-22 11:24:24 +01:00
Andreas Schickinger
19fe83ed25 Merged PR 1018: #2555 Hotfix Historie und Print Dialog doppelte Scrollbar
#2555 Hotfix Historie und Print Dialog doppelte Scrollbar

Related work items: #2555
2021-12-20 12:06:44 +00:00
Lorenz Hilpert
3c033a1f0d Merged PR 1017: #2556 Fehlermeldung - scrollPos
#2556 Fehlermeldung  - scrollPos

Related work items: #2556
2021-12-20 09:57:50 +00:00
Andreas Schickinger
be031fb702 Merged PR 1016: #2543 Hotfix PDP SSC Fehlermeldung
#2543 Hotfix PDP SSC Fehlermeldung

Related work items: #2543
2021-12-16 13:24:06 +00:00
Lorenz Hilpert
6cfbce4f16 Merge branch 'release/1.5' into develop 2021-12-10 10:50:36 +01:00
2728 changed files with 33578 additions and 82184 deletions

1
.gitignore vendored
View File

@@ -34,6 +34,7 @@ speed-measure-plugin.json
/.sass-cache
/connect.lock
/coverage
/testresults
/libpeerconnection.log
npm-debug.log
yarn-error.log

View File

@@ -3,7 +3,6 @@
"johnpapa.angular2",
"esbenp.prettier-vscode",
"angular.ng-template",
"ms-vscode.vscode-typescript-tslint-plugin",
"eg2.vscode-npm-script"
]
}
}

View File

@@ -1,5 +1,5 @@
#stage 1
FROM node:14 as node
FROM node:14 as base
ARG IS_PRODUCTION=false
ARG SEMVERSION=1.0.0
ARG BuildUniqueID
@@ -11,9 +11,19 @@ RUN npm version ${SEMVERSION}
RUN npm install --always-auth=false
RUN if [ "${IS_PRODUCTION}" = "true" ] ; then npm run-script build-prod ; else npm run-script build ; fi
# stage 2
FROM nginx:alpine
# stage final
FROM nginx:alpine as publish
ARG BuildUniqueID
LABEL build.uniqueid="${BuildUniqueID:-1}"
COPY --from=node /app/dist/sales /usr/share/nginx/html
COPY --from=node /app/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=base /app/dist/isa-app /usr/share/nginx/html
COPY --from=base /app/nginx.conf /etc/nginx/conf.d/default.conf
# stage npm test
FROM base as test
ARG BuildUniqueID
LABEL build.uniqueid="${BuildUniqueID:-1}"
RUN wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -q -O /tmp/chrome.deb && apt update && apt install -y /tmp/chrome.deb
# ignore exitcode, sonst gibts keinen container
RUN npm test || true
ENTRYPOINT [ "/bin/sleep", "60000" ]

View File

@@ -3,260 +3,6 @@
"version": 1,
"newProjectRoot": "apps",
"projects": {
"ui": {
"root": "libs/ui",
"sourceRoot": "libs/ui",
"projectType": "library",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"options": {
"tsConfig": "libs/ui/tsconfig.lib.json",
"project": "libs/ui/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "libs/ui/tsconfig.lib.prod.json"
}
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "libs/ui/src/test.ts",
"tsConfig": "libs/ui/tsconfig.spec.json",
"karmaConfig": "libs/ui/karma.conf.js"
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"libs/ui/tsconfig.lib.json",
"libs/ui/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"sales": {
"root": "apps/sales/",
"sourceRoot": "apps/sales/src",
"projectType": "application",
"prefix": "app",
"schematics": {},
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"aot": true,
"outputPath": "dist/sales",
"outputHashing": "all",
"index": "apps/sales/src/index.html",
"main": "apps/sales/src/main.ts",
"polyfills": "apps/sales/src/polyfills.ts",
"tsConfig": "apps/sales/tsconfig.app.json",
"assets": [
"apps/sales/src/favicon.ico",
"apps/sales/src/assets",
"apps/sales/src/manifest.webmanifest",
"apps/sales/src/browserconfig.xml",
"apps/sales/src/silent-refresh.html"
],
"styles": [
"apps/sales/src/styles.scss"
],
"stylePreprocessorOptions": {
"includePaths": [
"apps/sales/src/scss"
]
},
"scripts": [],
"customWebpackConfig": {
"path": "apps/sales/webpack.config.js"
}
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "apps/sales/src/environments/environment.ts",
"with": "apps/sales/src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "25kb"
}
],
"serviceWorker": true
},
"development": {
"budgets": [
{
"type": "anyComponentStyle",
"maximumWarning": "25kb"
}
]
}
}
},
"serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
"options": {
"browserTarget": "sales:build",
"customWebpackConfig": {
"path": "apps/sales/webpack.config.js"
}
},
"configurations": {
"test": {
"browserTarget": "sales:build:test"
},
"integration": {
"browserTarget": "sales:build:integration"
},
"staging": {
"browserTarget": "sales:build:staging"
},
"production": {
"browserTarget": "sales:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "sales:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "apps/sales/src/test.ts",
"polyfills": "apps/sales/src/polyfills.ts",
"tsConfig": "apps/sales/tsconfig.spec.json",
"karmaConfig": "apps/sales/karma.conf.js",
"styles": [
"apps/sales/src/styles.scss"
],
"stylePreprocessorOptions": {
"includePaths": [
"apps/sales/src/scss"
]
},
"scripts": [],
"assets": [
"apps/sales/src/favicon.ico",
"apps/sales/src/assets",
"apps/sales/src/manifest.webmanifest"
]
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"apps/sales/tsconfig.app.json",
"apps/sales/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"sales-e2e": {
"root": "apps/sales-e2e/",
"projectType": "application",
"prefix": "",
"architect": {
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "apps/sales-e2e/protractor.conf.js",
"devServerTarget": "sales:serve"
},
"configurations": {
"integration": {
"devServerTarget": "sales:serve:integration"
},
"production": {
"devServerTarget": "sales:serve:production"
}
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": "apps/sales-e2e/tsconfig.e2e.json",
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"sso": {
"root": "libs/sso",
"sourceRoot": "libs/sso/src",
"projectType": "library",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"options": {
"tsConfig": "libs/sso/tsconfig.lib.json",
"project": "libs/sso/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "libs/sso/tsconfig.lib.prod.json"
}
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "libs/sso/src/test.ts",
"tsConfig": "libs/sso/tsconfig.spec.json",
"karmaConfig": "libs/sso/karma.conf.js"
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"libs/sso/tsconfig.lib.json",
"libs/sso/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"@swagger/availability": {
"root": "apps/swagger/availability",
"sourceRoot": "apps/swagger/availability/src",
@@ -264,7 +10,7 @@
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"tsConfig": "apps/swagger/availability/tsconfig.lib.json",
"project": "apps/swagger/availability/ng-package.json"
@@ -304,7 +50,7 @@
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"tsConfig": "apps/swagger/checkout/tsconfig.lib.json",
"project": "apps/swagger/checkout/ng-package.json"
@@ -344,7 +90,7 @@
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"tsConfig": "apps/swagger/crm/tsconfig.lib.json",
"project": "apps/swagger/crm/ng-package.json"
@@ -384,7 +130,7 @@
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"tsConfig": "apps/swagger/isa/tsconfig.lib.json",
"project": "apps/swagger/isa/ng-package.json"
@@ -424,7 +170,7 @@
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"tsConfig": "apps/swagger/oms/tsconfig.lib.json",
"project": "apps/swagger/oms/ng-package.json"
@@ -464,7 +210,7 @@
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"tsConfig": "apps/swagger/print/tsconfig.lib.json",
"project": "apps/swagger/print/ng-package.json"
@@ -504,7 +250,7 @@
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"tsConfig": "apps/swagger/cat/tsconfig.lib.json",
"project": "apps/swagger/cat/ng-package.json"
@@ -544,7 +290,7 @@
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"tsConfig": "apps/swagger/eis/tsconfig.lib.json",
"project": "apps/swagger/eis/ng-package.json"
@@ -584,7 +330,7 @@
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"tsConfig": "apps/native-container/tsconfig.lib.json",
"project": "apps/native-container/ng-package.json"
@@ -624,7 +370,7 @@
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"tsConfig": "apps/isa/remission/tsconfig.lib.json",
"project": "apps/isa/remission/ng-package.json"
@@ -664,7 +410,7 @@
"prefix": "crm",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"tsConfig": "apps/domain/crm/tsconfig.lib.json",
"project": "apps/domain/crm/ng-package.json"
@@ -704,7 +450,7 @@
"prefix": "checkout",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"tsConfig": "apps/domain/checkout/tsconfig.lib.json",
"project": "apps/domain/checkout/ng-package.json"
@@ -3296,7 +3042,594 @@
}
}
}
},
"isa-app": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
},
"@schematics/angular:application": {
"strict": true
}
},
"root": "apps/isa-app",
"sourceRoot": "apps/isa-app/src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"allowedCommonJsDependencies": [
"lodash",
"pdfjs-dist/es5/build/pdf",
"pdfjs-dist/es5/web/pdf_viewer"
],
"outputPath": "dist/isa-app",
"index": "apps/isa-app/src/index.html",
"main": "apps/isa-app/src/main.ts",
"polyfills": "apps/isa-app/src/polyfills.ts",
"tsConfig": "apps/isa-app/tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": [
"apps/isa-app/src/favicon.ico",
"apps/isa-app/src/assets",
"apps/isa-app/src/config",
"apps/isa-app/src/silent-refresh.html",
"apps/isa-app/src/manifest.webmanifest"
],
"styles": [
"apps/isa-app/src/styles.scss"
],
"scripts": [],
"serviceWorker": true,
"ngswConfigPath": "apps/isa-app/ngsw-config.json"
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "25kb"
}
],
"fileReplacements": [
{
"replace": "apps/isa-app/src/environments/environment.ts",
"with": "apps/isa-app/src/environments/environment.prod.ts"
}
],
"outputHashing": "all"
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"browserTarget": "isa-app:build:production"
},
"development": {
"browserTarget": "isa-app:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "isa-app:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "apps/isa-app/src/test.ts",
"polyfills": "apps/isa-app/src/polyfills.ts",
"tsConfig": "apps/isa-app/tsconfig.spec.json",
"karmaConfig": "apps/isa-app/karma.conf.js",
"inlineStyleLanguage": "scss",
"assets": [
"apps/isa-app/src/favicon.ico",
"apps/isa-app/src/assets",
"apps/isa-app/src/manifest.webmanifest"
],
"styles": [
"apps/isa-app/src/styles.scss"
],
"scripts": []
}
}
}
},
"@core/config": {
"projectType": "library",
"root": "apps/core/config",
"sourceRoot": "apps/core/config/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "apps/core/config/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/core/config/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "apps/core/config/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "apps/core/config/src/test.ts",
"tsConfig": "apps/core/config/tsconfig.spec.json",
"karmaConfig": "apps/core/config/karma.conf.js"
}
}
}
},
"@core/auth": {
"projectType": "library",
"root": "apps/core/auth",
"sourceRoot": "apps/core/auth/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "apps/core/auth/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/core/auth/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "apps/core/auth/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "apps/core/auth/src/test.ts",
"tsConfig": "apps/core/auth/tsconfig.spec.json",
"karmaConfig": "apps/core/auth/karma.conf.js"
}
}
}
},
"@shell/footer": {
"projectType": "library",
"root": "apps/shell/footer",
"sourceRoot": "apps/shell/footer/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "apps/shell/footer/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/shell/footer/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "apps/shell/footer/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "apps/shell/footer/src/test.ts",
"tsConfig": "apps/shell/footer/tsconfig.spec.json",
"karmaConfig": "apps/shell/footer/karma.conf.js"
}
}
}
},
"@shell/process": {
"projectType": "library",
"root": "apps/shell/process",
"sourceRoot": "apps/shell/process/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "apps/shell/process/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/shell/process/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "apps/shell/process/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "apps/shell/process/src/test.ts",
"tsConfig": "apps/shell/process/tsconfig.spec.json",
"karmaConfig": "apps/shell/process/karma.conf.js"
}
}
}
},
"@page/dashboard": {
"projectType": "library",
"root": "apps/page/dashboard",
"sourceRoot": "apps/page/dashboard/src",
"prefix": "page",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "apps/page/dashboard/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/page/dashboard/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "apps/page/dashboard/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "apps/page/dashboard/src/test.ts",
"tsConfig": "apps/page/dashboard/tsconfig.spec.json",
"karmaConfig": "apps/page/dashboard/karma.conf.js"
}
}
}
},
"@domain/isa": {
"projectType": "library",
"root": "apps/domain/isa",
"sourceRoot": "apps/domain/isa/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "apps/domain/isa/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/domain/isa/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "apps/domain/isa/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "apps/domain/isa/src/test.ts",
"tsConfig": "apps/domain/isa/tsconfig.spec.json",
"karmaConfig": "apps/domain/isa/karma.conf.js"
}
}
}
},
"@core/logger": {
"projectType": "library",
"root": "apps/core/logger",
"sourceRoot": "apps/core/logger/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "apps/core/logger/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/core/logger/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "apps/core/logger/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "apps/core/logger/src/test.ts",
"tsConfig": "apps/core/logger/tsconfig.spec.json",
"karmaConfig": "apps/core/logger/karma.conf.js"
}
}
}
},
"@shell/filter-overlay": {
"projectType": "library",
"root": "apps/shell/filter-overlay",
"sourceRoot": "apps/shell/filter-overlay/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "apps/shell/filter-overlay/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/shell/filter-overlay/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "apps/shell/filter-overlay/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "apps/shell/filter-overlay/src/test.ts",
"tsConfig": "apps/shell/filter-overlay/tsconfig.spec.json",
"karmaConfig": "apps/shell/filter-overlay/karma.conf.js"
}
}
}
},
"@store/search-component-store": {
"projectType": "library",
"root": "apps/store/search-component-store",
"sourceRoot": "apps/store/search-component-store/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "apps/store/search-component-store/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/store/search-component-store/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "apps/store/search-component-store/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "apps/store/search-component-store/src/test.ts",
"tsConfig": "apps/store/search-component-store/tsconfig.spec.json",
"karmaConfig": "apps/store/search-component-store/karma.conf.js"
}
}
}
},
"@domain/remission": {
"projectType": "library",
"root": "apps/domain/remission",
"sourceRoot": "apps/domain/remission/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "apps/domain/remission/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/domain/remission/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "apps/domain/remission/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "apps/domain/remission/src/test.ts",
"tsConfig": "apps/domain/remission/tsconfig.spec.json",
"karmaConfig": "apps/domain/remission/karma.conf.js"
}
}
}
},
"@page/remission": {
"projectType": "library",
"root": "apps/page/remission",
"sourceRoot": "apps/page/remission/src",
"prefix": "page",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "apps/page/remission/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/page/remission/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "apps/page/remission/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "apps/page/remission/src/test.ts",
"tsConfig": "apps/page/remission/tsconfig.spec.json",
"karmaConfig": "apps/page/remission/karma.conf.js"
}
}
}
},
"@modal/notifications": {
"projectType": "library",
"root": "apps/modal/notifications",
"sourceRoot": "apps/modal/notifications/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "apps/modal/notifications/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/modal/notifications/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "apps/modal/notifications/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "apps/modal/notifications/src/test.ts",
"tsConfig": "apps/modal/notifications/tsconfig.spec.json",
"karmaConfig": "apps/modal/notifications/karma.conf.js"
}
}
}
},
"@ui/branch-dropdown": {
"projectType": "library",
"root": "apps/ui/branch-dropdown",
"sourceRoot": "apps/ui/branch-dropdown/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"tsConfig": "apps/ui/branch-dropdown/tsconfig.lib.json",
"project": "apps/ui/branch-dropdown/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/ui/branch-dropdown/tsconfig.lib.prod.json"
}
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "apps/ui/branch-dropdown/src/test.ts",
"tsConfig": "apps/ui/branch-dropdown/tsconfig.spec.json",
"karmaConfig": "apps/ui/branch-dropdown/karma.conf.js"
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"apps/ui/branch-dropdown/tsconfig.lib.json",
"apps/ui/branch-dropdown/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"@adapter/scan": {
"projectType": "library",
"root": "apps/adapter/scan",
"sourceRoot": "apps/adapter/scan/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "apps/adapter/scan/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/adapter/scan/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "apps/adapter/scan/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "apps/adapter/scan/src/test.ts",
"tsConfig": "apps/adapter/scan/tsconfig.spec.json",
"karmaConfig": "apps/adapter/scan/karma.conf.js"
}
}
}
},
"@core/toast": {
"projectType": "library",
"root": "apps/core/toast",
"sourceRoot": "apps/core/toast/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "apps/core/toast/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/core/toast/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "apps/core/toast/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "apps/core/toast/src/test.ts",
"tsConfig": "apps/core/toast/tsconfig.spec.json",
"karmaConfig": "apps/core/toast/karma.conf.js"
}
}
}
}
},
"defaultProject": "sales"
"defaultProject": "isa-app"
}

View File

@@ -0,0 +1,25 @@
# Scan
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.2.0.
## Code scaffolding
Run `ng generate component component-name --project scan` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project scan`.
> Note: Don't forget to add `--project scan` or else it will be added to the default project in your `angular.json` file.
## Build
Run `ng build scan` to build the project. The build artifacts will be stored in the `dist/` directory.
## Publishing
After building your library with `ng build scan`, go to the dist folder `cd dist/scan` and run `npm publish`.
## Running unit tests
Run `ng test scan` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.

View File

@@ -9,16 +9,25 @@ module.exports = function (config) {
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('karma-coverage'),
require('@angular-devkit/build-angular/plugins/karma'),
],
client: {
jasmine: {
// you can add configuration options for Jasmine here
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
// for example, you can disable the random execution with `random: false`
// or set a specific seed with `seed: 4321`
},
clearContext: false, // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir: require('path').join(__dirname, '../../coverage'),
reports: ['html', 'lcovonly'],
fixWebpackSourcePaths: true,
jasmineHtmlReporter: {
suppressAll: true, // removes the duplicated traces
},
coverageReporter: {
dir: require('path').join(__dirname, '../../../coverage/adapter/scan'),
subdir: '.',
reporters: [{ type: 'html' }, { type: 'text-summary' }],
},
reporters: ['progress', 'kjhtml'],
port: 9876,
@@ -27,5 +36,6 @@ module.exports = function (config) {
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true,
});
};

View File

@@ -0,0 +1,7 @@
{
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../../dist/adapter/scan",
"lib": {
"entryFile": "src/public-api.ts"
}
}

View File

@@ -0,0 +1,11 @@
{
"name": "@adapter/scan",
"version": "0.0.1",
"peerDependencies": {
"@angular/common": "^12.2.0",
"@angular/core": "^12.2.0"
},
"dependencies": {
"tslib": "^2.3.0"
}
}

View File

@@ -0,0 +1,46 @@
import { Injectable } from '@angular/core';
import { PromptModalData, UiModalService, UiPromptModalComponent } from '@ui/modal';
import { Observable } from 'rxjs';
import { ScanAdapter } from './scan-adapter';
@Injectable()
export class DevScanAdapter implements ScanAdapter {
constructor(private _modal: UiModalService) {}
getName(): string {
return 'Dev Scanner';
}
isPrimary(): boolean {
return true;
}
isReady(): boolean {
return true;
}
scan(): Observable<string> {
return new Observable((observer) => {
const modalRef = this._modal.open({
content: UiPromptModalComponent,
title: 'Scannen',
data: {
message: 'Diese Eingabemaske dient nur zu Entwicklungs und Testzwecken.',
placeholder: 'Scan Code',
confirmText: 'weiter',
cancelText: 'abbrechen',
} as PromptModalData,
});
const sub = modalRef.afterClosed$.subscribe((result) => {
observer.next(result.data);
observer.complete();
});
return () => {
modalRef.close();
sub.unsubscribe();
};
});
}
}

View File

@@ -0,0 +1,32 @@
import { Injectable } from '@angular/core';
import { NativeContainerService } from 'native-container';
import { Observable } from 'rxjs';
import { filter, map, take } from 'rxjs/operators';
import { ScanAdapter } from './scan-adapter';
@Injectable()
export class NativeScanAdapter implements ScanAdapter {
constructor(private readonly nativeContainerService: NativeContainerService) {}
getName(): string {
return 'Native Scanner';
}
isPrimary(): boolean {
return true;
}
isReady(): boolean {
// TODO: Fix Login Keycard Dauerschleife
return this.nativeContainerService.isUiWebview().isNative || this.nativeContainerService.isIpadMini6();
// return false;
}
scan(): Observable<string> {
return this.nativeContainerService.openScanner('scanBook').pipe(
filter((result) => result.status === 'SUCCESS'),
map((result) => result.data),
take(1)
);
}
}

View File

@@ -0,0 +1,11 @@
import { Observable } from 'rxjs';
export interface ScanAdapter {
getName(): string;
isPrimary(): boolean;
isReady(): boolean;
scan(): Observable<string>;
}

View File

@@ -0,0 +1,16 @@
import { NgModule } from '@angular/core';
import { DevScanAdapter } from './dev.scan-adapter';
import { NativeScanAdapter } from './native.scan-adapter';
import { SCAN_ADAPTER } from './tokens';
@NgModule({})
export class ScanAdapterModule {
static forRoot(dev?: boolean) {
return {
ngModule: ScanAdapterModule,
providers: [{ provide: SCAN_ADAPTER, useClass: NativeScanAdapter, multi: true }],
// Use for testing:
// providers: [{ provide: SCAN_ADAPTER, useClass: dev ? DevScanAdapter : NativeScanAdapter, multi: true }],
};
}
}

View File

@@ -0,0 +1,30 @@
import { Inject, Injectable } from '@angular/core';
import { ScanAdapter } from './scan-adapter';
import { SCAN_ADAPTER } from './tokens';
@Injectable({
providedIn: 'root',
})
export class ScanAdapterService {
constructor(@Inject(SCAN_ADAPTER) private readonly scanAdapters: ScanAdapter[]) {}
scanners() {
return this.scanAdapters.filter((adapter) => adapter.isReady());
}
scanner() {
return this.scanners().find((scanner) => scanner.isPrimary()) || this.scanners().find(() => true);
}
isReady() {
return this.scanAdapters.some((adapter) => adapter.isReady());
}
scan() {
const primaryScanner = this.scanner();
if (primaryScanner) {
return primaryScanner.scan();
}
return null;
}
}

View File

@@ -0,0 +1,4 @@
import { InjectionToken } from '@angular/core';
import { ScanAdapter } from './scan-adapter';
export const SCAN_ADAPTER = new InjectionToken<ScanAdapter>('SCAN_ADAPTER');

View File

@@ -0,0 +1,6 @@
/*
* Public API Surface of scan
*/
export * from './lib/scan.service';
export * from './lib/scan.module';

View File

@@ -1,13 +1,24 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone-testing';
import 'zone.js';
import 'zone.js/testing';
import { getTestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
declare const require: any;
declare const require: {
context(
path: string,
deep?: boolean,
filter?: RegExp
): {
keys(): string[];
<T>(id: string): T;
};
};
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { teardown: { destroyAfterEach: true } });
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.

View File

@@ -0,0 +1,20 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"outDir": "../../../out-tsc/lib",
"target": "es2015",
"declaration": true,
"declarationMap": true,
"inlineSources": true,
"types": [],
"lib": [
"dom",
"es2018"
]
},
"exclude": [
"src/test.ts",
"**/*.spec.ts"
]
}

View File

@@ -0,0 +1,10 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.lib.json",
"compilerOptions": {
"declarationMap": false
},
"angularCompilerOptions": {
"compilationMode": "partial"
}
}

View File

@@ -0,0 +1,17 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"outDir": "../../../out-tsc/spec",
"types": [
"jasmine"
]
},
"files": [
"src/test.ts"
],
"include": [
"**/*.spec.ts",
"**/*.d.ts"
]
}

View File

@@ -1,11 +1,12 @@
import { Inject, Injectable } from '@angular/core';
import { Config } from '@core/config';
import { CDN_PRODUCT_IMAGE } from './tokens';
@Injectable({
providedIn: 'root',
})
export class ProductImageService {
constructor(@Inject(CDN_PRODUCT_IMAGE) private imageUrl: string) {}
constructor(private readonly _config: Config) {}
getImageUrl({
imageId,
@@ -18,6 +19,6 @@ export class ProductImageService {
height?: number;
showDummy?: boolean;
}): string {
return `${this.imageUrl}/${imageId}_${width}x${height}.jpg?showDummy=${showDummy}`;
return `${this._config.get('@cdn/product-image.url')}/${imageId}_${width}x${height}.jpg?showDummy=${showDummy}`;
}
}

View File

@@ -1,7 +1,7 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone';
import 'zone.js/dist/zone-testing';
import 'zone.js';
import 'zone.js/testing';
import { getTestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';

View File

@@ -1,5 +1,8 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
const customLaunchers = require('../../../karma/custom-launchers');
const junitReporter = require('../../../karma/junit-reporter')('core-application');
const coverageReporter = require('../../../karma/coverage-reporter')('core-application');
module.exports = function (config) {
config.set({
@@ -9,23 +12,31 @@ module.exports = function (config) {
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('karma-coverage'),
require('karma-junit-reporter'),
require('@angular-devkit/build-angular/plugins/karma'),
],
client: {
jasmine: {
// you can add configuration options for Jasmine here
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
// for example, you can disable the random execution with `random: false`
// or set a specific seed with `seed: 4321`
},
clearContext: false, // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir: require('path').join(__dirname, '../../../coverage/core/application'),
reports: ['html', 'lcovonly', 'text-summary'],
fixWebpackSourcePaths: true,
jasmineHtmlReporter: {
suppressAll: true, // removes the duplicated traces
},
coverageReporter,
junitReporter,
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
customLaunchers,
singleRun: false,
restartOnFileChange: true,
});

View File

@@ -11,8 +11,13 @@ import { ApplicationService } from './application.service';
export class CoreApplicationModule {
static forRoot(): ModuleWithProviders<CoreApplicationModule> {
return {
ngModule: CoreApplicationModule,
providers: [ApplicationService, StoreModule.forFeature('core-application', applicationReducer).providers],
ngModule: RootCoreApplicationModule,
};
}
}
@NgModule({
imports: [StoreModule.forFeature('core-application', applicationReducer)],
providers: [ApplicationService],
})
export class RootCoreApplicationModule {}

View File

@@ -1,32 +1,233 @@
import { TestBed } from '@angular/core/testing';
import { isObservable } from 'rxjs';
import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator';
import { Store } from '@ngrx/store';
import { Observable, of } from 'rxjs';
import { first } from 'rxjs/operators';
import { ApplicationProcess } from './defs';
import { ApplicationService } from './application.service';
import * as actions from './store/application.actions';
describe('ApplicationService', () => {
let service: ApplicationService;
let spectator: SpectatorService<ApplicationService>;
let store: SpyObject<Store>;
const createService = createServiceFactory({
service: ApplicationService,
mocks: [Store],
});
beforeEach(() => {
TestBed.configureTestingModule({
providers: [ApplicationService],
});
service = TestBed.inject(ApplicationService);
spectator = createService({});
store = spectator.inject(Store);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
describe('activatedProcessId', () => {
it('should return the processId', () => {
service.setActivatedProcessId(100);
expect(service.activatedProcessId).toEqual(100);
});
expect(spectator.service).toBeTruthy();
});
describe('activatedProcessId$', () => {
it('should return an observable', () => {
expect(isObservable(service.activatedProcessId$)).toBeTruthy();
expect(spectator.service.activatedProcessId$).toBeInstanceOf(Observable);
});
});
describe('activatedProcessId', () => {
it('should return the process id as a number', () => {
spyOnProperty(spectator.service['activatedProcessIdSubject'] as any, 'value').and.returnValue(2);
expect(spectator.service.activatedProcessId).toBe(2);
});
});
describe('getProcesses$()', () => {
it('should call select on store and return all selected processes', async () => {
const processes: ApplicationProcess[] = [
{ id: 1, name: 'Vorgang', type: 'cart', section: 'customer', data: { count: 1 } },
{ id: 2, name: 'Vorgang', type: 'task-calendar', section: 'branch' },
];
store.select.and.returnValue(of(processes));
const result = await spectator.service.getProcesses$().pipe(first()).toPromise();
expect(result).toEqual(processes);
expect(store.select).toHaveBeenCalled();
});
it('should call select on store and return all section customer processes', async () => {
const processes: ApplicationProcess[] = [
{ id: 1, name: 'Vorgang', type: 'cart', section: 'customer', data: { count: 1 } },
{ id: 2, name: 'Vorgang', type: 'task-calendar', section: 'branch' },
];
store.select.and.returnValue(of(processes));
const result = await spectator.service.getProcesses$('customer').pipe(first()).toPromise();
expect(result).toEqual([processes[0]]);
expect(store.select).toHaveBeenCalled();
});
it('should call select on store and return all section branch processes', async () => {
const processes: ApplicationProcess[] = [
{ id: 1, name: 'Vorgang', type: 'cart', section: 'customer', data: { count: 1 } },
{ id: 2, name: 'Vorgang', type: 'task-calendar', section: 'branch' },
];
store.select.and.returnValue(of(processes));
const result = await spectator.service.getProcesses$('branch').pipe(first()).toPromise();
expect(result).toEqual([processes[1]]);
expect(store.select).toHaveBeenCalled();
});
});
describe('getProcessById$()', () => {
it('should return the process by id', async () => {
const processes: ApplicationProcess[] = [
{ id: 1, name: 'Vorgang 1', section: 'customer' },
{ id: 2, name: 'Vorgang 2', section: 'customer' },
];
spyOn(spectator.service, 'getProcesses$').and.returnValue(of(processes));
const process = await spectator.service.getProcessById$(1).toPromise();
expect(process.id).toBe(1);
});
});
describe('getSection$()', () => {
it('should return the selected section branch', async () => {
const section = 'branch';
store.select.and.returnValue(of(section));
const result = await spectator.service.getSection$().pipe(first()).toPromise();
expect(result).toEqual(section);
expect(store.select).toHaveBeenCalled();
});
});
describe('getActivatedProcessId$', () => {
it('should return the current selected activated process id', async () => {
const activatedProcessId = 2;
store.select.and.returnValue(of({ id: activatedProcessId }));
const result = await spectator.service.getActivatedProcessId$().pipe(first()).toPromise();
expect(result).toEqual(activatedProcessId);
expect(store.select).toHaveBeenCalled();
});
});
describe('activateProcess()', () => {
it('should dispatch action setActivatedProcess with argument activatedProcessId and action type', () => {
const activatedProcessId = 2;
spectator.service.activateProcess(activatedProcessId);
expect(store.dispatch).toHaveBeenCalledWith({ activatedProcessId, type: actions.setActivatedProcess.type });
});
});
describe('removeProcess()', () => {
it('should dispatch action removeProcess with argument processId and action type', () => {
const processId = 2;
spectator.service.removeProcess(processId);
expect(store.dispatch).toHaveBeenCalledWith({ processId, type: actions.removeProcess.type });
});
});
describe('createProcess()', () => {
it('should dispatch action addProcess with process', async () => {
const process: ApplicationProcess = {
id: 1,
name: 'Vorgang 1',
section: 'customer',
type: 'cart',
};
const timestamp = 100;
spyOn(spectator.service as any, '_createTimestamp').and.returnValue(timestamp);
spyOn(spectator.service, 'getProcessById$').and.returnValue(of(undefined));
await spectator.service.createProcess(process);
expect(store.dispatch).toHaveBeenCalledWith({
type: actions.addProcess.type,
process: {
...process,
activated: 0,
created: timestamp,
},
});
});
it('should throw an error if the process id is already existing', async () => {
const process: ApplicationProcess = {
id: 1,
name: 'Vorgang 1',
section: 'customer',
type: 'cart',
};
spyOn(spectator.service, 'getProcessById$').and.returnValue(of(process));
await expectAsync(spectator.service.createProcess(process)).toBeRejectedWithError('Process Id existiert bereits');
});
it('should throw an error if the process id is not a number', async () => {
const process: ApplicationProcess = {
id: undefined,
name: 'Vorgang 1',
section: 'customer',
type: 'cart',
};
spyOn(spectator.service, 'getProcessById$').and.returnValue(of({ id: 5, name: 'Vorgang 2', section: 'customer' }));
await expectAsync(spectator.service.createProcess(process)).toBeRejectedWithError('Process Id nicht gesetzt');
});
});
describe('patchProcess', () => {
it('should dispatch action patchProcess with changes', async () => {
const process: ApplicationProcess = {
id: 1,
name: 'Vorgang 1',
section: 'customer',
type: 'cart',
};
await spectator.service.patchProcess(process.id, process);
expect(store.dispatch).toHaveBeenCalledWith({
type: actions.patchProcess.type,
processId: process.id,
changes: {
...process,
},
});
});
});
describe('setSection()', () => {
it('should dispatch action setSection with argument section and action type', () => {
const section = 'customer';
spectator.service.setSection(section);
expect(store.dispatch).toHaveBeenCalledWith({ section, type: actions.setSection.type });
});
});
describe('getLastActivatedProcessWithSectionAndType()', () => {
it('should return the last activated process by section and type', async () => {
const processes: ApplicationProcess[] = [
{ id: 1, name: 'Vorgang 1', section: 'customer', type: 'cart', activated: 100 },
{ id: 2, name: 'Vorgang 2', section: 'customer', type: 'cart', activated: 200 },
{ id: 3, name: 'Vorgang 3', section: 'customer', type: 'goodsOut', activated: 300 },
];
spyOn(spectator.service, 'getProcesses$').and.returnValue(of(processes));
expect(await spectator.service.getLastActivatedProcessWithSectionAndType$('customer', 'cart').pipe(first()).toPromise()).toBe(
processes[1]
);
});
});
describe('getLastActivatedProcessWithSection()', () => {
it('should return the last activated process by section', async () => {
const processes: ApplicationProcess[] = [
{ id: 1, name: 'Vorgang 1', section: 'customer', activated: 100 },
{ id: 2, name: 'Vorgang 2', section: 'customer', activated: 200 },
{ id: 3, name: 'Vorgang 3', section: 'customer', activated: 300 },
];
spyOn(spectator.service, 'getProcesses$').and.returnValue(of(processes));
expect(await spectator.service.getLastActivatedProcessWithSection$('customer').pipe(first()).toPromise()).toBe(processes[2]);
});
});
describe('_createTimestamp', () => {
it('should return the current timestamp in ms', () => {
expect(spectator.service['_createTimestamp']()).toBeCloseTo(Date.now());
});
});
});

View File

@@ -1,37 +1,129 @@
import { Injectable } from '@angular/core';
import { Store } from '@ngrx/store';
import { BehaviorSubject } from 'rxjs';
import { processRemoved, selectSection, setSection } from './store';
import { isBoolean, isNumber } from '@utils/common';
import { BehaviorSubject, Observable } from 'rxjs';
import { first, map, switchMap } from 'rxjs/operators';
import { ApplicationProcess } from './defs';
import {
removeProcess,
selectSection,
selectProcesses,
setSection,
addProcess,
setActivatedProcess,
selectActivatedProcess,
patchProcess,
patchProcessData,
} from './store';
@Injectable()
export class ApplicationService {
/** @deprecated */
private activatedProcessIdSubject = new BehaviorSubject<number>(undefined);
/** @deprecated */
get activatedProcessId() {
return this.activatedProcessIdSubject.value;
}
/** @deprecated */
get activatedProcessId$() {
return this.activatedProcessIdSubject.asObservable();
}
readonly section$ = this.store.select(selectSection);
constructor(private store: Store) {}
setActivatedProcessId(processId: number) {
if (this.activatedProcessId !== processId) {
this.activatedProcessIdSubject.next(processId);
}
getProcesses$(section?: 'customer' | 'branch') {
const processes$ = this.store.select(selectProcesses);
return processes$.pipe(map((processes) => processes.filter((process) => (section ? process.section === section : true))));
}
getProcessById$(processId: number): Observable<ApplicationProcess> {
return this.getProcesses$().pipe(map((processes) => processes.find((process) => process.id === processId)));
}
getSection$() {
return this.store.select(selectSection);
}
/** @deprecated */
getActivatedProcessId$() {
return this.store.select(selectActivatedProcess).pipe(map((process) => process?.id));
}
activateProcess(activatedProcessId: number) {
this.store.dispatch(setActivatedProcess({ activatedProcessId }));
this.activatedProcessIdSubject.next(activatedProcessId);
}
removeProcess(processId: number) {
this.store.dispatch(processRemoved({ processId }));
this.store.dispatch(removeProcess({ processId }));
}
createProcess() {}
patchProcess(processId: number, changes: Partial<ApplicationProcess>) {
this.store.dispatch(patchProcess({ processId, changes }));
}
patchProcessData(processId: number, data: Record<string, any>) {
this.store.dispatch(patchProcessData({ processId, data }));
}
async createProcess(process: ApplicationProcess) {
const existingProcess = await this.getProcessById$(process?.id).pipe(first()).toPromise();
if (existingProcess?.id === process?.id) {
throw new Error('Process Id existiert bereits');
}
if (!isNumber(process.id)) {
throw new Error('Process Id nicht gesetzt');
}
if (!isBoolean(process.closeable)) {
process.closeable = true;
}
if (!isBoolean(process.confirmClosing)) {
process.confirmClosing = true;
}
process.created = this._createTimestamp();
process.activated = 0;
this.store.dispatch(addProcess({ process }));
}
setSection(section: 'customer' | 'branch') {
this.store.dispatch(setSection({ section }));
}
getLastActivatedProcessWithSectionAndType$(section: 'customer' | 'branch', type: string): Observable<ApplicationProcess> {
return this.getProcesses$(section).pipe(
map((processes) =>
processes
?.filter((process) => process.type === type)
?.reduce((latest, current) => {
if (!latest) {
return current;
}
return latest?.activated > current?.activated ? latest : current;
}, undefined)
)
);
}
getLastActivatedProcessWithSection$(section: 'customer' | 'branch'): Observable<ApplicationProcess> {
return this.getProcesses$(section).pipe(
map((processes) =>
processes?.reduce((latest, current) => {
if (!latest) {
return current;
}
return latest?.activated > current?.activated ? latest : current;
}, undefined)
)
);
}
private _createTimestamp() {
return Date.now();
}
}

View File

@@ -1,5 +1,11 @@
export interface ApplicationProcess {
id: number;
created?: number;
activated?: number;
name: string;
data: { [key: string]: any };
section: 'customer' | 'branch';
type?: string;
data?: { [key: string]: any };
closeable?: boolean;
confirmClosing?: boolean;
}

View File

@@ -1,7 +1,6 @@
// start:ng42.barrel
export * from './application.module';
export * from './application.service';
export * from './process.service';
export * from './defs';
export * from './store';
// end:ng42.barrel

View File

@@ -1,8 +0,0 @@
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class ProcessService {
constructor() {}
updateName(processId: number, name: string) {}
}

View File

@@ -1,10 +1,16 @@
import { createAction, props } from '@ngrx/store';
import { ApplicationProcess } from '..';
const prefix = '[CORE-APPLICATION]';
/**
* Action nach Entfernung eines Prozesses
*/
export const processRemoved = createAction(`${prefix} Process Removed`, props<{ processId: number }>());
export const setSection = createAction(`${prefix} Set Section`, props<{ section: 'customer' | 'branch' }>());
export const addProcess = createAction(`${prefix} Add Process`, props<{ process: ApplicationProcess }>());
export const removeProcess = createAction(`${prefix} Remove Process`, props<{ processId: number }>());
export const setActivatedProcess = createAction(`${prefix} Set Activated Process`, props<{ activatedProcessId: number }>());
export const patchProcess = createAction(`${prefix} Patch Process`, props<{ processId: number; changes: Partial<ApplicationProcess> }>());
export const patchProcessData = createAction(`${prefix} Patch Process Data`, props<{ processId: number; data: Record<string, any> }>());

View File

@@ -0,0 +1,200 @@
import { INITIAL_APPLICATION_STATE } from './application.state';
import * as actions from './application.actions';
import { applicationReducer } from './application.reducer';
import { ApplicationProcess } from '../defs';
import { ApplicationState } from './application.state';
describe('applicationReducer', () => {
describe('setSection()', () => {
it('should return modified state with section customer', () => {
const initialState = INITIAL_APPLICATION_STATE;
const action = actions.setSection({ section: 'customer' });
const state = applicationReducer(initialState, action);
expect(state).toEqual({
...initialState,
section: 'customer',
});
});
it('should return modified state with section branch', () => {
const initialState = INITIAL_APPLICATION_STATE;
const action = actions.setSection({ section: 'branch' });
const state = applicationReducer(initialState, action);
expect(state).toEqual({
...initialState,
section: 'branch',
});
});
});
describe('addProcess()', () => {
it('should return modified state with new process if no processes are registered in the state', () => {
const initialState = INITIAL_APPLICATION_STATE;
const process: ApplicationProcess = {
id: 1,
name: 'Vorgang',
section: 'customer',
type: 'cart',
data: {},
};
const action = actions.addProcess({ process });
const state = applicationReducer(initialState, action);
expect(state.processes[0]).toEqual(process);
});
});
describe('patchProcess()', () => {
it('should return modified state with updated process when id is found', () => {
const initialState = INITIAL_APPLICATION_STATE;
const process: ApplicationProcess = {
id: 1,
name: 'Vorgang',
section: 'customer',
type: 'cart',
};
const action = actions.patchProcess({ processId: process.id, changes: { ...process, name: 'Test' } });
const state = applicationReducer(
{
...initialState,
processes: [process],
},
action
);
expect(state.processes[0].name).toEqual('Test');
});
it('should return unmodified state when id is not existing', () => {
const initialState = INITIAL_APPLICATION_STATE;
const process: ApplicationProcess = {
id: 1,
name: 'Vorgang',
section: 'customer',
type: 'cart',
};
const action = actions.patchProcess({ processId: process.id, changes: { ...process, id: 2 } });
const state = applicationReducer(
{
...initialState,
processes: [process],
},
action
);
expect(state.processes).toEqual([process]);
});
});
describe('removeProcess()', () => {
it('should return initial state if no processes are registered in the state', () => {
const initialState = INITIAL_APPLICATION_STATE;
const action = actions.removeProcess({ processId: 2 });
const state = applicationReducer(initialState, action);
expect(state).toEqual(initialState);
});
it('should return the unmodified state if processId not found', () => {
const initialState = INITIAL_APPLICATION_STATE;
const modifiedState: ApplicationState = {
...initialState,
section: 'customer',
processes: [
{
id: 1,
name: 'Vorgang',
section: 'customer',
type: 'cart',
},
{
id: 4,
name: 'Vorgang',
section: 'customer',
type: 'goods-out',
},
] as ApplicationProcess[],
};
const action = actions.removeProcess({ processId: 2 });
const state = applicationReducer(modifiedState, action);
expect(state).toEqual(modifiedState);
});
it('should return modified state, after process gets removed', () => {
const initialState = INITIAL_APPLICATION_STATE;
const modifiedState: ApplicationState = {
...initialState,
section: 'customer',
processes: [
{
id: 1,
name: 'Vorgang',
section: 'customer',
type: 'cart',
},
{
id: 2,
name: 'Vorgang',
section: 'customer',
type: 'goods-out',
},
] as ApplicationProcess[],
};
const action = actions.removeProcess({ processId: 2 });
const state = applicationReducer(modifiedState, action);
expect(state.processes).toEqual([
{
id: 1,
name: 'Vorgang',
section: 'customer',
type: 'cart',
},
]);
});
});
describe('setActivatedProcess()', () => {
it('should return modified state with process.activated value', () => {
const process: ApplicationProcess = {
id: 3,
name: 'Vorgang 3',
section: 'customer',
};
const initialState: ApplicationState = {
...INITIAL_APPLICATION_STATE,
processes: [process],
};
const action = actions.setActivatedProcess({ activatedProcessId: 3 });
const state = applicationReducer(initialState, action);
expect(state.processes[0].activated).toBeDefined();
});
it('should return modified state without process.activated value when activatedProcessId doesnt exist', () => {
const process: ApplicationProcess = {
id: 1,
name: 'Vorgang 3',
section: 'customer',
};
const initialState: ApplicationState = {
...INITIAL_APPLICATION_STATE,
processes: [process],
};
const action = actions.setActivatedProcess({ activatedProcessId: 3 });
const state = applicationReducer(initialState, action);
expect(state.processes[0].activated).toBeUndefined();
});
});
});

View File

@@ -1,10 +1,45 @@
import { Action, createReducer, on } from '@ngrx/store';
import { setSection } from './application.actions';
import { setSection, addProcess, removeProcess, setActivatedProcess, patchProcess, patchProcessData } from './application.actions';
import { ApplicationState, INITIAL_APPLICATION_STATE } from './application.state';
const _applicationReducer = createReducer(
INITIAL_APPLICATION_STATE,
on(setSection, (state, { section }) => ({ ...state, section }))
on(setSection, (state, { section }) => ({ ...state, section })),
on(addProcess, (state, { process }) => ({ ...state, processes: [...state.processes, { data: {}, ...process }] })),
on(removeProcess, (state, { processId }) => {
const processes = state?.processes?.filter((process) => process.id !== processId) || [];
return { ...state, processes };
}),
on(setActivatedProcess, (state, { activatedProcessId }) => {
const processes = state.processes.map((process) => {
if (process.id === activatedProcessId) {
return { ...process, activated: Date.now() };
}
return process;
});
return { ...state, processes };
}),
on(patchProcess, (state, { processId, changes }) => {
const processes = state.processes.map((process) => {
if (process.id === processId) {
return { ...process, ...changes, id: processId };
}
return process;
});
return { ...state, processes };
}),
on(patchProcessData, (state, { processId, data }) => {
const processes = state.processes.map((process) => {
if (process.id === processId) {
return { ...process, data: { ...(process.data || {}), ...data } };
}
return process;
});
return { ...state, processes };
})
);
export function applicationReducer(state: ApplicationState, action: Action) {

View File

@@ -0,0 +1,32 @@
import { ApplicationState } from './application.state';
import { ApplicationProcess } from '../defs';
import * as selectors from './application.selectors';
describe('applicationSelectors', () => {
it('should select the processes', () => {
const processes: ApplicationProcess[] = [{ id: 1, name: 'Vorgang 1', section: 'customer' }];
const state: Partial<ApplicationState> = {
processes,
};
expect(selectors.selectProcesses.projector(state)).toEqual(processes);
});
it('should select the section', () => {
const state: Partial<ApplicationState> = {
section: 'customer',
};
expect(selectors.selectSection.projector(state)).toEqual('customer');
});
it('should select the activatedProcess', () => {
const processes: ApplicationProcess[] = [
{ id: 1, name: 'Vorgang 1', section: 'customer', activated: 100 },
{ id: 2, name: 'Vorgang 2', section: 'customer', activated: 300 },
{ id: 3, name: 'Vorgang 3', section: 'customer', activated: 200 },
];
const state: Partial<ApplicationState> = {
processes,
};
expect(selectors.selectActivatedProcess.projector(state)).toEqual(processes[1]);
});
});

View File

@@ -3,3 +3,14 @@ import { ApplicationState } from './application.state';
export const selectApplicationState = createFeatureSelector<ApplicationState>('core-application');
export const selectSection = createSelector(selectApplicationState, (s) => s.section);
export const selectProcesses = createSelector(selectApplicationState, (s) => s.processes);
export const selectActivatedProcess = createSelector(selectApplicationState, (s) =>
s?.processes?.reduce((process, current) => {
if (!process) {
return current;
}
return process.activated > current.activated ? process : current;
}, undefined)
);

View File

@@ -1,7 +1,11 @@
import { ApplicationProcess } from '../defs';
export interface ApplicationState {
processes: ApplicationProcess[];
section: 'customer' | 'branch';
}
export const INITIAL_APPLICATION_STATE: ApplicationState = {
processes: [],
section: 'customer',
};

View File

@@ -1,7 +1,7 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone';
import 'zone.js/dist/zone-testing';
import 'zone.js';
import 'zone.js/testing';
import { getTestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';

25
apps/core/auth/README.md Normal file
View File

@@ -0,0 +1,25 @@
# Auth
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.2.0.
## Code scaffolding
Run `ng generate component component-name --project auth` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project auth`.
> Note: Don't forget to add `--project auth` or else it will be added to the default project in your `angular.json` file.
## Build
Run `ng build auth` to build the project. The build artifacts will be stored in the `dist/` directory.
## Publishing
After building your library with `ng build auth`, go to the dist folder `cd dist/auth` and run `npm publish`.
## Running unit tests
Run `ng test auth` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.

View File

@@ -0,0 +1,43 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
const customLaunchers = require('../../../karma/custom-launchers');
const junitReporter = require('../../../karma/junit-reporter')('core-auth');
const coverageReporter = require('../../../karma/coverage-reporter')('core-auth');
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage'),
require('karma-junit-reporter'),
require('@angular-devkit/build-angular/plugins/karma'),
],
client: {
jasmine: {
// you can add configuration options for Jasmine here
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
// for example, you can disable the random execution with `random: false`
// or set a specific seed with `seed: 4321`
},
clearContext: false, // leave Jasmine Spec Runner output visible in browser
},
jasmineHtmlReporter: {
suppressAll: true, // removes the duplicated traces
},
coverageReporter,
junitReporter,
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
customLaunchers,
singleRun: false,
restartOnFileChange: true,
});
};

View File

@@ -0,0 +1,7 @@
{
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../../dist/core/auth",
"lib": {
"entryFile": "src/public-api.ts"
}
}

View File

@@ -0,0 +1,11 @@
{
"name": "@core/auth",
"version": "0.0.1",
"peerDependencies": {
"@angular/common": "^12.2.0",
"@angular/core": "^12.2.0"
},
"dependencies": {
"tslib": "^2.3.0"
}
}

View File

@@ -0,0 +1,17 @@
import { ModuleWithProviders, NgModule } from '@angular/core';
import { AuthService } from './auth.service';
import { OAuthModule } from 'angular-oauth2-oidc';
@NgModule({})
export class AuthModule {
static forRoot(): ModuleWithProviders<AuthModule> {
return {
ngModule: AuthModule,
providers: [
AuthService,
OAuthModule.forRoot({
resourceServer: { sendAccessToken: true },
}).providers,
],
};
}
}

View File

@@ -0,0 +1,151 @@
import { Config } from '@core/config';
import { SpectatorService, createServiceFactory, SpyObject } from '@ngneat/spectator';
import { OAuthService } from 'angular-oauth2-oidc';
import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';
describe('AuthService', () => {
let spectator: SpectatorService<AuthService>;
const createService = createServiceFactory({
service: AuthService,
mocks: [Config, OAuthService],
});
let config: SpyObject<Config>;
let oAuthService: SpyObject<OAuthService>;
beforeEach(() => {
spectator = createService();
config = spectator.inject(Config);
oAuthService = spectator.inject(OAuthService);
});
it('should be created', () => {
expect(spectator.service).toBeTruthy();
});
describe('init()', () => {
it('should configure the oAuthService', () => {
config.get.and.returnValue({});
spectator.service.init();
expect(oAuthService.configure).toHaveBeenCalledWith({
redirectUri: window.location.origin,
silentRefreshRedirectUri: window.location.origin + '/silent-refresh.html',
useSilentRefresh: true,
});
expect(oAuthService.tokenValidationHandler).toBeInstanceOf(JwksValidationHandler);
expect(oAuthService.setupAutomaticSilentRefresh).toHaveBeenCalled();
});
it('should load the discovery document', async () => {
config.get.and.returnValue({});
oAuthService.loadDiscoveryDocumentAndTryLogin.and.returnValue(Promise.resolve(true));
spyOn(spectator.service['_initialized'], 'next');
await spectator.service.init();
expect(oAuthService.loadDiscoveryDocumentAndTryLogin).toHaveBeenCalled();
expect(spectator.service['_initialized'].next).toHaveBeenCalledWith(true);
});
it('should throw an error if its already initialized', async () => {
spyOn(spectator.service['_initialized'], 'getValue').and.returnValue(true);
await expectAsync(spectator.service.init()).toBeRejectedWithError('AuthService is already initialized');
});
});
describe('isAuthenticated()', () => {
it('should call hasValidIdToken() and return its value', () => {
oAuthService.hasValidIdToken.and.returnValue(true);
expect(spectator.service.isAuthenticated()).toBeTrue();
expect(oAuthService.hasValidIdToken).toHaveBeenCalled();
});
});
describe('getToken()', () => {
it('should call getAccessToken() and return its value', () => {
oAuthService.getAccessToken.and.returnValue('token');
expect(spectator.service.getToken()).toEqual('token');
expect(oAuthService.getAccessToken).toHaveBeenCalled();
});
});
describe('getClaims()', () => {
it('should call getAccessToken() and return its value', () => {
oAuthService.getAccessToken.and.returnValue('token');
const claims = {
claim1: 'value',
claim2: 'value2',
};
spyOn(spectator.service, 'parseJwt').and.returnValue(claims);
expect(spectator.service.getClaims()).toEqual(claims);
expect(spectator.service.parseJwt).toHaveBeenCalledWith('token');
expect(oAuthService.getAccessToken).toHaveBeenCalled();
});
});
describe('getClaimByKey()', () => {
it('should call getClaims() and return its key value', () => {
spyOn(spectator.service, 'getClaims').and.returnValue({
claim1: 'value',
claim2: 'value2',
});
expect(spectator.service.getClaimByKey('claim1')).toEqual('value');
expect(spectator.service.getClaims).toHaveBeenCalled();
});
it('should return null if getClaims() returns null or undefined', () => {
spyOn(spectator.service, 'getClaims').and.returnValue(null);
expect(spectator.service.getClaimByKey('claim1')).toBeNull();
expect(spectator.service.getClaims).toHaveBeenCalled();
});
});
describe('parseJwt()', () => {
it('should return null if the token is null or undefined', () => {
expect(spectator.service.parseJwt(null)).toBeNull();
expect(spectator.service.parseJwt(undefined)).toBeNull();
});
it('should return the value of the key', () => {
const token =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ';
expect(spectator.service.parseJwt(token)).toEqual({
sub: '1234567890',
name: 'John Doe',
admin: true,
});
});
});
describe('login()', () => {
it('should call initLoginFlow()', () => {
spectator.service.login();
expect(oAuthService.initLoginFlow).toHaveBeenCalled();
});
});
describe('logout()', () => {
it('should call revokeTokenAndLogout()', async () => {
await spectator.service.logout();
expect(oAuthService.revokeTokenAndLogout).toHaveBeenCalled();
});
});
describe('getToken()', () => {
it('should return getAccessToken()', () => {
spectator.service.getToken();
expect(oAuthService.getAccessToken).toHaveBeenCalled();
});
});
describe('initialized', () => {
it('should return _initialized as Observable', () => {
spyOn(spectator.service['_initialized'], 'asObservable').and.callThrough();
expect(spectator.service.initialized$).toBeInstanceOf(Observable);
expect(spectator.service['_initialized'].asObservable).toHaveBeenCalled();
});
});
});

View File

@@ -0,0 +1,84 @@
import { Injectable } from '@angular/core';
import { Config } from '@core/config';
import { isNullOrUndefined } from '@utils/common';
import { AuthConfig, OAuthService } from 'angular-oauth2-oidc';
import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class AuthService {
private readonly _initialized = new BehaviorSubject<boolean>(false);
get initialized$() {
return this._initialized.asObservable();
}
constructor(private _config: Config, private readonly _oAuthService: OAuthService) {}
async init() {
if (this._initialized.getValue()) {
throw new Error('AuthService is already initialized');
}
const authConfig: AuthConfig = this._config.get('@core/auth');
authConfig.redirectUri = window.location.origin;
authConfig.silentRefreshRedirectUri = window.location.origin + '/silent-refresh.html';
authConfig.useSilentRefresh = true;
this._oAuthService.configure(authConfig);
this._oAuthService.tokenValidationHandler = new JwksValidationHandler();
this._oAuthService.setupAutomaticSilentRefresh();
await this._oAuthService.loadDiscoveryDocumentAndTryLogin();
this._initialized.next(true);
}
isAuthenticated() {
return this._oAuthService.hasValidIdToken();
}
getToken() {
return this._oAuthService.getAccessToken();
}
getClaims() {
const token = this._oAuthService.getAccessToken();
return this.parseJwt(token);
}
getClaimByKey(key: string) {
const claims = this.getClaims();
if (isNullOrUndefined(claims)) {
return null;
}
return claims[key];
}
parseJwt(token: string) {
if (isNullOrUndefined(token)) {
return null;
}
const base64Url = token.split('.')[1];
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
const encoded = window.atob(base64);
return JSON.parse(encoded);
}
login() {
this._oAuthService.initLoginFlow();
}
setKeyCardToken(token: string) {
this._oAuthService.customQueryParams = {
temp_token: token,
};
}
async logout() {
await this._oAuthService.revokeTokenAndLogout();
}
}

View File

@@ -0,0 +1,4 @@
// start:ng42.barrel
export * from './auth.module';
export * from './auth.service';
// end:ng42.barrel

View File

@@ -0,0 +1,5 @@
/*
* Public API Surface of auth
*/
export * from './lib';

View File

@@ -1,15 +1,24 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'core-js/es7/reflect';
import 'zone.js/dist/zone';
import 'zone.js/dist/zone-testing';
import 'zone.js';
import 'zone.js/testing';
import { getTestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
declare const require: any;
declare const require: {
context(
path: string,
deep?: boolean,
filter?: RegExp
): {
keys(): string[];
<T>(id: string): T;
};
};
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { teardown: { destroyAfterEach: true } });
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.

View File

@@ -0,0 +1,20 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"outDir": "../../../out-tsc/lib",
"target": "es2015",
"declaration": true,
"declarationMap": true,
"inlineSources": true,
"types": [],
"lib": [
"dom",
"es2018"
]
},
"exclude": [
"src/test.ts",
"**/*.spec.ts"
]
}

View File

@@ -0,0 +1,10 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.lib.json",
"compilerOptions": {
"declarationMap": false
},
"angularCompilerOptions": {
"compilationMode": "partial"
}
}

View File

@@ -0,0 +1,17 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"outDir": "../../../out-tsc/spec",
"types": [
"jasmine"
]
},
"files": [
"src/test.ts"
],
"include": [
"**/*.spec.ts",
"**/*.d.ts"
]
}

View File

@@ -3,7 +3,7 @@ import { Store } from '@ngrx/store';
import { getNumberId } from '@utils/id';
import { Observable } from 'rxjs';
import { map, take } from 'rxjs/operators';
import { first, map, take } from 'rxjs/operators';
import { Breadcrumb } from './defs';
import * as actions from './store/breadcrumb.actions';
@@ -29,6 +29,19 @@ export class BreadcrumbService {
return this.store.select(selectors.selectBreadcrumbsByKey, key);
}
getLastActivatedBreadcrumbByKey$(key: string | number): Observable<Breadcrumb> {
return this.getBreadcrumbByKey$(key).pipe(
map((crumbs) =>
crumbs.reduce((latest, current) => {
if (!latest) {
return current;
}
return latest.timestamp > current.timestamp ? latest : current;
}, undefined)
)
);
}
addBreadcrumb(breadcrumb: Breadcrumb): Breadcrumb {
const newBreadcrumb: Breadcrumb = { ...breadcrumb, id: getNumberId(), timestamp: Date.now(), changed: Date.now() };
this.store.dispatch(actions.addBreadcrumb({ breadcrumb: newBreadcrumb }));
@@ -39,6 +52,11 @@ export class BreadcrumbService {
this.store.dispatch(actions.updateBreadcrumb({ id: breadcrumbId, changes: { ...changes, changed: Date.now() } }));
}
async patchBreadcrumbByKeyAndTags(key: string | number, tags: string[], changes: Partial<Breadcrumb>) {
const crumbs = await this.getBreadcrumbsByKeyAndTags$(key, tags).pipe(first()).toPromise();
crumbs.forEach((crumb) => this.patchBreadcrumb(crumb.id, changes));
}
async addBreadcrumbIfNotExists(breadcrumb: Breadcrumb) {
const crumbs = await this.getBreadcrumbsByKeyAndTags$(breadcrumb.key, breadcrumb.tags).pipe(take(1)).toPromise();
if (crumbs.length === 0) {
@@ -112,6 +130,11 @@ export class BreadcrumbService {
this.store.dispatch(actions.removeManyBreadcrumb({ ids: breadcrumbsToRemove.map((crumb) => crumb.id) }));
}
async removeBreadcrumbsByKeyAndTags(key: number | string, tags: string[]) {
const crumbs = await this.getBreadcrumbsByKeyAndTags$(key, tags).pipe(first()).toPromise();
crumbs.forEach((crumb) => this.removeBreadcrumb(crumb.id));
}
getLatestBreadcrumbForSection(section: 'customer' | 'branch') {
return this.store
.select(selectors.selectBreadcrumbsBySection, { section })

View File

@@ -42,5 +42,5 @@ export interface Breadcrumb {
/**
* Applicatiuon Section
*/
section: 'branch' | 'customer';
section: string;
}

View File

@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { processRemoved } from '@core/application';
import { removeProcess } from '@core/application';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { NEVER } from 'rxjs';
import { mergeMap, tap, first, map } from 'rxjs/operators';
@@ -10,7 +10,7 @@ export class BreadcrumbEffects {
removeProcess$ = createEffect(
() =>
this.actions$.pipe(
ofType(processRemoved),
ofType(removeProcess),
mergeMap((action) =>
this.breadcrumb.getBreadcrumbByKey$(action.processId).pipe(
first(),

View File

@@ -1,7 +1,7 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone';
import 'zone.js/dist/zone-testing';
import 'zone.js';
import 'zone.js/testing';
import { getTestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';

View File

@@ -51,7 +51,7 @@ export class CacheService {
return cached.data;
}
private delete(token: Object, from: 'session' | 'persist' = 'session') {
delete(token: Object, from: 'session' | 'persist' = 'session') {
if (from === 'session') {
sessionStorage.removeItem(this.getKey(token));
} else if (from === 'persist') {

View File

@@ -1,7 +1,7 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone';
import 'zone.js/dist/zone-testing';
import 'zone.js';
import 'zone.js/testing';
import { getTestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';

View File

@@ -1,7 +1,7 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone';
import 'zone.js/dist/zone-testing';
import 'zone.js';
import 'zone.js/testing';
import { getTestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';

View File

@@ -0,0 +1,25 @@
# Config
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.2.0.
## Code scaffolding
Run `ng generate component component-name --project config` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project config`.
> Note: Don't forget to add `--project config` or else it will be added to the default project in your `angular.json` file.
## Build
Run `ng build config` to build the project. The build artifacts will be stored in the `dist/` directory.
## Publishing
After building your library with `ng build config`, go to the dist folder `cd dist/config` and run `npm publish`.
## Running unit tests
Run `ng test config` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.

View File

@@ -0,0 +1,43 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
const customLaunchers = require('../../../karma/custom-launchers');
const junitReporter = require('../../../karma/junit-reporter')('core-config');
const coverageReporter = require('../../../karma/coverage-reporter')('core-config');
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage'),
require('karma-junit-reporter'),
require('@angular-devkit/build-angular/plugins/karma'),
],
client: {
jasmine: {
// you can add configuration options for Jasmine here
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
// for example, you can disable the random execution with `random: false`
// or set a specific seed with `seed: 4321`
},
clearContext: false, // leave Jasmine Spec Runner output visible in browser
},
jasmineHtmlReporter: {
suppressAll: true, // removes the duplicated traces
},
coverageReporter,
junitReporter,
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
customLaunchers,
singleRun: false,
restartOnFileChange: true,
});
};

View File

@@ -0,0 +1,7 @@
{
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../../dist/core/config",
"lib": {
"entryFile": "src/public-api.ts"
}
}

View File

@@ -0,0 +1,11 @@
{
"name": "@core/config",
"version": "0.0.1",
"peerDependencies": {
"@angular/common": "^12.2.0",
"@angular/core": "^12.2.0"
},
"dependencies": {
"tslib": "^2.3.0"
}
}

View File

@@ -0,0 +1,8 @@
import { Observable } from 'rxjs';
/**
* Config loader interface for loading configurations
*/
export interface ConfigLoader {
load(): Promise<any>;
}

View File

@@ -0,0 +1,4 @@
// start:ng42.barrel
export * from './config-loader';
export * from './json.config-loader';
// end:ng42.barrel

View File

@@ -0,0 +1,36 @@
// unit test JsonConfigLoader
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator';
import { CORE_JSON_CONFIG_LOADER_URL } from '../tokens';
import { JsonConfigLoader } from './json.config-loader';
describe('JsonConfigLoader', () => {
let spectator: SpectatorService<JsonConfigLoader>;
const createService = createServiceFactory({
imports: [HttpClientTestingModule],
service: JsonConfigLoader,
mocks: [],
providers: [{ provide: CORE_JSON_CONFIG_LOADER_URL, useValue: '/assets/config.json' }],
});
let httpTestingController: HttpTestingController;
beforeEach(() => {
spectator = createService();
httpTestingController = spectator.inject(HttpTestingController);
});
it('should create', () => {
expect(spectator.service).toBeTruthy();
});
describe('load', () => {
it('should call the provided url', async () => {
const reqPromise = spectator.service.load();
const req = httpTestingController.expectOne('/assets/config.json');
req.flush({ unit: 'test' });
const result = await reqPromise;
httpTestingController.verify();
expect(result).toEqual({ unit: 'test' });
});
});
});

View File

@@ -0,0 +1,13 @@
import { HttpClient } from '@angular/common/http';
import { Inject, Injectable } from '@angular/core';
import { ConfigLoader } from './config-loader';
import { CORE_JSON_CONFIG_LOADER_URL } from '../tokens';
@Injectable()
export class JsonConfigLoader implements ConfigLoader {
constructor(@Inject(CORE_JSON_CONFIG_LOADER_URL) private url: string, private http: HttpClient) {}
load(): Promise<any> {
return this.http.get(this.url).toPromise();
}
}

View File

@@ -0,0 +1,7 @@
import { Type } from '@angular/core';
import { ConfigLoader } from './config-loaders';
export interface ConfigModuleOptions {
useConfigLoader: Type<ConfigLoader>;
jsonConfigLoaderUrl?: string;
}

View File

@@ -0,0 +1,28 @@
import { APP_INITIALIZER, ModuleWithProviders, NgModule } from '@angular/core';
import { CORE_CONFIG_LOADER } from '@core/config';
import { Config } from './config';
import { ConfigModuleOptions } from './config-module-options';
import { CORE_JSON_CONFIG_LOADER_URL } from './tokens';
export function _initializeConfigFactory(config: Config) {
return () => config.init();
}
@NgModule({})
export class ConfigModule {
static forRoot(options: ConfigModuleOptions): ModuleWithProviders<ConfigModule> {
const configLoaderProvider = {
provide: CORE_CONFIG_LOADER,
useClass: options.useConfigLoader,
};
return {
ngModule: ConfigModule,
providers: [
Config,
configLoaderProvider,
options.jsonConfigLoaderUrl ? { provide: CORE_JSON_CONFIG_LOADER_URL, useValue: options.jsonConfigLoaderUrl } : null,
],
};
}
}

View File

@@ -0,0 +1,45 @@
import { createServiceFactory, SpectatorService } from '@ngneat/spectator';
import { Config } from './config';
import { ConfigLoader } from './config-loaders';
import { CORE_CONFIG_LOADER } from './tokens';
class TestConfigLoader implements ConfigLoader {
load() {
return Promise.resolve({});
}
}
// Unit test Config
describe('Config', () => {
let spectator: SpectatorService<Config>;
const createService = createServiceFactory({
service: Config,
providers: [{ provide: CORE_CONFIG_LOADER, useClass: TestConfigLoader }],
});
let configLoader: ConfigLoader;
beforeEach(() => {
spectator = createService();
configLoader = spectator.inject(CORE_CONFIG_LOADER);
});
it('should create', () => {
expect(spectator.service).toBeTruthy();
});
describe('init()', () => {
it('should load config and assigns it to _config', async () => {
const config = { unit: 'test' };
spyOn(configLoader, 'load').and.returnValue(Promise.resolve(config));
await spectator.service.init();
expect(spectator.service['_config']).toEqual(config);
});
});
describe('get()', () => {
it('should return config value', () => {
spectator.service['_config'] = { test: 'test' };
expect(spectator.service.get('test')).toEqual('test');
});
});
});

View File

@@ -0,0 +1,27 @@
import { Inject, Injectable } from '@angular/core';
import { ReplaySubject } from 'rxjs';
import { ConfigLoader } from './config-loaders';
import { CORE_CONFIG_LOADER } from './tokens';
import { pick } from './utils';
@Injectable()
export class Config {
private _config: any;
private readonly _initilized = new ReplaySubject<void>(1);
get initialized() {
return this._initilized.asObservable();
}
constructor(@Inject(CORE_CONFIG_LOADER) private readonly _configLoader: ConfigLoader) {}
// load config and assign it to this._config
async init() {
this._config = await this._configLoader.load();
this._initilized.next();
}
get(path: string) {
return pick(path, this._config);
}
}

View File

@@ -0,0 +1,8 @@
// start:ng42.barrel
export * from './config-module-options';
export * from './config.module';
export * from './config';
export * from './tokens';
export * from './config-loaders';
export * from './utils';
// end:ng42.barrel

View File

@@ -0,0 +1,6 @@
import { InjectionToken } from '@angular/core';
import { ConfigLoader } from './config-loaders';
export const CORE_CONFIG_LOADER = new InjectionToken<ConfigLoader>('core.config.loader');
export const CORE_JSON_CONFIG_LOADER_URL = new InjectionToken<ConfigLoader>('core.json.config.loader.url');

View File

@@ -1,3 +1,3 @@
// start:ng42.barrel
export * from './flatten';
export * from './pick';
// end:ng42.barrel

View File

@@ -0,0 +1,41 @@
import { pick } from './pick';
describe('pick', () => {
it('should pick properties from the 1st level from the object', () => {
const obj = {
foo: 'bar',
};
expect(pick('foo', obj)).toEqual('bar');
});
it('should pick properties from the 2nd level from the object', () => {
const obj = {
foo: {
bar: 'baz',
},
};
expect(pick('foo.bar', obj)).toEqual('baz');
});
it('should pick properties from the 3rd level from the object', () => {
const obj = {
foo: {
bar: {
baz: 'qux',
},
},
};
expect(pick('foo.bar.baz', obj)).toEqual('qux');
});
it('should throw an error of obj is not an object', () => {
expect(() => pick('foo', 'bar')).toThrowError(`bar is not an object`);
});
it('should return undefined if the property is not found', () => {
const obj = {
foo: 'bar',
};
expect(pick('bar', obj)).toEqual(undefined);
});
});

View File

@@ -0,0 +1,33 @@
/**
* Pick a value from an object at a given path.
* @param path path of the value to pick
* @param obj object to pick from
* @returns the value at the path or undefined
* @throws if obj is not an object
*/
export function pick<T = any>(path: string, obj: Object): T {
const paths = path.split('.');
// check if obj is null or undefined
if (obj == null) {
return undefined;
}
// check if obj is of type object and not an array
// and throw an error if not
if (typeof obj !== 'object' || Array.isArray(obj)) {
throw new Error(`${obj} is not an object`);
}
let result = obj;
// loop through the path and pick the value
// early exit if the path is empty
for (const path of paths) {
result = result[path];
if (result == null) {
return undefined;
}
}
return result as T;
}

View File

@@ -0,0 +1,5 @@
/*
* Public API Surface of config
*/
export * from './lib';

View File

@@ -0,0 +1,25 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js';
import 'zone.js/testing';
import { getTestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
declare const require: {
context(
path: string,
deep?: boolean,
filter?: RegExp
): {
keys(): string[];
<T>(id: string): T;
};
};
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { teardown: { destroyAfterEach: true } });
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);

View File

@@ -0,0 +1,20 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"outDir": "../../../out-tsc/lib",
"target": "es2015",
"declaration": true,
"declarationMap": true,
"inlineSources": true,
"types": [],
"lib": [
"dom",
"es2018"
]
},
"exclude": [
"src/test.ts",
"**/*.spec.ts"
]
}

View File

@@ -0,0 +1,10 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.lib.json",
"compilerOptions": {
"declarationMap": false
},
"angularCompilerOptions": {
"compilationMode": "partial"
}
}

View File

@@ -0,0 +1,17 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"outDir": "../../../out-tsc/spec",
"types": [
"jasmine"
]
},
"files": [
"src/test.ts"
],
"include": [
"**/*.spec.ts",
"**/*.d.ts"
]
}

View File

@@ -1,7 +1,7 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone';
import 'zone.js/dist/zone-testing';
import 'zone.js';
import 'zone.js/testing';
import { getTestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';

View File

@@ -0,0 +1,25 @@
# Logger
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.2.0.
## Code scaffolding
Run `ng generate component component-name --project logger` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project logger`.
> Note: Don't forget to add `--project logger` or else it will be added to the default project in your `angular.json` file.
## Build
Run `ng build logger` to build the project. The build artifacts will be stored in the `dist/` directory.
## Publishing
After building your library with `ng build logger`, go to the dist folder `cd dist/logger` and run `npm publish`.
## Running unit tests
Run `ng test logger` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.

View File

@@ -0,0 +1,43 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
const customLaunchers = require('../../../karma/custom-launchers');
const junitReporter = require('../../../karma/junit-reporter')('core-logger');
const coverageReporter = require('../../../karma/coverage-reporter')('core-logger');
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage'),
require('karma-junit-reporter'),
require('@angular-devkit/build-angular/plugins/karma'),
],
client: {
jasmine: {
// you can add configuration options for Jasmine here
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
// for example, you can disable the random execution with `random: false`
// or set a specific seed with `seed: 4321`
},
clearContext: false, // leave Jasmine Spec Runner output visible in browser
},
jasmineHtmlReporter: {
suppressAll: true, // removes the duplicated traces
},
junitReporter,
coverageReporter,
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
customLaunchers,
singleRun: false,
restartOnFileChange: true,
});
};

View File

@@ -0,0 +1,7 @@
{
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../../dist/core/logger",
"lib": {
"entryFile": "src/public-api.ts"
}
}

View File

@@ -0,0 +1,11 @@
{
"name": "@core/logger",
"version": "0.0.1",
"peerDependencies": {
"@angular/common": "^12.2.0",
"@angular/core": "^12.2.0"
},
"dependencies": {
"tslib": "^2.3.0"
}
}

View File

@@ -0,0 +1,51 @@
import { createServiceFactory, SpectatorService } from '@ngneat/spectator';
import { ConsoleLogProvider } from './console-log.provider';
import { LogLevel } from './log-level';
describe('ConsoleLogProvider', () => {
let spectator: SpectatorService<ConsoleLogProvider>;
const createService = createServiceFactory({
service: ConsoleLogProvider,
});
beforeEach(() => {
spectator = createService();
});
it('should create', () => {
expect(spectator.service).toBeTruthy();
});
describe('log', () => {
it('should call console.debug', () => {
spyOn(console, 'debug');
spectator.service.log(LogLevel.DEBUG, 'test');
expect(console.debug).toHaveBeenCalledWith('test');
});
it('should call console.info', () => {
spyOn(console, 'info');
spectator.service.log(LogLevel.INFO, 'test');
expect(console.info).toHaveBeenCalledWith('test');
});
it('should call console.warn', () => {
spyOn(console, 'warn');
spectator.service.log(LogLevel.WARN, 'test');
expect(console.warn).toHaveBeenCalledWith('test');
});
it('should call console.error', () => {
spyOn(console, 'error');
spectator.service.log(LogLevel.ERROR, 'test');
expect(console.error).toHaveBeenCalledWith('test');
});
it('should not call console.log', () => {
spyOn(console, 'log');
spectator.service.log(LogLevel.OFF, 'test');
expect(console.log).not.toHaveBeenCalled();
});
});
});

View File

@@ -0,0 +1,25 @@
import { Injectable } from '@angular/core';
import { LogLevel } from './log-level';
import { LogProvider } from './log.provider';
@Injectable()
export class ConsoleLogProvider implements LogProvider {
log(logLevel: LogLevel, message: string, ...optionalParams: any[]): void {
switch (logLevel) {
case LogLevel.DEBUG:
console.debug(message, ...optionalParams);
break;
case LogLevel.INFO:
console.info(message, ...optionalParams);
break;
case LogLevel.WARN:
console.warn(message, ...optionalParams);
break;
case LogLevel.ERROR:
console.error(message, ...optionalParams);
break;
case LogLevel.OFF:
break;
}
}
}

View File

@@ -0,0 +1,8 @@
// start:ng42.barrel
export * from './console-log.provider';
export * from './log-level';
export * from './log.provider';
export * from './logger.module';
export * from './logger.service';
export * from './tokens';
// end:ng42.barrel

View File

@@ -0,0 +1,14 @@
export enum LogLevel {
DEBUG = 0,
INFO = 1,
WARN = 2,
ERROR = 3,
OFF = 4,
// aliases
debug = 0,
info = 1,
warn = 2,
error = 3,
off = 4,
}

View File

@@ -0,0 +1,6 @@
import { Injectable } from '@angular/core';
import { LogLevel } from './log-level';
export interface LogProvider {
log(logLevel: LogLevel, message: string, ...optionalParams: any[]): void;
}

View File

@@ -0,0 +1,31 @@
import { ModuleWithProviders, NgModule } from '@angular/core';
import { Config } from '@core/config';
import { ConsoleLogProvider } from './console-log.provider';
import { Logger } from './logger.service';
import { LOG_PROVIDER, LOG_LEVEL } from './tokens';
export function _logLevelProviderFactory(config: Config) {
return config.get('@core/logger.logLevel');
}
@NgModule({})
export class CoreLoggerModule {
static forRoot(): ModuleWithProviders<CoreLoggerModule> {
return {
ngModule: CoreLoggerModule,
providers: [
Logger,
{
provide: LOG_PROVIDER,
useClass: ConsoleLogProvider,
multi: true,
},
{
provide: LOG_LEVEL,
useFactory: _logLevelProviderFactory,
deps: [Config],
},
],
};
}
}

View File

@@ -0,0 +1,140 @@
import { SpectatorService, createServiceFactory } from '@ngneat/spectator';
import { LogLevel } from './log-level';
import { Logger } from './logger.service';
import { LOG_PROVIDER } from './tokens';
import { LOG_LEVEL } from '.';
describe('LoggerService', () => {
let spectator: SpectatorService<Logger>;
let logProviderMock1 = jasmine.createSpyObj('LogProvider', ['log']);
let logProviderMock2 = jasmine.createSpyObj('LogProvider', ['log']);
const createService = createServiceFactory({
service: Logger,
mocks: [Logger],
providers: [
{
provide: LOG_PROVIDER,
useValue: logProviderMock1,
multi: true,
},
{
provide: LOG_PROVIDER,
useValue: logProviderMock2,
multi: true,
},
{
provide: LOG_LEVEL,
useValue: LogLevel.DEBUG,
},
],
});
beforeEach(() => {
spectator = createService();
});
it('should create', () => {
expect(spectator.service).toBeTruthy();
});
const testData: {
serviceLogLevel: LogLevel;
callLogLevel: LogLevel;
shoudCall: boolean;
}[] = [
{ serviceLogLevel: LogLevel.DEBUG, callLogLevel: LogLevel.DEBUG, shoudCall: true },
{ serviceLogLevel: LogLevel.DEBUG, callLogLevel: LogLevel.INFO, shoudCall: true },
{ serviceLogLevel: LogLevel.DEBUG, callLogLevel: LogLevel.WARN, shoudCall: true },
{ serviceLogLevel: LogLevel.DEBUG, callLogLevel: LogLevel.ERROR, shoudCall: true },
{ serviceLogLevel: LogLevel.INFO, callLogLevel: LogLevel.DEBUG, shoudCall: false },
{ serviceLogLevel: LogLevel.INFO, callLogLevel: LogLevel.INFO, shoudCall: true },
{ serviceLogLevel: LogLevel.INFO, callLogLevel: LogLevel.WARN, shoudCall: true },
{ serviceLogLevel: LogLevel.INFO, callLogLevel: LogLevel.ERROR, shoudCall: true },
{ serviceLogLevel: LogLevel.WARN, callLogLevel: LogLevel.DEBUG, shoudCall: false },
{ serviceLogLevel: LogLevel.WARN, callLogLevel: LogLevel.INFO, shoudCall: false },
{ serviceLogLevel: LogLevel.WARN, callLogLevel: LogLevel.WARN, shoudCall: true },
{ serviceLogLevel: LogLevel.WARN, callLogLevel: LogLevel.ERROR, shoudCall: true },
{ serviceLogLevel: LogLevel.ERROR, callLogLevel: LogLevel.DEBUG, shoudCall: false },
{ serviceLogLevel: LogLevel.ERROR, callLogLevel: LogLevel.INFO, shoudCall: false },
{ serviceLogLevel: LogLevel.ERROR, callLogLevel: LogLevel.WARN, shoudCall: false },
{ serviceLogLevel: LogLevel.ERROR, callLogLevel: LogLevel.ERROR, shoudCall: true },
{ serviceLogLevel: LogLevel.OFF, callLogLevel: LogLevel.DEBUG, shoudCall: false },
{ serviceLogLevel: LogLevel.OFF, callLogLevel: LogLevel.INFO, shoudCall: false },
{ serviceLogLevel: LogLevel.OFF, callLogLevel: LogLevel.WARN, shoudCall: false },
{ serviceLogLevel: LogLevel.OFF, callLogLevel: LogLevel.ERROR, shoudCall: false },
];
describe('log()', () => {
beforeEach(() => {
logProviderMock1.log.calls.reset();
logProviderMock2.log.calls.reset();
});
for (const test of testData) {
if (test.shoudCall) {
it(`should call logProvider if logLevel is ${LogLevel[test.callLogLevel]} and serviceLogLevel is ${
LogLevel[test.serviceLogLevel]
}`, () => {
spectator.service['_logLevel'] = test.serviceLogLevel;
spectator.service.log(test.callLogLevel, 'test');
expect(logProviderMock1.log).toHaveBeenCalledTimes(1);
expect(logProviderMock2.log).toHaveBeenCalledTimes(1);
});
} else {
it(`should not call logProvider if logLevel is ${LogLevel[test.callLogLevel]} and serviceLogLevel is ${
LogLevel[test.serviceLogLevel]
}`, () => {
spectator.service['_logLevel'] = test.serviceLogLevel;
spectator.service.log(test.callLogLevel, 'test');
expect(logProviderMock1.log).not.toHaveBeenCalled();
expect(logProviderMock2.log).not.toHaveBeenCalled();
});
}
}
});
describe('warn()', () => {
it('should call log and logLevel should be WARN', () => {
spyOn(spectator.service, 'log');
spectator.service.warn('test', 'data');
expect(spectator.service.log).toHaveBeenCalledWith(LogLevel.WARN, 'test', 'data');
});
});
describe('info()', () => {
it('should call log and logLevel should be INFO', () => {
spyOn(spectator.service, 'log');
spectator.service.info('test', 'data');
expect(spectator.service.log).toHaveBeenCalledWith(LogLevel.INFO, 'test', 'data');
});
});
describe('debug()', () => {
it('should call log and logLevel should be DEBUG', () => {
spyOn(spectator.service, 'log');
spectator.service.debug('test', 'data');
expect(spectator.service.log).toHaveBeenCalledWith(LogLevel.DEBUG, 'test', 'data');
});
});
describe('error()', () => {
it('should call log and logLevel should be ERROR', () => {
spyOn(spectator.service, 'log');
spectator.service.error('test', 'data');
expect(spectator.service.log).toHaveBeenCalledWith(LogLevel.ERROR, 'test', 'data');
});
});
});

View File

@@ -0,0 +1,39 @@
import { Inject, Injectable } from '@angular/core';
import { LogLevel } from './log-level';
import { LogProvider } from './log.provider';
import { LOG_LEVEL, LOG_PROVIDER } from './tokens';
@Injectable()
export class Logger {
constructor(@Inject(LOG_PROVIDER) private readonly _loggerProviders: LogProvider[], @Inject(LOG_LEVEL) private _logLevel: LogLevel) {}
log(logLevel: LogLevel, message: string, ...optionalParams: any[]): void {
if (this._logLevel === LogLevel.OFF) {
return;
}
if (this._logLevel <= logLevel) {
console.log(this._logLevel, logLevel, this._logLevel <= logLevel);
this._loggerProviders.forEach((provider) => {
provider.log(logLevel, message, ...optionalParams);
});
}
}
warn(message: string, ...optionalParams: any[]): void {
this.log(LogLevel.WARN, message, ...optionalParams);
}
info(message: string, ...optionalParams: any[]): void {
this.log(LogLevel.INFO, message, ...optionalParams);
}
debug(message: string, ...optionalParams: any[]): void {
this.log(LogLevel.DEBUG, message, ...optionalParams);
}
error(message: string, ...optionalParams: any[]): void {
this.log(LogLevel.ERROR, message, ...optionalParams);
}
}

View File

@@ -0,0 +1,6 @@
import { LogProvider } from './log.provider';
import { InjectionToken } from '@angular/core';
import { LogLevel } from './log-level';
export const LOG_PROVIDER = new InjectionToken<LogProvider[]>('LOG_PROVIDER');
export const LOG_LEVEL = new InjectionToken<LogLevel>('LOG_LEVEL');

View File

@@ -0,0 +1,5 @@
/*
* Public API Surface of logger
*/
export * from './lib';

View File

@@ -0,0 +1,25 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js';
import 'zone.js/testing';
import { getTestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
declare const require: {
context(
path: string,
deep?: boolean,
filter?: RegExp
): {
keys(): string[];
<T>(id: string): T;
};
};
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { teardown: { destroyAfterEach: true } });
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);

View File

@@ -0,0 +1,20 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"outDir": "../../../out-tsc/lib",
"target": "es2015",
"declaration": true,
"declarationMap": true,
"inlineSources": true,
"types": [],
"lib": [
"dom",
"es2018"
]
},
"exclude": [
"src/test.ts",
"**/*.spec.ts"
]
}

View File

@@ -0,0 +1,10 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.lib.json",
"compilerOptions": {
"declarationMap": false
},
"angularCompilerOptions": {
"compilationMode": "partial"
}
}

View File

@@ -0,0 +1,17 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"outDir": "../../../out-tsc/spec",
"types": [
"jasmine"
]
},
"files": [
"src/test.ts"
],
"include": [
"**/*.spec.ts",
"**/*.d.ts"
]
}

View File

@@ -1,7 +1,7 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone';
import 'zone.js/dist/zone-testing';
import 'zone.js';
import 'zone.js/testing';
import { getTestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';

25
apps/core/toast/README.md Normal file
View File

@@ -0,0 +1,25 @@
# Toast
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.2.0.
## Code scaffolding
Run `ng generate component component-name --project toast` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project toast`.
> Note: Don't forget to add `--project toast` or else it will be added to the default project in your `angular.json` file.
## Build
Run `ng build toast` to build the project. The build artifacts will be stored in the `dist/` directory.
## Publishing
After building your library with `ng build toast`, go to the dist folder `cd dist/toast` and run `npm publish`.
## Running unit tests
Run `ng test toast` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.

View File

@@ -9,16 +9,25 @@ module.exports = function (config) {
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('karma-coverage'),
require('@angular-devkit/build-angular/plugins/karma'),
],
client: {
jasmine: {
// you can add configuration options for Jasmine here
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
// for example, you can disable the random execution with `random: false`
// or set a specific seed with `seed: 4321`
},
clearContext: false, // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir: require('path').join(__dirname, '../../coverage'),
reports: ['html', 'lcovonly'],
fixWebpackSourcePaths: true,
jasmineHtmlReporter: {
suppressAll: true, // removes the duplicated traces
},
coverageReporter: {
dir: require('path').join(__dirname, '../../../coverage/core/toast'),
subdir: '.',
reporters: [{ type: 'html' }, { type: 'text-summary' }],
},
reporters: ['progress', 'kjhtml'],
port: 9876,
@@ -27,5 +36,6 @@ module.exports = function (config) {
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true,
});
};

View File

@@ -0,0 +1,7 @@
{
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../../dist/core/toast",
"lib": {
"entryFile": "src/public-api.ts"
}
}

Some files were not shown because too many files have changed in this diff Show More