diff options
48 files changed, 284 insertions, 59 deletions
diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml index bc079cd4e9a..bd8298678a0 100644 --- a/.github/workflows/cypress.yml +++ b/.github/workflows/cypress.yml @@ -94,11 +94,56 @@ jobs: matrix: # Run multiple copies of the current job in parallel # Please increase the number or runners as your tests suite grows (0 based index for e2e tests) - containers: ["component", '0', '1', '2', '3', '4', '5', '6', '7'] + containers: ['component', 'setup', '0', '1', '2', '3', '4', '5', '6', '7'] # Hack as strategy.job-total includes the component and GitHub does not allow math expressions # Always align this number with the total of e2e runners (max. index + 1) total-containers: [8] + services: + mysql: + # Only start mysql if we are running the setup tests + image: ${{matrix.containers == 'setup' && 'ghcr.io/nextcloud/continuous-integration-mysql-8.4:latest' || ''}} + ports: + - '3306/tcp' + env: + MYSQL_ROOT_PASSWORD: rootpassword + MYSQL_USER: oc_autotest + MYSQL_PASSWORD: nextcloud + MYSQL_DATABASE: oc_autotest + options: --health-cmd="mysqladmin ping" --health-interval 5s --health-timeout 2s --health-retries 10 + + mariadb: + # Only start mariadb if we are running the setup tests + image: ${{matrix.containers == 'setup' && 'mariadb:11.4' || ''}} + ports: + - '3306/tcp' + env: + MYSQL_ROOT_PASSWORD: rootpassword + MYSQL_USER: oc_autotest + MYSQL_PASSWORD: nextcloud + MYSQL_DATABASE: oc_autotest + options: --health-cmd="mariadb-admin ping" --health-interval 5s --health-timeout 2s --health-retries 5 + + postgres: + # Only start postgres if we are running the setup tests + image: ${{matrix.containers == 'setup' && 'ghcr.io/nextcloud/continuous-integration-postgres-17:latest' || ''}} + ports: + - '5432/tcp' + env: + POSTGRES_USER: root + POSTGRES_PASSWORD: rootpassword + POSTGRES_DB: nextcloud + options: --mount type=tmpfs,destination=/var/lib/postgresql/data --health-cmd pg_isready --health-interval 5s --health-timeout 2s --health-retries 5 + + oracle: + # Only start oracle if we are running the setup tests + image: ${{matrix.containers == 'setup' && 'ghcr.io/gvenzl/oracle-free:23' || ''}} + ports: + - '1521' + env: + ORACLE_PASSWORD: oracle + options: --health-cmd healthcheck.sh --health-interval 20s --health-timeout 10s --health-retries 10 + name: runner ${{ matrix.containers }} steps: @@ -141,6 +186,7 @@ jobs: CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} SPLIT: ${{ matrix.total-containers }} SPLIT_INDEX: ${{ matrix.containers == 'component' && 0 || matrix.containers }} + SETUP_TESTING: ${{ matrix.containers == 'setup' && 'true' || '' }} - name: Upload snapshots and videos uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 diff --git a/apps/files/l10n/cs.js b/apps/files/l10n/cs.js index 0d9ab61cef5..acf20a0af79 100644 --- a/apps/files/l10n/cs.js +++ b/apps/files/l10n/cs.js @@ -73,7 +73,6 @@ OC.L10N.register( "Transferred from %1$s on %2$s" : "Převedeno z %1$s na %2$s", "Files compatibility" : "Kompatibilita souborů", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Umožňuje omezit názvy souborů aby bylo zajištěno, že soubory bude možné synchronizovat se všemi klienty. Ve výchozím stavu jsou povoleny veškeré názvy souborů, splňující standard POSIX (např. Linux nebo macOS).", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "Po povolení názvů souborů, kompatibilních s Windows, stávající soubory už nebude možné změnit, ale je možné je přejmenovat na platné nové názvy jejich vlastníkem.", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "Po povolení tohoto natavení je také možné soubory stěhovat automaticky. Další informace viz dokumentace k příkazu occ.", "Enforce Windows compatibility" : "Vynutit kompatibilitu s Windows", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "Toto bude blokovat použití názvů souborů, které nejsou platné na strojích s Windows, jako je použití vyhrazených názvů nebo speciálních znaků. Ale nevynutí kompatibilitu v případě rozlišování malých/VELKÝCH písmen.", diff --git a/apps/files/l10n/cs.json b/apps/files/l10n/cs.json index 029d7b5cd5c..fec4ee94d64 100644 --- a/apps/files/l10n/cs.json +++ b/apps/files/l10n/cs.json @@ -71,7 +71,6 @@ "Transferred from %1$s on %2$s" : "Převedeno z %1$s na %2$s", "Files compatibility" : "Kompatibilita souborů", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Umožňuje omezit názvy souborů aby bylo zajištěno, že soubory bude možné synchronizovat se všemi klienty. Ve výchozím stavu jsou povoleny veškeré názvy souborů, splňující standard POSIX (např. Linux nebo macOS).", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "Po povolení názvů souborů, kompatibilních s Windows, stávající soubory už nebude možné změnit, ale je možné je přejmenovat na platné nové názvy jejich vlastníkem.", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "Po povolení tohoto natavení je také možné soubory stěhovat automaticky. Další informace viz dokumentace k příkazu occ.", "Enforce Windows compatibility" : "Vynutit kompatibilitu s Windows", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "Toto bude blokovat použití názvů souborů, které nejsou platné na strojích s Windows, jako je použití vyhrazených názvů nebo speciálních znaků. Ale nevynutí kompatibilitu v případě rozlišování malých/VELKÝCH písmen.", diff --git a/apps/files/l10n/de.js b/apps/files/l10n/de.js index e1018075df1..465a4113512 100644 --- a/apps/files/l10n/de.js +++ b/apps/files/l10n/de.js @@ -73,7 +73,6 @@ OC.L10N.register( "Transferred from %1$s on %2$s" : "Übertragen von %1$s auf %2$s", "Files compatibility" : "Dateikompatibilität", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Ermöglicht die Einschränkung von Dateinamen, um sicherzustellen, dass Dateien mit allen Clients synchronisiert werden können. Standardmäßig sind alle unter POSIX (z. B. Linux oder macOS) gültigen Dateinamen zulässig.", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "Nach Aktivierung der Windows-kompatiblen Dateinamen können vorhandene Dateien nicht mehr geändert, aber von ihrem Besitzer in gültige neue Namen umbenannt werden.", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "Nach dem Aktivieren dieser Einstellung ist es auch möglich, Dateien automatisch zu migrieren. Weitere Informationen finden sich in der Dokumentation zum Befehl „occ“.", "Enforce Windows compatibility" : "Windows-Kompatibilität erzwingen", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "Dadurch werden Dateinamen blockiert, die auf Windows-Systemen unzulässig sind, z. B. reservierte Namen oder Sonderzeichen. Die Kompatibilität der Groß-/Kleinschreibung wird dadurch jedoch nicht erzwungen.", diff --git a/apps/files/l10n/de.json b/apps/files/l10n/de.json index 673f5c63b51..2df91e216b1 100644 --- a/apps/files/l10n/de.json +++ b/apps/files/l10n/de.json @@ -71,7 +71,6 @@ "Transferred from %1$s on %2$s" : "Übertragen von %1$s auf %2$s", "Files compatibility" : "Dateikompatibilität", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Ermöglicht die Einschränkung von Dateinamen, um sicherzustellen, dass Dateien mit allen Clients synchronisiert werden können. Standardmäßig sind alle unter POSIX (z. B. Linux oder macOS) gültigen Dateinamen zulässig.", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "Nach Aktivierung der Windows-kompatiblen Dateinamen können vorhandene Dateien nicht mehr geändert, aber von ihrem Besitzer in gültige neue Namen umbenannt werden.", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "Nach dem Aktivieren dieser Einstellung ist es auch möglich, Dateien automatisch zu migrieren. Weitere Informationen finden sich in der Dokumentation zum Befehl „occ“.", "Enforce Windows compatibility" : "Windows-Kompatibilität erzwingen", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "Dadurch werden Dateinamen blockiert, die auf Windows-Systemen unzulässig sind, z. B. reservierte Namen oder Sonderzeichen. Die Kompatibilität der Groß-/Kleinschreibung wird dadurch jedoch nicht erzwungen.", diff --git a/apps/files/l10n/de_DE.js b/apps/files/l10n/de_DE.js index fd1834ba5c2..5483daa286f 100644 --- a/apps/files/l10n/de_DE.js +++ b/apps/files/l10n/de_DE.js @@ -73,7 +73,6 @@ OC.L10N.register( "Transferred from %1$s on %2$s" : "Übertragen von %1$s an %2$s", "Files compatibility" : "Dateikompatibilität", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Ermöglicht die Einschränkung von Dateinamen, um sicherzustellen, dass Dateien mit allen Clients synchronisiert werden können. Standardmäßig sind alle unter POSIX (z. B. Linux oder macOS) gültigen Dateinamen zulässig.", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "Nach Aktivierung der Windows-kompatiblen Dateinamen können vorhandene Dateien nicht mehr geändert, aber von ihrem Besitzer in gültige neue Namen umbenannt werden.", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "Nach dem Aktivieren dieser Einstellung ist es auch möglich, Dateien automatisch zu migrieren. Weitere Informationen finden sich in der Dokumentation zum Befehl \"occ“.", "Enforce Windows compatibility" : "Windows-Kompatibilität erzwingen", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "Dadurch werden Dateinamen blockiert, die auf Windows-Systemen unzulässig sind, z. B. reservierte Namen oder Sonderzeichen. Die Kompatibilität der Groß-/Kleinschreibung wird dadurch jedoch nicht erzwungen.", diff --git a/apps/files/l10n/de_DE.json b/apps/files/l10n/de_DE.json index 2c3e20326d6..779131af5e1 100644 --- a/apps/files/l10n/de_DE.json +++ b/apps/files/l10n/de_DE.json @@ -71,7 +71,6 @@ "Transferred from %1$s on %2$s" : "Übertragen von %1$s an %2$s", "Files compatibility" : "Dateikompatibilität", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Ermöglicht die Einschränkung von Dateinamen, um sicherzustellen, dass Dateien mit allen Clients synchronisiert werden können. Standardmäßig sind alle unter POSIX (z. B. Linux oder macOS) gültigen Dateinamen zulässig.", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "Nach Aktivierung der Windows-kompatiblen Dateinamen können vorhandene Dateien nicht mehr geändert, aber von ihrem Besitzer in gültige neue Namen umbenannt werden.", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "Nach dem Aktivieren dieser Einstellung ist es auch möglich, Dateien automatisch zu migrieren. Weitere Informationen finden sich in der Dokumentation zum Befehl \"occ“.", "Enforce Windows compatibility" : "Windows-Kompatibilität erzwingen", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "Dadurch werden Dateinamen blockiert, die auf Windows-Systemen unzulässig sind, z. B. reservierte Namen oder Sonderzeichen. Die Kompatibilität der Groß-/Kleinschreibung wird dadurch jedoch nicht erzwungen.", diff --git a/apps/files/l10n/en_GB.js b/apps/files/l10n/en_GB.js index f19022f6ffb..2058bd2f2fc 100644 --- a/apps/files/l10n/en_GB.js +++ b/apps/files/l10n/en_GB.js @@ -73,7 +73,6 @@ OC.L10N.register( "Transferred from %1$s on %2$s" : "Transferred from %1$s on %2$s", "Files compatibility" : "Files compatibility", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed.", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner.", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command.", "Enforce Windows compatibility" : "Enforce Windows compatibility", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity.", diff --git a/apps/files/l10n/en_GB.json b/apps/files/l10n/en_GB.json index ff092108295..2d293ebf557 100644 --- a/apps/files/l10n/en_GB.json +++ b/apps/files/l10n/en_GB.json @@ -71,7 +71,6 @@ "Transferred from %1$s on %2$s" : "Transferred from %1$s on %2$s", "Files compatibility" : "Files compatibility", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed.", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner.", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command.", "Enforce Windows compatibility" : "Enforce Windows compatibility", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity.", diff --git a/apps/files/l10n/es.js b/apps/files/l10n/es.js index 54e89b8c5e6..edb4acfd4f5 100644 --- a/apps/files/l10n/es.js +++ b/apps/files/l10n/es.js @@ -73,7 +73,6 @@ OC.L10N.register( "Transferred from %1$s on %2$s" : "Se transfirió desde %1$s en %2$s", "Files compatibility" : "Compatibilidad de archivos", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Permitir la restricción en nombres de archivo para asegurar que los archivos se puedan sincronizar con todos los clientes. Por defecto, se permiten todos los nombres de archivos válidos en POSIX (por ejemplo, Linux o macOS).", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "Luego de habilitar los nombres de archivo compatibles con windows, los archivos existentes no podrán ser modificados, pero, podrán ser renombrados a nuevos nombres válidos por su respectivo propietario.", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "También es posible migrar los archivos automáticamente luego de habilitar este ajuste. Por favor, refiérase a la documentación sobre el comando occ.", "Enforce Windows compatibility" : "Forzar la compatibilidad con Windows", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "Esto bloqueará los nombres de archivos inválidos en sistemas Windows, tales como usar nombres reservados o caracteres especiales. Pero no forzará la compatibilidad del uso de mayúsculas y minúsculas.", diff --git a/apps/files/l10n/es.json b/apps/files/l10n/es.json index 79fb844a32c..d9940c3968d 100644 --- a/apps/files/l10n/es.json +++ b/apps/files/l10n/es.json @@ -71,7 +71,6 @@ "Transferred from %1$s on %2$s" : "Se transfirió desde %1$s en %2$s", "Files compatibility" : "Compatibilidad de archivos", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Permitir la restricción en nombres de archivo para asegurar que los archivos se puedan sincronizar con todos los clientes. Por defecto, se permiten todos los nombres de archivos válidos en POSIX (por ejemplo, Linux o macOS).", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "Luego de habilitar los nombres de archivo compatibles con windows, los archivos existentes no podrán ser modificados, pero, podrán ser renombrados a nuevos nombres válidos por su respectivo propietario.", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "También es posible migrar los archivos automáticamente luego de habilitar este ajuste. Por favor, refiérase a la documentación sobre el comando occ.", "Enforce Windows compatibility" : "Forzar la compatibilidad con Windows", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "Esto bloqueará los nombres de archivos inválidos en sistemas Windows, tales como usar nombres reservados o caracteres especiales. Pero no forzará la compatibilidad del uso de mayúsculas y minúsculas.", diff --git a/apps/files/l10n/et_EE.js b/apps/files/l10n/et_EE.js index 246a7f7b064..50a02b2ad26 100644 --- a/apps/files/l10n/et_EE.js +++ b/apps/files/l10n/et_EE.js @@ -73,7 +73,6 @@ OC.L10N.register( "Transferred from %1$s on %2$s" : "Üleantud kasutajalt %1$s %2$s", "Files compatibility" : "Failide ühilduvus", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Luba failinimede piiramine tagamaks, et sünkroniseerimine toimib kõikide platvormide klientide vahel. Vaikimisi on lubatud kõik POSIX-i standardile vastavad failinimed (seda järgivad Linux ja macOS).", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "Kui võtad kasutusele Windowsiga ühilduvad failinimed, siis olemasolevad mitteühilduvaid faile ei saa enam muuta, aga faili omanik saab failinime muuta ühilduvaks.", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "Lisaks on peale selle seadistuse kasutuselevõtmist võimalik kõik mitteühilduvad failid automaatselt ära muuta. Asjakohast teavet leiad kasutusjuhendist occ-käsku kirjeldavast peatükist.", "Enforce Windows compatibility" : "Kasuta ühilduvust Windowsiga", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "Sellega blokeerid niisuguste failinimede kasutamise, mis Windowsis ei toimiks. See tähendab mõnede nimede ja tähemärkide keelamist. Aga see seadistus ei jõusta suur- ja väiketähtede kasutust.", diff --git a/apps/files/l10n/et_EE.json b/apps/files/l10n/et_EE.json index 00ffe074653..d0942feda0a 100644 --- a/apps/files/l10n/et_EE.json +++ b/apps/files/l10n/et_EE.json @@ -71,7 +71,6 @@ "Transferred from %1$s on %2$s" : "Üleantud kasutajalt %1$s %2$s", "Files compatibility" : "Failide ühilduvus", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Luba failinimede piiramine tagamaks, et sünkroniseerimine toimib kõikide platvormide klientide vahel. Vaikimisi on lubatud kõik POSIX-i standardile vastavad failinimed (seda järgivad Linux ja macOS).", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "Kui võtad kasutusele Windowsiga ühilduvad failinimed, siis olemasolevad mitteühilduvaid faile ei saa enam muuta, aga faili omanik saab failinime muuta ühilduvaks.", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "Lisaks on peale selle seadistuse kasutuselevõtmist võimalik kõik mitteühilduvad failid automaatselt ära muuta. Asjakohast teavet leiad kasutusjuhendist occ-käsku kirjeldavast peatükist.", "Enforce Windows compatibility" : "Kasuta ühilduvust Windowsiga", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "Sellega blokeerid niisuguste failinimede kasutamise, mis Windowsis ei toimiks. See tähendab mõnede nimede ja tähemärkide keelamist. Aga see seadistus ei jõusta suur- ja väiketähtede kasutust.", diff --git a/apps/files/l10n/pl.js b/apps/files/l10n/pl.js index a06c4433bdc..88f77ae9d76 100644 --- a/apps/files/l10n/pl.js +++ b/apps/files/l10n/pl.js @@ -73,7 +73,6 @@ OC.L10N.register( "Transferred from %1$s on %2$s" : "Przeniesiono z %1$s dnia %2$s", "Files compatibility" : "Zgodność plików", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Zezwalaj na ograniczenie nazw plików, aby zapewnić synchronizację plików ze wszystkimi klientami. Domyślnie dozwolone są wszystkie nazwy plików obowiązujące w systemie POSIX (np. Linux lub macOS).", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "Po włączeniu nazw plików zgodnych z systemem Windows, istniejących plików nie można już modyfikować, ale ich właściciel może zmienić ich nazwy na nowe, prawidłowe.", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "Możliwe jest również automatyczne migrowanie plików po włączeniu tego ustawienia. Więcej informacji można znaleźć w dokumentacji polecenia occ.", "Enforce Windows compatibility" : "Wymuszaj zgodność z systemem Windows", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "Spowoduje to zablokowanie nazw plików nieprawidłowych w systemach Windows, na przykład nazw zastrzeżonych lub znaków specjalnych. Nie wymusi to jednak zgodności z rozróżnianiem wielkości liter.", diff --git a/apps/files/l10n/pl.json b/apps/files/l10n/pl.json index 2705ef5eea4..0fc336bd1bb 100644 --- a/apps/files/l10n/pl.json +++ b/apps/files/l10n/pl.json @@ -71,7 +71,6 @@ "Transferred from %1$s on %2$s" : "Przeniesiono z %1$s dnia %2$s", "Files compatibility" : "Zgodność plików", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Zezwalaj na ograniczenie nazw plików, aby zapewnić synchronizację plików ze wszystkimi klientami. Domyślnie dozwolone są wszystkie nazwy plików obowiązujące w systemie POSIX (np. Linux lub macOS).", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "Po włączeniu nazw plików zgodnych z systemem Windows, istniejących plików nie można już modyfikować, ale ich właściciel może zmienić ich nazwy na nowe, prawidłowe.", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "Możliwe jest również automatyczne migrowanie plików po włączeniu tego ustawienia. Więcej informacji można znaleźć w dokumentacji polecenia occ.", "Enforce Windows compatibility" : "Wymuszaj zgodność z systemem Windows", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "Spowoduje to zablokowanie nazw plików nieprawidłowych w systemach Windows, na przykład nazw zastrzeżonych lub znaków specjalnych. Nie wymusi to jednak zgodności z rozróżnianiem wielkości liter.", diff --git a/apps/files/l10n/pt_BR.js b/apps/files/l10n/pt_BR.js index 3ddf3495fa4..a297cdc10b2 100644 --- a/apps/files/l10n/pt_BR.js +++ b/apps/files/l10n/pt_BR.js @@ -73,7 +73,6 @@ OC.L10N.register( "Transferred from %1$s on %2$s" : "Transferido de %1$s para %2$s", "Files compatibility" : "Compatibilidade de arquivos", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Permitir restringir nomes de arquivos para garantir que os arquivos possam ser sincronizados com todos os clientes. Por padrão, todos os nomes de arquivos válidos em POSIX (p. ex., Linux ou macOS) são permitidos.", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "Depois de ativar os nomes de arquivos compatíveis com o Windows, os arquivos existentes não podem mais ser modificados, mas podem ser renomeados para novos nomes válidos pelo proprietário.", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "Também é possível migrar arquivos automaticamente depois de ativar essa configuração. Consulte a documentação sobre o comando occ.", "Enforce Windows compatibility" : "Forçar compatibilidade com Windows ", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "Isso bloqueará nomes de arquivos não válidos em sistemas Windows, como nomes reservados ou caracteres especiais. Mas isso não imporá a compatibilidade da distinção entre maiúsculas e minúsculas.", diff --git a/apps/files/l10n/pt_BR.json b/apps/files/l10n/pt_BR.json index 4e5c1e7d051..579d333dfbf 100644 --- a/apps/files/l10n/pt_BR.json +++ b/apps/files/l10n/pt_BR.json @@ -71,7 +71,6 @@ "Transferred from %1$s on %2$s" : "Transferido de %1$s para %2$s", "Files compatibility" : "Compatibilidade de arquivos", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Permitir restringir nomes de arquivos para garantir que os arquivos possam ser sincronizados com todos os clientes. Por padrão, todos os nomes de arquivos válidos em POSIX (p. ex., Linux ou macOS) são permitidos.", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "Depois de ativar os nomes de arquivos compatíveis com o Windows, os arquivos existentes não podem mais ser modificados, mas podem ser renomeados para novos nomes válidos pelo proprietário.", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "Também é possível migrar arquivos automaticamente depois de ativar essa configuração. Consulte a documentação sobre o comando occ.", "Enforce Windows compatibility" : "Forçar compatibilidade com Windows ", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "Isso bloqueará nomes de arquivos não válidos em sistemas Windows, como nomes reservados ou caracteres especiais. Mas isso não imporá a compatibilidade da distinção entre maiúsculas e minúsculas.", diff --git a/apps/files/l10n/sr.js b/apps/files/l10n/sr.js index 94e6e94c5a4..5be69357590 100644 --- a/apps/files/l10n/sr.js +++ b/apps/files/l10n/sr.js @@ -73,7 +73,6 @@ OC.L10N.register( "Transferred from %1$s on %2$s" : "Пренесено са %1$s на %2$s", "Files compatibility" : "Компатибилност фајлова", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Дозвољава се ограничавање имена фајлова тако да сви клијенти могу да их синхронизују. Подразумевано се дозвољавају сва имена фајлова која су исправна на POSIX системима (нпр. Linux или macOS).", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "Када се укључе windows компатибилна имена фајлова, постојећи фајлови се више неће моћи мењати, али њихов власник може да им промени име на исправно ново име.", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "Фајлови такође могу аутоматски да се мигрирају након укључивања овог подешавања, молимо вас да погледате документацију у вези са occ командом.", "Enforce Windows compatibility" : "Форсирај Windows компатибилност", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "Ово ће да блокира имена фајлова која су неисправна на Windows системима, као што су она која користе резервисана имена или специјалне карактере. Али ово неће форсирати компатибилност разликовања малих и великих слова.", diff --git a/apps/files/l10n/sr.json b/apps/files/l10n/sr.json index 280c8cc2afd..52c41a7612e 100644 --- a/apps/files/l10n/sr.json +++ b/apps/files/l10n/sr.json @@ -71,7 +71,6 @@ "Transferred from %1$s on %2$s" : "Пренесено са %1$s на %2$s", "Files compatibility" : "Компатибилност фајлова", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Дозвољава се ограничавање имена фајлова тако да сви клијенти могу да их синхронизују. Подразумевано се дозвољавају сва имена фајлова која су исправна на POSIX системима (нпр. Linux или macOS).", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "Када се укључе windows компатибилна имена фајлова, постојећи фајлови се више неће моћи мењати, али њихов власник може да им промени име на исправно ново име.", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "Фајлови такође могу аутоматски да се мигрирају након укључивања овог подешавања, молимо вас да погледате документацију у вези са occ командом.", "Enforce Windows compatibility" : "Форсирај Windows компатибилност", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "Ово ће да блокира имена фајлова која су неисправна на Windows системима, као што су она која користе резервисана имена или специјалне карактере. Али ово неће форсирати компатибилност разликовања малих и великих слова.", diff --git a/apps/files/l10n/sv.js b/apps/files/l10n/sv.js index d6827bb0ab3..1eac3304ab0 100644 --- a/apps/files/l10n/sv.js +++ b/apps/files/l10n/sv.js @@ -73,7 +73,6 @@ OC.L10N.register( "Transferred from %1$s on %2$s" : "Överförd från %1$s på %2$s", "Files compatibility" : "Filkompatibilitet", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Tillåt att begränsa filnamn för att säkerställa att filer kan synkroniseras med alla klienter. Som standard är alla filnamn som är giltiga på POSIX (t.ex. Linux eller macOS) tillåtna.", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "När Windows-kompatibla filnamn har aktiverats kan befintliga filer inte längre ändras, men de kan byta namn till giltiga nya namn av sin ägare.", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "Det är också möjligt att migrera filer automatiskt efter att den här inställningen har aktiverats. Se dokumentationen om kommandot occ för mer information.", "Enforce Windows compatibility" : "Tvinga Windows-kompatibilitet", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "Detta kommer att blockera filnamn som inte är giltiga på Windows-system, som att använda reserverade namn eller specialtecken. Men detta kommer inte att framtvinga kompatibiliteten för skiftlägeskänslighet.", diff --git a/apps/files/l10n/sv.json b/apps/files/l10n/sv.json index c5b48b00897..27768e830bb 100644 --- a/apps/files/l10n/sv.json +++ b/apps/files/l10n/sv.json @@ -71,7 +71,6 @@ "Transferred from %1$s on %2$s" : "Överförd från %1$s på %2$s", "Files compatibility" : "Filkompatibilitet", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "Tillåt att begränsa filnamn för att säkerställa att filer kan synkroniseras med alla klienter. Som standard är alla filnamn som är giltiga på POSIX (t.ex. Linux eller macOS) tillåtna.", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "När Windows-kompatibla filnamn har aktiverats kan befintliga filer inte längre ändras, men de kan byta namn till giltiga nya namn av sin ägare.", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "Det är också möjligt att migrera filer automatiskt efter att den här inställningen har aktiverats. Se dokumentationen om kommandot occ för mer information.", "Enforce Windows compatibility" : "Tvinga Windows-kompatibilitet", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "Detta kommer att blockera filnamn som inte är giltiga på Windows-system, som att använda reserverade namn eller specialtecken. Men detta kommer inte att framtvinga kompatibiliteten för skiftlägeskänslighet.", diff --git a/apps/files/l10n/zh_CN.js b/apps/files/l10n/zh_CN.js index 17571dc849b..003a12b2320 100644 --- a/apps/files/l10n/zh_CN.js +++ b/apps/files/l10n/zh_CN.js @@ -73,7 +73,6 @@ OC.L10N.register( "Transferred from %1$s on %2$s" : "从 %1$s 转移至 %2$s", "Files compatibility" : "文件兼容性", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "允许限制文件名称以确保文件可以与所有客户端同步。默认状态下,所有POSIX(例如 Linux 或 macOS)系统有效的文件名都是被允许的。", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "启用与 Windows 兼容的文件名后,无法再修改现有文件,但可以由其所有者重命名为有效的新名称。", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "启用此设置后,也可以自动迁移文件,请参阅有关 occ 命令的文档。", "Enforce Windows compatibility" : "强制 Windows 兼容性", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "这将阻止在 Windows 系统中无效的文件名称,比如使用保留字符。但这不会强制大小写敏感性兼容。", diff --git a/apps/files/l10n/zh_CN.json b/apps/files/l10n/zh_CN.json index e872bd42873..aab018cfab8 100644 --- a/apps/files/l10n/zh_CN.json +++ b/apps/files/l10n/zh_CN.json @@ -71,7 +71,6 @@ "Transferred from %1$s on %2$s" : "从 %1$s 转移至 %2$s", "Files compatibility" : "文件兼容性", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "允许限制文件名称以确保文件可以与所有客户端同步。默认状态下,所有POSIX(例如 Linux 或 macOS)系统有效的文件名都是被允许的。", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "启用与 Windows 兼容的文件名后,无法再修改现有文件,但可以由其所有者重命名为有效的新名称。", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "启用此设置后,也可以自动迁移文件,请参阅有关 occ 命令的文档。", "Enforce Windows compatibility" : "强制 Windows 兼容性", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "这将阻止在 Windows 系统中无效的文件名称,比如使用保留字符。但这不会强制大小写敏感性兼容。", diff --git a/apps/files/l10n/zh_HK.js b/apps/files/l10n/zh_HK.js index 0b68516c402..4b77fd52159 100644 --- a/apps/files/l10n/zh_HK.js +++ b/apps/files/l10n/zh_HK.js @@ -73,7 +73,6 @@ OC.L10N.register( "Transferred from %1$s on %2$s" : "於 %2$s 從 %1$s 轉移", "Files compatibility" : "檔案兼容性", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "允許限製檔案名稱以確保檔案可以與所有客戶端同步。默認情況下,允許 POSIX(例如 Linux 或 macOS)上有效的所有檔案名稱。", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "啟用 Windows 兼容檔案名後,現有的檔案無法再被修改,但其擁有者可以將其重新命名為有效的新名稱。", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "啟用此設定後,還可以自動遷移檔案,請參考有關 occ 指令的說明書。", "Enforce Windows compatibility" : "實施 Windows 兼容性", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "這將阻止在 Windows 系統上無效的檔案名,例如使用保留名稱或特殊字元。但這不會強制區分大小寫的兼容性。", diff --git a/apps/files/l10n/zh_HK.json b/apps/files/l10n/zh_HK.json index def7021f66e..fa74cbe8827 100644 --- a/apps/files/l10n/zh_HK.json +++ b/apps/files/l10n/zh_HK.json @@ -71,7 +71,6 @@ "Transferred from %1$s on %2$s" : "於 %2$s 從 %1$s 轉移", "Files compatibility" : "檔案兼容性", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "允許限製檔案名稱以確保檔案可以與所有客戶端同步。默認情況下,允許 POSIX(例如 Linux 或 macOS)上有效的所有檔案名稱。", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "啟用 Windows 兼容檔案名後,現有的檔案無法再被修改,但其擁有者可以將其重新命名為有效的新名稱。", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "啟用此設定後,還可以自動遷移檔案,請參考有關 occ 指令的說明書。", "Enforce Windows compatibility" : "實施 Windows 兼容性", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "這將阻止在 Windows 系統上無效的檔案名,例如使用保留名稱或特殊字元。但這不會強制區分大小寫的兼容性。", diff --git a/apps/files/l10n/zh_TW.js b/apps/files/l10n/zh_TW.js index 9ee3f40b41d..ed24a6b2299 100644 --- a/apps/files/l10n/zh_TW.js +++ b/apps/files/l10n/zh_TW.js @@ -73,7 +73,6 @@ OC.L10N.register( "Transferred from %1$s on %2$s" : "於 %2$s 從 %1$s 轉移", "Files compatibility" : "檔案相容性", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "允許限制檔案名稱以確保檔案可以與所有客戶端同步。預設情況下,允許 POSIX(例如 Linux 或 macOS)上所有有效的檔案名稱。", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "啟用與 Windows 相容的檔案名稱後,無法再修改現有檔案,但可以由其擁有者重新命名為有效的新名稱。", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "啟用此設定後,也可以自動遷移檔案,詳情請參閱關於 occ 命令的文件。", "Enforce Windows compatibility" : "強制 Windows 相容性", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "這會封鎖在 Windows 系統上無效的檔案名稱,例如使用保留名稱或特殊字元。但這不會強制區分大小寫的相容性。", diff --git a/apps/files/l10n/zh_TW.json b/apps/files/l10n/zh_TW.json index 4814a6d91af..84ac29f65b1 100644 --- a/apps/files/l10n/zh_TW.json +++ b/apps/files/l10n/zh_TW.json @@ -71,7 +71,6 @@ "Transferred from %1$s on %2$s" : "於 %2$s 從 %1$s 轉移", "Files compatibility" : "檔案相容性", "Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed." : "允許限制檔案名稱以確保檔案可以與所有客戶端同步。預設情況下,允許 POSIX(例如 Linux 或 macOS)上所有有效的檔案名稱。", - "After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner." : "啟用與 Windows 相容的檔案名稱後,無法再修改現有檔案,但可以由其擁有者重新命名為有效的新名稱。", "It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command." : "啟用此設定後,也可以自動遷移檔案,詳情請參閱關於 occ 命令的文件。", "Enforce Windows compatibility" : "強制 Windows 相容性", "This will block filenames not valid on Windows systems, like using reserved names or special characters. But this will not enforce compatibility of case sensitivity." : "這會封鎖在 Windows 系統上無效的檔案名稱,例如使用保留名稱或特殊字元。但這不會強制區分大小寫的相容性。", diff --git a/apps/files/lib/Settings/DeclarativeAdminSettings.php b/apps/files/lib/Settings/DeclarativeAdminSettings.php index 2f363f05958..bbf97cc4d32 100644 --- a/apps/files/lib/Settings/DeclarativeAdminSettings.php +++ b/apps/files/lib/Settings/DeclarativeAdminSettings.php @@ -49,7 +49,7 @@ class DeclarativeAdminSettings implements IDeclarativeSettingsFormWithHandlers { 'doc_url' => $this->urlGenerator->linkToDocs('admin-windows-compatible-filenames'), 'description' => ( $this->l->t('Allow to restrict filenames to ensure files can be synced with all clients. By default all filenames valid on POSIX (e.g. Linux or macOS) are allowed.') - . "\n" . $this->l->t('After enabling the windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner.') + . "\n" . $this->l->t('After enabling the Windows compatible filenames, existing files cannot be modified anymore but can be renamed to valid new names by their owner.') . "\n" . $this->l->t('It is also possible to migrate files automatically after enabling this setting, please refer to the documentation about the occ command.') ), diff --git a/apps/files_external/lib/Lib/Storage/Swift.php b/apps/files_external/lib/Lib/Storage/Swift.php index a71331766d4..e80570f14ba 100644 --- a/apps/files_external/lib/Lib/Storage/Swift.php +++ b/apps/files_external/lib/Lib/Storage/Swift.php @@ -288,7 +288,6 @@ class Swift extends Common { public function stat(string $path): array|false { $path = $this->normalizePath($path); - if ($path === '.') { $path = ''; } elseif ($this->is_dir($path)) { @@ -308,22 +307,23 @@ class Swift extends Common { return false; } - $dateTime = $object->lastModified ? \DateTime::createFromFormat(\DateTime::RFC1123, $object->lastModified) : false; - $mtime = $dateTime ? $dateTime->getTimestamp() : null; - $objectMetadata = $object->getMetadata(); - if (isset($objectMetadata['timestamp'])) { - $mtime = $objectMetadata['timestamp']; + $mtime = null; + if (!empty($object->lastModified)) { + $dateTime = \DateTime::createFromFormat(\DateTime::RFC1123, $object->lastModified); + if ($dateTime !== false) { + $mtime = $dateTime->getTimestamp(); + } } - if (!empty($mtime)) { - $mtime = floor($mtime); + if (is_numeric($object->getMetadata()['timestamp'] ?? null)) { + $mtime = (float)$object->getMetadata()['timestamp']; } - $stat = []; - $stat['size'] = (int)$object->contentLength; - $stat['mtime'] = $mtime; - $stat['atime'] = time(); - return $stat; + return [ + 'size' => (int)$object->contentLength, + 'mtime' => isset($mtime) ? (int)floor($mtime) : null, + 'atime' => time(), + ]; } public function filetype(string $path) { diff --git a/apps/files_sharing/l10n/ko.js b/apps/files_sharing/l10n/ko.js index 87b568cf22f..6c6967c59a8 100644 --- a/apps/files_sharing/l10n/ko.js +++ b/apps/files_sharing/l10n/ko.js @@ -313,7 +313,9 @@ OC.L10N.register( "Use this method to share files with individuals or teams within your organization. If the recipient already has access to the share but cannot locate it, you can send them the internal share link for easy access." : "이 방법을 사용하여 조직 내 개인 또는 팀과 파일을 공유하세요. 수신자가 이미 공유 폴더에 접근할 수 있지만 위치를 찾을 수 없는 경우, 쉽게 접근할 수 있도록 내부 공유 링크를 보낼 수 있습니다.", "Use this method to share files with individuals or organizations outside your organization. Files and folders can be shared via public share links and email addresses. You can also share to other Nextcloud accounts hosted on different instances using their federated cloud ID." : "이 방법을 사용하면 조직 외부의 조직이나 개인과 파일을 공유할 수 있습니다. 파일과 폴더는 공개 공유 링크와 이메일 주소를 통해 공유할 수 있습니다. 또한, 다른 인스턴스에 소속된 다른 Nextcloud 계정과도 연합 클라우드 ID를 사용하여 공유할 수 있습니다.", "Shares that are not part of the internal or external shares. This can be shares from apps or other sources." : "내부 또는 외부 공유에 포함되지 않은 공유입니다. 앱이나 다른 소스에서 공유된 내용이 여기에 해당할 수 있습니다.", + "Share with accounts, teams, federated cloud IDs" : "계정, 팀 및 연합 클라우드 ID와 공유", "Share with accounts and teams" : "계정 및 팀과 공유", + "Email, federated cloud ID" : "이메일, 연합 클라우드 ID", "Unable to load the shares list" : "공유 목록을 불러올 수 없음", "Expires {relativetime}" : "{relativetime}에 만료", "this share just expired." : "이 공유는 방금 만료되었습니다.", @@ -377,6 +379,7 @@ OC.L10N.register( "Could not update share" : "공유를 갱신할 수 없음", "Share saved" : "공유 저장됨", "Share expiry date saved" : "공유 만료일 저장됨", + "Share hide-download state saved" : "공유 다운로드 숨기기 상태 저장됨", "Share label saved" : "공유 이름 저장됨", "Share note for recipient saved" : "받는이를 위한 공유 메모 저장됨", "Share password saved" : "공유 암호 저장됨", @@ -421,6 +424,7 @@ OC.L10N.register( "You are not allowed to edit link shares that you don't own" : "당신이 것이 아닌 링크 공유를 편집할 권한이 없습니다.", "_1 email address already added_::_{count} email addresses already added_" : ["{count}개 이메일 주소가 이미 추가됨"], "_1 email address added_::_{count} email addresses added_" : ["{count}개 이메일 주소 추가함"], + "Share with accounts, teams, federated cloud id" : "계정, 팀 및 연합 클라우드 ID와 공유", "Email, federated cloud id" : "이메일, 연합 클라우드 ID" }, "nplurals=1; plural=0;"); diff --git a/apps/files_sharing/l10n/ko.json b/apps/files_sharing/l10n/ko.json index 9d1e8f09b2b..d08e914da29 100644 --- a/apps/files_sharing/l10n/ko.json +++ b/apps/files_sharing/l10n/ko.json @@ -311,7 +311,9 @@ "Use this method to share files with individuals or teams within your organization. If the recipient already has access to the share but cannot locate it, you can send them the internal share link for easy access." : "이 방법을 사용하여 조직 내 개인 또는 팀과 파일을 공유하세요. 수신자가 이미 공유 폴더에 접근할 수 있지만 위치를 찾을 수 없는 경우, 쉽게 접근할 수 있도록 내부 공유 링크를 보낼 수 있습니다.", "Use this method to share files with individuals or organizations outside your organization. Files and folders can be shared via public share links and email addresses. You can also share to other Nextcloud accounts hosted on different instances using their federated cloud ID." : "이 방법을 사용하면 조직 외부의 조직이나 개인과 파일을 공유할 수 있습니다. 파일과 폴더는 공개 공유 링크와 이메일 주소를 통해 공유할 수 있습니다. 또한, 다른 인스턴스에 소속된 다른 Nextcloud 계정과도 연합 클라우드 ID를 사용하여 공유할 수 있습니다.", "Shares that are not part of the internal or external shares. This can be shares from apps or other sources." : "내부 또는 외부 공유에 포함되지 않은 공유입니다. 앱이나 다른 소스에서 공유된 내용이 여기에 해당할 수 있습니다.", + "Share with accounts, teams, federated cloud IDs" : "계정, 팀 및 연합 클라우드 ID와 공유", "Share with accounts and teams" : "계정 및 팀과 공유", + "Email, federated cloud ID" : "이메일, 연합 클라우드 ID", "Unable to load the shares list" : "공유 목록을 불러올 수 없음", "Expires {relativetime}" : "{relativetime}에 만료", "this share just expired." : "이 공유는 방금 만료되었습니다.", @@ -375,6 +377,7 @@ "Could not update share" : "공유를 갱신할 수 없음", "Share saved" : "공유 저장됨", "Share expiry date saved" : "공유 만료일 저장됨", + "Share hide-download state saved" : "공유 다운로드 숨기기 상태 저장됨", "Share label saved" : "공유 이름 저장됨", "Share note for recipient saved" : "받는이를 위한 공유 메모 저장됨", "Share password saved" : "공유 암호 저장됨", @@ -419,6 +422,7 @@ "You are not allowed to edit link shares that you don't own" : "당신이 것이 아닌 링크 공유를 편집할 권한이 없습니다.", "_1 email address already added_::_{count} email addresses already added_" : ["{count}개 이메일 주소가 이미 추가됨"], "_1 email address added_::_{count} email addresses added_" : ["{count}개 이메일 주소 추가함"], + "Share with accounts, teams, federated cloud id" : "계정, 팀 및 연합 클라우드 ID와 공유", "Email, federated cloud id" : "이메일, 연합 클라우드 ID" },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/core/Command/Config/System/SetConfig.php b/core/Command/Config/System/SetConfig.php index 4d23c191ac1..62ab7f7120f 100644 --- a/core/Command/Config/System/SetConfig.php +++ b/core/Command/Config/System/SetConfig.php @@ -142,6 +142,13 @@ class SetConfig extends Base { 'readable-value' => ($value === '') ? 'empty string' : 'string ' . $value, ]; + case 'json': + $value = json_decode($value, true); + return [ + 'value' => $value, + 'readable-value' => 'json ' . json_encode($value), + ]; + default: throw new \InvalidArgumentException('Invalid type'); } @@ -183,7 +190,7 @@ class SetConfig extends Base { */ public function completeOptionValues($optionName, CompletionContext $context) { if ($optionName === 'type') { - return ['string', 'integer', 'double', 'boolean']; + return ['string', 'integer', 'double', 'boolean', 'json', 'null']; } return parent::completeOptionValues($optionName, $context); } diff --git a/core/Command/Info/File.php b/core/Command/Info/File.php index a081d1d13e1..c21c2e666fb 100644 --- a/core/Command/Info/File.php +++ b/core/Command/Info/File.php @@ -8,6 +8,7 @@ declare(strict_types=1); namespace OC\Core\Command\Info; use OC\Files\ObjectStore\ObjectStoreStorage; +use OC\Files\Storage\Wrapper\Encryption; use OC\Files\View; use OCA\Files_External\Config\ExternalMountPoint; use OCA\GroupFolders\Mount\GroupMountPoint; @@ -71,6 +72,15 @@ class File extends Command { } else { $output->writeln(' <error>encryption key not found</error> should be located at: ' . $keyPath); } + $storage = $node->getStorage(); + if ($storage->instanceOfStorage(Encryption::class)) { + /** @var Encryption $storage */ + if (!$storage->hasValidHeader($node->getInternalPath())) { + $output->writeln(' <error>file doesn\'t have a valid encryption header</error>'); + } + } else { + $output->writeln(' <error>file is marked as encrypted, but encryption doesn\'t seem to be setup</error>'); + } } if ($node instanceof Folder && $node->isEncrypted() || $node instanceof OCPFile && $node->getParent()->isEncrypted()) { diff --git a/core/l10n/ko.js b/core/l10n/ko.js index 21de2675fe3..ac73f72136a 100644 --- a/core/l10n/ko.js +++ b/core/l10n/ko.js @@ -27,6 +27,7 @@ OC.L10N.register( "Could not complete login" : "로그인을 완료할 수 없음", "State token missing" : "상태 토큰 누락", "Your login token is invalid or has expired" : "로그인 토큰이 잘못되었거나 만료되었습니다.", + "Please use original client" : "원본 클라이언트를 사용해주십시오.", "This community release of Nextcloud is unsupported and push notifications are limited." : "이 Nextcloud 커뮤니티 릴리즈는 지원하지 않는 버전이며, 푸시 알림은 제한됩니다.", "Login" : "로그인", "Unsupported email length (>255)" : "지원하지 않는 이메일 길이 (255자 초과)", diff --git a/core/l10n/ko.json b/core/l10n/ko.json index 67fc5f25474..98c8a26cfbb 100644 --- a/core/l10n/ko.json +++ b/core/l10n/ko.json @@ -25,6 +25,7 @@ "Could not complete login" : "로그인을 완료할 수 없음", "State token missing" : "상태 토큰 누락", "Your login token is invalid or has expired" : "로그인 토큰이 잘못되었거나 만료되었습니다.", + "Please use original client" : "원본 클라이언트를 사용해주십시오.", "This community release of Nextcloud is unsupported and push notifications are limited." : "이 Nextcloud 커뮤니티 릴리즈는 지원하지 않는 버전이며, 푸시 알림은 제한됩니다.", "Login" : "로그인", "Unsupported email length (>255)" : "지원하지 않는 이메일 길이 (255자 초과)", diff --git a/core/src/components/setup/RecommendedApps.vue b/core/src/components/setup/RecommendedApps.vue index aaad6d93476..b31e4b54ca4 100644 --- a/core/src/components/setup/RecommendedApps.vue +++ b/core/src/components/setup/RecommendedApps.vue @@ -4,7 +4,7 @@ --> <template> - <div class="guest-box"> + <div class="guest-box" data-cy-setup-recommended-apps> <h2>{{ t('core', 'Recommended apps') }}</h2> <p v-if="loadingApps" class="loading text-center"> {{ t('core', 'Loading apps …') }} @@ -40,13 +40,15 @@ <NcButton v-if="showInstallButton && !installingApps" type="tertiary" role="link" - :href="defaultPageUrl"> + :href="defaultPageUrl" + data-cy-setup-recommended-apps-skip> {{ t('core', 'Skip') }} </NcButton> <NcButton v-if="showInstallButton" type="primary" :disabled="installingApps || !isAnyAppSelected" + data-cy-setup-recommended-apps-install> @click.stop.prevent="installApps"> {{ installingApps ? t('core', 'Installing apps …') : t('core', 'Install recommended apps') }} </NcButton> diff --git a/cypress.config.ts b/cypress.config.ts index 1e83c0b7f5d..0b1a0524c9d 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -3,6 +3,13 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ import type { Configuration } from 'webpack' +import { defineConfig } from 'cypress' +import { join } from 'path' +import { removeDirectory } from 'cypress-delete-downloads-folder' + +import cypressSplit from 'cypress-split' +import webpackPreprocessor from '@cypress/webpack-preprocessor' + import { applyChangesToNextcloud, configureNextcloud, @@ -10,11 +17,6 @@ import { stopNextcloud, waitOnNextcloud, } from './cypress/dockerNode' -import { defineConfig } from 'cypress' -import cypressSplit from 'cypress-split' -import { removeDirectory } from 'cypress-delete-downloads-folder' -import webpackPreprocessor from '@cypress/webpack-preprocessor' - import webpackConfig from './webpack.config.js' export default defineConfig({ @@ -62,8 +64,6 @@ export default defineConfig({ // We've imported your old cypress plugins here. // You may want to clean this up later by importing these. async setupNodeEvents(on, config) { - cypressSplit(on, config) - on('file:preprocessor', webpackPreprocessor({ webpackOptions: webpackConfig as Configuration })) on('task', { removeDirectory }) @@ -106,6 +106,16 @@ export default defineConfig({ } }) + // Check if we are running the setup checks + if (process.env.SETUP_TESTING === 'true') { + console.log('Adding setup tests to specPattern 🧮') + config.specPattern = [join(__dirname, 'cypress/e2e/core/setup.ts')] + console.log('└─ Done') + } else { + // If we are not running the setup tests, we need to remove the setup tests from the specPattern + cypressSplit(on, config) + } + // Before the browser launches // starting Nextcloud testing container const ip = await startNextcloud(process.env.BRANCH) diff --git a/cypress/dockerNode.ts b/cypress/dockerNode.ts index b65f164dc15..5cd2415f111 100644 --- a/cypress/dockerNode.ts +++ b/cypress/dockerNode.ts @@ -94,6 +94,9 @@ export const startNextcloud = async function(branch: string = getCurrentGitBranc HostPort: '8083', }], }, + // If running the setup tests, let's bind to host + // to communicate with the github actions DB services + NetworkMode: process.env.SETUP_TESTING === 'true' ? await getGithubNetwork() : undefined, }, Env: [ `BRANCH=${branch}`, @@ -106,9 +109,6 @@ export const startNextcloud = async function(branch: string = getCurrentGitBranc await runExec(container, ['chown', '-R', 'www-data:www-data', '/var/www/html/data'], false, 'root') await runExec(container, ['chmod', '0770', '/var/www/html/data'], false, 'root') - // Init Nextcloud - // await runExec(container, ['initnc.sh'], true, 'root') - // Get container's IP const ip = await getContainerIP(container) @@ -252,6 +252,7 @@ export const getContainerIP = async function( if (err) { throw err } + if (data?.HostConfig.PortBindings?.['80/tcp']?.[0]?.HostPort) { ip = `localhost:${data.HostConfig.PortBindings['80/tcp'][0].HostPort}` } else { @@ -335,3 +336,21 @@ const sleep = function(milliseconds: number) { const getCurrentGitBranch = function() { return execSync('git rev-parse --abbrev-ref HEAD').toString().trim() || 'master' } + +/** + * Get the network name of the github actions network + * This is used to connect to the database services + * started by github actions + */ +const getGithubNetwork = async function(): Promise<string|undefined> { + console.log('├─ Looking for github actions network... 🔍') + const networks = await docker.listNetworks() + const network = networks.find((network) => network.Name.startsWith('github_network')) + if (network) { + console.log('│ └─ Found github actions network: ' + network.Name) + return network.Name + } + + console.log('│ └─ No github actions network found') + return undefined +} diff --git a/cypress/e2e/core/setup.ts b/cypress/e2e/core/setup.ts new file mode 100644 index 00000000000..01606a75617 --- /dev/null +++ b/cypress/e2e/core/setup.ts @@ -0,0 +1,114 @@ +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +/** + * DO NOT RENAME THIS FILE to .cy.ts ⚠️ + * This is not following the pattern of the other files in this folder + * because it is manually added to the tests by the cypress config. + */ +describe('Can install Nextcloud', { testIsolation: true, retries: 0 }, () => { + beforeEach(() => { + // Move the config file and data folder + cy.runCommand('rm /var/www/html/config/config.php', { failOnNonZeroExit: false }) + cy.runCommand('rm /var/www/html/data/owncloud.db', { failOnNonZeroExit: false }) + }) + + it('Sqlite', () => { + cy.visit('/') + cy.get('[data-cy-setup-form]').should('be.visible') + cy.get('[data-cy-setup-form-field="adminlogin"]').should('be.visible') + cy.get('[data-cy-setup-form-field="adminpass"]').should('be.visible') + cy.get('[data-cy-setup-form-field="directory"]').should('have.value', '/var/www/html/data') + + // Select the SQLite database + cy.get('[data-cy-setup-form-field="dbtype-sqlite"] input').check({ force: true }) + + sharedSetup() + }) + + it('MySQL', () => { + cy.visit('/') + cy.get('[data-cy-setup-form]').should('be.visible') + cy.get('[data-cy-setup-form-field="adminlogin"]').should('be.visible') + cy.get('[data-cy-setup-form-field="adminpass"]').should('be.visible') + cy.get('[data-cy-setup-form-field="directory"]').should('have.value', '/var/www/html/data') + + // Select the SQLite database + cy.get('[data-cy-setup-form-field="dbtype-mysql"] input').check({ force: true }) + + // Fill in the DB form + cy.get('[data-cy-setup-form-field="dbuser"]').type('{selectAll}oc_autotest') + cy.get('[data-cy-setup-form-field="dbpass"]').type('{selectAll}nextcloud') + cy.get('[data-cy-setup-form-field="dbname"]').type('{selectAll}oc_autotest') + cy.get('[data-cy-setup-form-field="dbhost"]').type('{selectAll}mysql:3306') + + sharedSetup() + }) + + it('MariaDB', () => { + cy.visit('/') + cy.get('[data-cy-setup-form]').should('be.visible') + cy.get('[data-cy-setup-form-field="adminlogin"]').should('be.visible') + cy.get('[data-cy-setup-form-field="adminpass"]').should('be.visible') + cy.get('[data-cy-setup-form-field="directory"]').should('have.value', '/var/www/html/data') + + // Select the SQLite database + cy.get('[data-cy-setup-form-field="dbtype-mysql"] input').check({ force: true }) + + // Fill in the DB form + cy.get('[data-cy-setup-form-field="dbuser"]').type('{selectAll}oc_autotest') + cy.get('[data-cy-setup-form-field="dbpass"]').type('{selectAll}nextcloud') + cy.get('[data-cy-setup-form-field="dbname"]').type('{selectAll}oc_autotest') + cy.get('[data-cy-setup-form-field="dbhost"]').type('{selectAll}mariadb:3306') + + sharedSetup() + }) + + it('PostgreSQL', () => { + cy.visit('/') + cy.get('[data-cy-setup-form]').should('be.visible') + cy.get('[data-cy-setup-form-field="adminlogin"]').should('be.visible') + cy.get('[data-cy-setup-form-field="adminpass"]').should('be.visible') + cy.get('[data-cy-setup-form-field="directory"]').should('have.value', '/var/www/html/data') + + // Select the SQLite database + cy.get('[data-cy-setup-form-field="dbtype-pgsql"] input').check({ force: true }) + + // Fill in the DB form + cy.get('[data-cy-setup-form-field="dbuser"]').type('{selectAll}root') + cy.get('[data-cy-setup-form-field="dbpass"]').type('{selectAll}rootpassword') + cy.get('[data-cy-setup-form-field="dbname"]').type('{selectAll}nextcloud') + cy.get('[data-cy-setup-form-field="dbhost"]').type('{selectAll}postgres:5432') + + sharedSetup() + }) + +}) + +/** + * Shared admin setup function for the Nextcloud setup + */ +function sharedSetup() { + const randAdmin = 'admin-' + Math.random().toString(36).substring(2, 15) + + // Fill in the form + cy.get('[data-cy-setup-form-field="adminlogin"]').type(randAdmin) + cy.get('[data-cy-setup-form-field="adminpass"]').type(randAdmin) + + // Nothing more to do on sqlite, let's continue + cy.get('[data-cy-setup-form-submit]').click() + + // Wait for the setup to finish + cy.location('pathname', { timeout: 10000 }) + .should('include', '/core/apps/recommended') + + // Skip the setup apps + cy.get('[data-cy-setup-recommended-apps]').should('be.visible') + cy.get('[data-cy-setup-recommended-apps-skip]').click() + + // Go to files + cy.visit('/apps/files/') + cy.get('[data-cy-files-content]').should('be.visible') +} diff --git a/dist/core-recommendedapps.js b/dist/core-recommendedapps.js index 073705a5999..71d8d449059 100644 --- a/dist/core-recommendedapps.js +++ b/dist/core-recommendedapps.js @@ -1,2 +1,2 @@ -(()=>{"use strict";var t,e={12665:(t,e,n)=>{n.d(e,{A:()=>s});var i=n(71354),o=n.n(i),r=n(76314),a=n.n(r)()(o());a.push([t.id,".dialog-row[data-v-07178674]{display:flex;justify-content:end;margin-top:8px}p.loading[data-v-07178674],p.loading-error[data-v-07178674]{height:100px}p[data-v-07178674]:last-child{margin-top:10px}.text-center[data-v-07178674]{text-align:center}.app[data-v-07178674]{display:flex;flex-direction:row}.app img[data-v-07178674]{height:50px;width:50px;filter:var(--background-invert-if-dark)}.app img[data-v-07178674],.app .info[data-v-07178674]{padding:12px}.app .info h3[data-v-07178674],.app .info p[data-v-07178674]{text-align:start}.app .info h3[data-v-07178674]{margin-top:0}.app .checkbox-radio-switch[data-v-07178674]{margin-inline-start:auto;padding:0 2px}","",{version:3,sources:["webpack://./core/src/components/setup/RecommendedApps.vue"],names:[],mappings:"AACA,6BACC,YAAA,CACA,mBAAA,CACA,cAAA,CAIA,4DAEC,YAAA,CAGD,8BACC,eAAA,CAIF,8BACC,iBAAA,CAGD,sBACC,YAAA,CACA,kBAAA,CAEA,0BACC,WAAA,CACA,UAAA,CACA,uCAAA,CAGD,sDACC,YAAA,CAIA,6DACC,gBAAA,CAGD,+BACC,YAAA,CAIF,6CACC,wBAAA,CACA,aAAA",sourcesContent:["\n.dialog-row {\n\tdisplay: flex;\n\tjustify-content: end;\n\tmargin-top: 8px;\n}\n\np {\n\t&.loading,\n\t&.loading-error {\n\t\theight: 100px;\n\t}\n\n\t&:last-child {\n\t\tmargin-top: 10px;\n\t}\n}\n\n.text-center {\n\ttext-align: center;\n}\n\n.app {\n\tdisplay: flex;\n\tflex-direction: row;\n\n\timg {\n\t\theight: 50px;\n\t\twidth: 50px;\n\t\tfilter: var(--background-invert-if-dark);\n\t}\n\n\timg, .info {\n\t\tpadding: 12px;\n\t}\n\n\t.info {\n\t\th3, p {\n\t\t\ttext-align: start;\n\t\t}\n\n\t\th3 {\n\t\t\tmargin-top: 0;\n\t\t}\n\t}\n\n\t.checkbox-radio-switch {\n\t\tmargin-inline-start: auto;\n\t\tpadding: 0 2px;\n\t}\n}\n"],sourceRoot:""}]);const s=a},93376:(t,e,n)=>{var i=n(21777),o=n(53334),r=n(85471),a=n(35947);const s=null===(c=(0,i.HW)())?(0,a.YK)().setApp("core").build():(0,a.YK)().setApp("core").setUid(c.uid).build();var c;(0,a.YK)().setApp("unified-search").detectUser().build();var l=n(32981),p=n(63814),d=n(65043);function u(t,e,n){(function(t,e){if(e.has(t))throw new TypeError("Cannot initialize the same private elements twice on an object")})(t,e),e.set(t,n)}function h(t,e,n){return t.set(m(t,e),n),n}function A(t,e){return t.get(m(t,e))}function m(t,e,n){if("function"==typeof t?t===e:t.has(e))return arguments.length<3?e:n;throw new TypeError("Private element is not present on this object")}function g(t,e,n){return(e=function(t){var e=function(t){if("object"!=typeof t||!t)return t;var e=t[Symbol.toPrimitive];if(void 0!==e){var n=e.call(t,"string");if("object"!=typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return"symbol"==typeof e?e:e+""}(e))in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}class v{constructor(t){g(this,"value",void 0),g(this,"next",void 0),this.value=t}}var f=new WeakMap,C=new WeakMap,b=new WeakMap;class y{constructor(){u(this,f,void 0),u(this,C,void 0),u(this,b,void 0),this.clear()}enqueue(t){var e;const n=new v(t);A(f,this)?(A(C,this).next=n,h(C,this,n)):(h(f,this,n),h(C,this,n)),h(b,this,(e=A(b,this),++e))}dequeue(){var t;const e=A(f,this);if(e)return h(f,this,A(f,this).next),h(b,this,(t=A(b,this),--t)),e.value}peek(){if(A(f,this))return A(f,this).value}clear(){h(f,this,void 0),h(C,this,void 0),h(b,this,0)}get size(){return A(b,this)}*[Symbol.iterator](){let t=A(f,this);for(;t;)yield t.value,t=t.next}}function w(t){x(t);const e=new y;let n=0;const i=()=>{n<t&&e.size>0&&(e.dequeue()(),n++)},o=async(t,e,o)=>{const r=(async()=>t(...o))();e(r);try{await r}catch{}n--,i()},r=function(r){for(var a=arguments.length,s=new Array(a>1?a-1:0),c=1;c<a;c++)s[c-1]=arguments[c];return new Promise((a=>{((r,a,s)=>{new Promise((t=>{e.enqueue(t)})).then(o.bind(void 0,r,a,s)),(async()=>{await Promise.resolve(),n<t&&i()})()})(r,a,s)}))};return Object.defineProperties(r,{activeCount:{get:()=>n},pendingCount:{get:()=>e.size},clearQueue:{value(){e.clear()}},concurrency:{get:()=>t,set(o){x(o),t=o,queueMicrotask((()=>{for(;n<t&&e.size>0;)i()}))}}}),r}function x(t){if(!Number.isInteger(t)&&t!==Number.POSITIVE_INFINITY||!(t>0))throw new TypeError("Expected `concurrency` to be a number from 1 and up")}var _=n(97012),k=n(32073);const S={calendar:{description:(0,o.t)("core","Schedule work & meetings, synced with all your devices."),icon:(0,p.d0)("core","places/calendar.svg")},contacts:{description:(0,o.t)("core","Keep your colleagues and friends in one place without leaking their private info."),icon:(0,p.d0)("core","places/contacts.svg")},mail:{description:(0,o.t)("core","Simple email app nicely integrated with Files, Contacts and Calendar."),icon:(0,p.d0)("core","actions/mail.svg")},spreed:{description:(0,o.t)("core","Chatting, video calls, screen sharing, online meetings and web conferencing – in your browser and with mobile apps."),icon:(0,p.d0)("core","apps/spreed.svg")},richdocuments:{name:"Nextcloud Office",description:(0,o.t)("core","Collaborative documents, spreadsheets and presentations, built on Collabora Online."),icon:(0,p.d0)("core","apps/richdocuments.svg")},notes:{description:(0,o.t)("core","Distraction free note taking app."),icon:(0,p.d0)("core","apps/notes.svg")},richdocumentscode:{hidden:!0}},I=Object.keys(S),P={name:"RecommendedApps",components:{NcCheckboxRadioSwitch:k.A,NcButton:_.A},data:()=>({showInstallButton:!1,installingApps:!1,loadingApps:!0,loadingAppsError:!1,apps:[],defaultPageUrl:(0,l.C)("core","defaultPageUrl")}),computed:{recommendedApps(){return this.apps.filter((t=>I.includes(t.id)))},isAnyAppSelected(){return this.recommendedApps.some((t=>t.isSelected))}},async mounted(){try{const{data:t}=await d.Ay.get((0,p.Jv)("settings/apps/list"));s.info(`${t.apps.length} apps fetched`),this.apps=t.apps.map((t=>Object.assign(t,{loading:!1,installationError:!1,isSelected:t.isCompatible}))),s.debug(`${this.recommendedApps.length} recommended apps found`,{apps:this.recommendedApps}),this.showInstallButton=!0}catch(t){s.error("could not fetch app list",{error:t}),this.loadingAppsError=!0}finally{this.loadingApps=!1}},methods:{installApps(){this.installingApps=!0;const t=w(1),e=this.recommendedApps.filter((t=>!t.active&&t.isCompatible&&t.canInstall&&t.isSelected)).map((e=>t((async()=>(s.info(`installing ${e.id}`),e.loading=!0,d.Ay.post((0,p.Jv)("settings/apps/enable"),{appIds:[e.id],groups:[]}).catch((t=>{s.error(`could not install ${e.id}`,{error:t}),e.isSelected=!1,e.installationError=!0})).then((()=>{s.info(`installed ${e.id}`),e.loading=!1,e.active=!0})))))));s.debug(`installing ${e.length} recommended apps`),Promise.all(e).then((()=>{s.info("all recommended apps installed, redirecting …"),window.location=this.defaultPageUrl})).catch((t=>s.error("could not install recommended apps",{error:t})))},customIcon:t=>t in S&&S[t].icon?S[t].icon:(s.warn(`no app icon for recommended app ${t}`),(0,p.d0)("core","places/default-app-icon.svg")),customName:t=>t.id in S&&S[t.id].name||t.name,customDescription:t=>t in S?S[t].description:(s.warn(`no app description for recommended app ${t}`),""),isHidden:t=>t in S&&!!S[t].hidden,toggleSelect(t){if(!(t in S)||!this.showInstallButton)return;const e=this.apps.findIndex((e=>e.id===t));this.$set(this.apps[e],"isSelected",!this.apps[e].isSelected)}}};var O=n(85072),j=n.n(O),B=n(97825),E=n.n(B),T=n(77659),N=n.n(T),D=n(55056),$=n.n(D),Y=n(10540),U=n.n(Y),M=n(41113),R=n.n(M),q=n(12665),z={};z.styleTagTransform=R(),z.setAttributes=$(),z.insert=N().bind(null,"head"),z.domAPI=E(),z.insertStyleElement=U(),j()(q.A,z),q.A&&q.A.locals&&q.A.locals;const F=(0,n(14486).A)(P,(function(){var t=this,e=t._self._c;return e("div",{staticClass:"guest-box"},[e("h2",[t._v(t._s(t.t("core","Recommended apps")))]),t._v(" "),t.loadingApps?e("p",{staticClass:"loading text-center"},[t._v("\n\t\t"+t._s(t.t("core","Loading apps …"))+"\n\t")]):t.loadingAppsError?e("p",{staticClass:"loading-error text-center"},[t._v("\n\t\t"+t._s(t.t("core","Could not fetch list of apps from the App Store."))+"\n\t")]):t._e(),t._v(" "),t._l(t.recommendedApps,(function(n){return e("div",{key:n.id,staticClass:"app"},[t.isHidden(n.id)?t._e():[e("img",{attrs:{src:t.customIcon(n.id),alt:""}}),t._v(" "),e("div",{staticClass:"info"},[e("h3",[t._v(t._s(t.customName(n)))]),t._v(" "),e("p",{domProps:{textContent:t._s(t.customDescription(n.id))}}),t._v(" "),n.installationError?e("p",[e("strong",[t._v(t._s(t.t("core","App download or installation failed")))])]):n.isCompatible?n.canInstall?t._e():e("p",[e("strong",[t._v(t._s(t.t("core","Cannot install this app")))])]):e("p",[e("strong",[t._v(t._s(t.t("core","Cannot install this app because it is not compatible")))])])]),t._v(" "),e("NcCheckboxRadioSwitch",{attrs:{checked:n.isSelected||n.active,disabled:!n.isCompatible||n.active,loading:n.loading},on:{"update:checked":function(e){return t.toggleSelect(n.id)}}})]],2)})),t._v(" "),e("div",{staticClass:"dialog-row"},[t.showInstallButton&&!t.installingApps?e("NcButton",{attrs:{type:"tertiary",role:"link",href:t.defaultPageUrl}},[t._v("\n\t\t\t"+t._s(t.t("core","Skip"))+"\n\t\t")]):t._e(),t._v(" "),t.showInstallButton?e("NcButton",{attrs:{type:"primary",disabled:t.installingApps||!t.isAnyAppSelected},on:{click:function(e){return e.stopPropagation(),e.preventDefault(),t.installApps.apply(null,arguments)}}},[t._v("\n\t\t\t"+t._s(t.installingApps?t.t("core","Installing apps …"):t.t("core","Install recommended apps"))+"\n\t\t")]):t._e()],1)],2)}),[],!1,null,"07178674",null).exports;n.nc=(0,i.aV)(),r.Ay.mixin({methods:{t:o.Tl}}),(new(r.Ay.extend(F))).$mount("#recommended-apps"),s.debug("recommended apps view rendered")}},n={};function i(t){var o=n[t];if(void 0!==o)return o.exports;var r=n[t]={id:t,loaded:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.loaded=!0,r.exports}i.m=e,t=[],i.O=(e,n,o,r)=>{if(!n){var a=1/0;for(p=0;p<t.length;p++){n=t[p][0],o=t[p][1],r=t[p][2];for(var s=!0,c=0;c<n.length;c++)(!1&r||a>=r)&&Object.keys(i.O).every((t=>i.O[t](n[c])))?n.splice(c--,1):(s=!1,r<a&&(a=r));if(s){t.splice(p--,1);var l=o();void 0!==l&&(e=l)}}return e}r=r||0;for(var p=t.length;p>0&&t[p-1][2]>r;p--)t[p]=t[p-1];t[p]=[n,o,r]},i.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return i.d(e,{a:e}),e},i.d=(t,e)=>{for(var n in e)i.o(e,n)&&!i.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},i.e=()=>Promise.resolve(),i.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),i.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),i.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.nmd=t=>(t.paths=[],t.children||(t.children=[]),t),i.j=2696,(()=>{i.b=document.baseURI||self.location.href;var t={2696:0};i.O.j=e=>0===t[e];var e=(e,n)=>{var o,r,a=n[0],s=n[1],c=n[2],l=0;if(a.some((e=>0!==t[e]))){for(o in s)i.o(s,o)&&(i.m[o]=s[o]);if(c)var p=c(i)}for(e&&e(n);l<a.length;l++)r=a[l],i.o(t,r)&&t[r]&&t[r][0](),t[r]=0;return i.O(p)},n=self.webpackChunknextcloud=self.webpackChunknextcloud||[];n.forEach(e.bind(null,0)),n.push=e.bind(null,n.push.bind(n))})(),i.nc=void 0;var o=i.O(void 0,[4208],(()=>i(93376)));o=i.O(o)})(); -//# sourceMappingURL=core-recommendedapps.js.map?v=7eba92eea8c86411a9a5
\ No newline at end of file +(()=>{"use strict";var e,t={10440:(e,t,n)=>{var i=n(21777),o=n(53334),a=n(85471),r=n(35947);const s=null===(c=(0,i.HW)())?(0,r.YK)().setApp("core").build():(0,r.YK)().setApp("core").setUid(c.uid).build();var c;(0,r.YK)().setApp("unified-search").detectUser().build();var p=n(32981),l=n(63814),d=n(65043);function u(e,t,n){(function(e,t){if(t.has(e))throw new TypeError("Cannot initialize the same private elements twice on an object")})(e,t),t.set(e,n)}function h(e,t,n){return e.set(A(e,t),n),n}function m(e,t){return e.get(A(e,t))}function A(e,t,n){if("function"==typeof e?e===t:e.has(t))return arguments.length<3?t:n;throw new TypeError("Private element is not present on this object")}function g(e,t,n){return(t=function(e){var t=function(e){if("object"!=typeof e||!e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var n=t.call(e,"string");if("object"!=typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==typeof t?t:t+""}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}class v{constructor(e){g(this,"value",void 0),g(this,"next",void 0),this.value=e}}var f=new WeakMap,b=new WeakMap,C=new WeakMap;class y{constructor(){u(this,f,void 0),u(this,b,void 0),u(this,C,void 0),this.clear()}enqueue(e){var t;const n=new v(e);m(f,this)?(m(b,this).next=n,h(b,this,n)):(h(f,this,n),h(b,this,n)),h(C,this,(t=m(C,this),++t))}dequeue(){var e;const t=m(f,this);if(t)return h(f,this,m(f,this).next),h(C,this,(e=m(C,this),--e)),t.value}peek(){if(m(f,this))return m(f,this).value}clear(){h(f,this,void 0),h(b,this,void 0),h(C,this,0)}get size(){return m(C,this)}*[Symbol.iterator](){let e=m(f,this);for(;e;)yield e.value,e=e.next}}function w(e){x(e);const t=new y;let n=0;const i=()=>{n<e&&t.size>0&&(t.dequeue()(),n++)},o=async(e,t,o)=>{const a=(async()=>e(...o))();t(a);try{await a}catch{}n--,i()},a=function(a){for(var r=arguments.length,s=new Array(r>1?r-1:0),c=1;c<r;c++)s[c-1]=arguments[c];return new Promise((r=>{((a,r,s)=>{new Promise((e=>{t.enqueue(e)})).then(o.bind(void 0,a,r,s)),(async()=>{await Promise.resolve(),n<e&&i()})()})(a,r,s)}))};return Object.defineProperties(a,{activeCount:{get:()=>n},pendingCount:{get:()=>t.size},clearQueue:{value(){t.clear()}},concurrency:{get:()=>e,set(o){x(o),e=o,queueMicrotask((()=>{for(;n<e&&t.size>0;)i()}))}}}),a}function x(e){if(!Number.isInteger(e)&&e!==Number.POSITIVE_INFINITY||!(e>0))throw new TypeError("Expected `concurrency` to be a number from 1 and up")}var _=n(97012),k=n(32073);const S={calendar:{description:(0,o.t)("core","Schedule work & meetings, synced with all your devices."),icon:(0,l.d0)("core","places/calendar.svg")},contacts:{description:(0,o.t)("core","Keep your colleagues and friends in one place without leaking their private info."),icon:(0,l.d0)("core","places/contacts.svg")},mail:{description:(0,o.t)("core","Simple email app nicely integrated with Files, Contacts and Calendar."),icon:(0,l.d0)("core","actions/mail.svg")},spreed:{description:(0,o.t)("core","Chatting, video calls, screen sharing, online meetings and web conferencing – in your browser and with mobile apps."),icon:(0,l.d0)("core","apps/spreed.svg")},richdocuments:{name:"Nextcloud Office",description:(0,o.t)("core","Collaborative documents, spreadsheets and presentations, built on Collabora Online."),icon:(0,l.d0)("core","apps/richdocuments.svg")},notes:{description:(0,o.t)("core","Distraction free note taking app."),icon:(0,l.d0)("core","apps/notes.svg")},richdocumentscode:{hidden:!0}},I=Object.keys(S),P={name:"RecommendedApps",components:{NcCheckboxRadioSwitch:k.A,NcButton:_.A},data:()=>({showInstallButton:!1,installingApps:!1,loadingApps:!0,loadingAppsError:!1,apps:[],defaultPageUrl:(0,p.C)("core","defaultPageUrl")}),computed:{recommendedApps(){return this.apps.filter((e=>I.includes(e.id)))},isAnyAppSelected(){return this.recommendedApps.some((e=>e.isSelected))}},async mounted(){try{const{data:e}=await d.Ay.get((0,l.Jv)("settings/apps/list"));s.info(`${e.apps.length} apps fetched`),this.apps=e.apps.map((e=>Object.assign(e,{loading:!1,installationError:!1,isSelected:e.isCompatible}))),s.debug(`${this.recommendedApps.length} recommended apps found`,{apps:this.recommendedApps}),this.showInstallButton=!0}catch(e){s.error("could not fetch app list",{error:e}),this.loadingAppsError=!0}finally{this.loadingApps=!1}},methods:{installApps(){this.installingApps=!0;const e=w(1),t=this.recommendedApps.filter((e=>!e.active&&e.isCompatible&&e.canInstall&&e.isSelected)).map((t=>e((async()=>(s.info(`installing ${t.id}`),t.loading=!0,d.Ay.post((0,l.Jv)("settings/apps/enable"),{appIds:[t.id],groups:[]}).catch((e=>{s.error(`could not install ${t.id}`,{error:e}),t.isSelected=!1,t.installationError=!0})).then((()=>{s.info(`installed ${t.id}`),t.loading=!1,t.active=!0})))))));s.debug(`installing ${t.length} recommended apps`),Promise.all(t).then((()=>{s.info("all recommended apps installed, redirecting …"),window.location=this.defaultPageUrl})).catch((e=>s.error("could not install recommended apps",{error:e})))},customIcon:e=>e in S&&S[e].icon?S[e].icon:(s.warn(`no app icon for recommended app ${e}`),(0,l.d0)("core","places/default-app-icon.svg")),customName:e=>e.id in S&&S[e.id].name||e.name,customDescription:e=>e in S?S[e].description:(s.warn(`no app description for recommended app ${e}`),""),isHidden:e=>e in S&&!!S[e].hidden,toggleSelect(e){if(!(e in S)||!this.showInstallButton)return;const t=this.apps.findIndex((t=>t.id===e));this.$set(this.apps[t],"isSelected",!this.apps[t].isSelected)}}};var O=n(85072),j=n.n(O),B=n(97825),E=n.n(B),T=n(77659),N=n.n(T),D=n(55056),$=n.n(D),Y=n(10540),U=n.n(Y),M=n(41113),R=n.n(M),q=n(43823),z={};z.styleTagTransform=R(),z.setAttributes=$(),z.insert=N().bind(null,"head"),z.domAPI=E(),z.insertStyleElement=U(),j()(q.A,z),q.A&&q.A.locals&&q.A.locals;const F=(0,n(14486).A)(P,(function(){var e=this,t=e._self._c;return t("div",{staticClass:"guest-box",attrs:{"data-cy-setup-recommended-apps":""}},[t("h2",[e._v(e._s(e.t("core","Recommended apps")))]),e._v(" "),e.loadingApps?t("p",{staticClass:"loading text-center"},[e._v("\n\t\t"+e._s(e.t("core","Loading apps …"))+"\n\t")]):e.loadingAppsError?t("p",{staticClass:"loading-error text-center"},[e._v("\n\t\t"+e._s(e.t("core","Could not fetch list of apps from the App Store."))+"\n\t")]):e._e(),e._v(" "),e._l(e.recommendedApps,(function(n){return t("div",{key:n.id,staticClass:"app"},[e.isHidden(n.id)?e._e():[t("img",{attrs:{src:e.customIcon(n.id),alt:""}}),e._v(" "),t("div",{staticClass:"info"},[t("h3",[e._v(e._s(e.customName(n)))]),e._v(" "),t("p",{domProps:{textContent:e._s(e.customDescription(n.id))}}),e._v(" "),n.installationError?t("p",[t("strong",[e._v(e._s(e.t("core","App download or installation failed")))])]):n.isCompatible?n.canInstall?e._e():t("p",[t("strong",[e._v(e._s(e.t("core","Cannot install this app")))])]):t("p",[t("strong",[e._v(e._s(e.t("core","Cannot install this app because it is not compatible")))])])]),e._v(" "),t("NcCheckboxRadioSwitch",{attrs:{checked:n.isSelected||n.active,disabled:!n.isCompatible||n.active,loading:n.loading},on:{"update:checked":function(t){return e.toggleSelect(n.id)}}})]],2)})),e._v(" "),t("div",{staticClass:"dialog-row"},[e.showInstallButton&&!e.installingApps?t("NcButton",{attrs:{type:"tertiary",role:"link",href:e.defaultPageUrl,"data-cy-setup-recommended-apps-skip":""}},[e._v("\n\t\t\t"+e._s(e.t("core","Skip"))+"\n\t\t")]):e._e(),e._v(" "),e.showInstallButton?t("NcButton",{attrs:{type:"primary",disabled:e.installingApps||!e.isAnyAppSelected,"data-cy-setup-recommended-apps-install":""}},[e._v('\n\t\t\t@click.stop.prevent="installApps">\n\t\t\t'+e._s(e.installingApps?e.t("core","Installing apps …"):e.t("core","Install recommended apps"))+"\n\t\t")]):e._e()],1)],2)}),[],!1,null,"5b5c8ecc",null).exports;n.nc=(0,i.aV)(),a.Ay.mixin({methods:{t:o.Tl}}),(new(a.Ay.extend(F))).$mount("#recommended-apps"),s.debug("recommended apps view rendered")},43823:(e,t,n)=>{n.d(t,{A:()=>s});var i=n(71354),o=n.n(i),a=n(76314),r=n.n(a)()(o());r.push([e.id,".dialog-row[data-v-5b5c8ecc]{display:flex;justify-content:end;margin-top:8px}p.loading[data-v-5b5c8ecc],p.loading-error[data-v-5b5c8ecc]{height:100px}p[data-v-5b5c8ecc]:last-child{margin-top:10px}.text-center[data-v-5b5c8ecc]{text-align:center}.app[data-v-5b5c8ecc]{display:flex;flex-direction:row}.app img[data-v-5b5c8ecc]{height:50px;width:50px;filter:var(--background-invert-if-dark)}.app img[data-v-5b5c8ecc],.app .info[data-v-5b5c8ecc]{padding:12px}.app .info h3[data-v-5b5c8ecc],.app .info p[data-v-5b5c8ecc]{text-align:start}.app .info h3[data-v-5b5c8ecc]{margin-top:0}.app .checkbox-radio-switch[data-v-5b5c8ecc]{margin-inline-start:auto;padding:0 2px}","",{version:3,sources:["webpack://./core/src/components/setup/RecommendedApps.vue"],names:[],mappings:"AACA,6BACC,YAAA,CACA,mBAAA,CACA,cAAA,CAIA,4DAEC,YAAA,CAGD,8BACC,eAAA,CAIF,8BACC,iBAAA,CAGD,sBACC,YAAA,CACA,kBAAA,CAEA,0BACC,WAAA,CACA,UAAA,CACA,uCAAA,CAGD,sDACC,YAAA,CAIA,6DACC,gBAAA,CAGD,+BACC,YAAA,CAIF,6CACC,wBAAA,CACA,aAAA",sourcesContent:["\n.dialog-row {\n\tdisplay: flex;\n\tjustify-content: end;\n\tmargin-top: 8px;\n}\n\np {\n\t&.loading,\n\t&.loading-error {\n\t\theight: 100px;\n\t}\n\n\t&:last-child {\n\t\tmargin-top: 10px;\n\t}\n}\n\n.text-center {\n\ttext-align: center;\n}\n\n.app {\n\tdisplay: flex;\n\tflex-direction: row;\n\n\timg {\n\t\theight: 50px;\n\t\twidth: 50px;\n\t\tfilter: var(--background-invert-if-dark);\n\t}\n\n\timg, .info {\n\t\tpadding: 12px;\n\t}\n\n\t.info {\n\t\th3, p {\n\t\t\ttext-align: start;\n\t\t}\n\n\t\th3 {\n\t\t\tmargin-top: 0;\n\t\t}\n\t}\n\n\t.checkbox-radio-switch {\n\t\tmargin-inline-start: auto;\n\t\tpadding: 0 2px;\n\t}\n}\n"],sourceRoot:""}]);const s=r}},n={};function i(e){var o=n[e];if(void 0!==o)return o.exports;var a=n[e]={id:e,loaded:!1,exports:{}};return t[e].call(a.exports,a,a.exports,i),a.loaded=!0,a.exports}i.m=t,e=[],i.O=(t,n,o,a)=>{if(!n){var r=1/0;for(l=0;l<e.length;l++){n=e[l][0],o=e[l][1],a=e[l][2];for(var s=!0,c=0;c<n.length;c++)(!1&a||r>=a)&&Object.keys(i.O).every((e=>i.O[e](n[c])))?n.splice(c--,1):(s=!1,a<r&&(r=a));if(s){e.splice(l--,1);var p=o();void 0!==p&&(t=p)}}return t}a=a||0;for(var l=e.length;l>0&&e[l-1][2]>a;l--)e[l]=e[l-1];e[l]=[n,o,a]},i.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return i.d(t,{a:t}),t},i.d=(e,t)=>{for(var n in t)i.o(t,n)&&!i.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},i.e=()=>Promise.resolve(),i.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),i.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),i.j=2696,(()=>{i.b=document.baseURI||self.location.href;var e={2696:0};i.O.j=t=>0===e[t];var t=(t,n)=>{var o,a,r=n[0],s=n[1],c=n[2],p=0;if(r.some((t=>0!==e[t]))){for(o in s)i.o(s,o)&&(i.m[o]=s[o]);if(c)var l=c(i)}for(t&&t(n);p<r.length;p++)a=r[p],i.o(e,a)&&e[a]&&e[a][0](),e[a]=0;return i.O(l)},n=self.webpackChunknextcloud=self.webpackChunknextcloud||[];n.forEach(t.bind(null,0)),n.push=t.bind(null,n.push.bind(n))})(),i.nc=void 0;var o=i.O(void 0,[4208],(()=>i(10440)));o=i.O(o)})(); +//# sourceMappingURL=core-recommendedapps.js.map?v=22a85edc85db40d68272
\ No newline at end of file diff --git a/dist/core-recommendedapps.js.map b/dist/core-recommendedapps.js.map index 0f9f44c3652..54514078a70 100644 --- a/dist/core-recommendedapps.js.map +++ b/dist/core-recommendedapps.js.map @@ -1 +1 @@ -{"version":3,"file":"core-recommendedapps.js?v=7eba92eea8c86411a9a5","mappings":"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","sources":["webpack:///nextcloud/webpack/runtime/chunk loaded","webpack:///nextcloud/core/src/components/setup/RecommendedApps.vue?vue&type=style&index=0&id=07178674&prod&lang=scss&scoped=true","webpack:///nextcloud/core/src/logger.js","webpack://nextcloud/./core/src/components/setup/RecommendedApps.vue?5f06","webpack:///nextcloud/node_modules/yocto-queue/index.js","webpack:///nextcloud/node_modules/p-limit/index.js","webpack:///nextcloud/core/src/components/setup/RecommendedApps.vue","webpack:///nextcloud/core/src/components/setup/RecommendedApps.vue?vue&type=script&lang=js","webpack://nextcloud/./core/src/components/setup/RecommendedApps.vue?ff8d","webpack://nextcloud/./core/src/components/setup/RecommendedApps.vue?84e8","webpack:///nextcloud/core/src/recommendedapps.js","webpack:///nextcloud/webpack/bootstrap","webpack:///nextcloud/webpack/runtime/compat get default export","webpack:///nextcloud/webpack/runtime/define property getters","webpack:///nextcloud/webpack/runtime/ensure chunk","webpack:///nextcloud/webpack/runtime/global","webpack:///nextcloud/webpack/runtime/hasOwnProperty shorthand","webpack:///nextcloud/webpack/runtime/make namespace object","webpack:///nextcloud/webpack/runtime/node module decorator","webpack:///nextcloud/webpack/runtime/runtimeId","webpack:///nextcloud/webpack/runtime/jsonp chunk loading","webpack:///nextcloud/webpack/runtime/nonce","webpack:///nextcloud/webpack/startup"],"sourcesContent":["var deferred = [];\n__webpack_require__.O = (result, chunkIds, fn, priority) => {\n\tif(chunkIds) {\n\t\tpriority = priority || 0;\n\t\tfor(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];\n\t\tdeferred[i] = [chunkIds, fn, priority];\n\t\treturn;\n\t}\n\tvar notFulfilled = Infinity;\n\tfor (var i = 0; i < deferred.length; i++) {\n\t\tvar chunkIds = deferred[i][0];\n\t\tvar fn = deferred[i][1];\n\t\tvar priority = deferred[i][2];\n\t\tvar fulfilled = true;\n\t\tfor (var j = 0; j < chunkIds.length; j++) {\n\t\t\tif ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))) {\n\t\t\t\tchunkIds.splice(j--, 1);\n\t\t\t} else {\n\t\t\t\tfulfilled = false;\n\t\t\t\tif(priority < notFulfilled) notFulfilled = priority;\n\t\t\t}\n\t\t}\n\t\tif(fulfilled) {\n\t\t\tdeferred.splice(i--, 1)\n\t\t\tvar r = fn();\n\t\t\tif (r !== undefined) result = r;\n\t\t}\n\t}\n\treturn result;\n};","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `.dialog-row[data-v-07178674]{display:flex;justify-content:end;margin-top:8px}p.loading[data-v-07178674],p.loading-error[data-v-07178674]{height:100px}p[data-v-07178674]:last-child{margin-top:10px}.text-center[data-v-07178674]{text-align:center}.app[data-v-07178674]{display:flex;flex-direction:row}.app img[data-v-07178674]{height:50px;width:50px;filter:var(--background-invert-if-dark)}.app img[data-v-07178674],.app .info[data-v-07178674]{padding:12px}.app .info h3[data-v-07178674],.app .info p[data-v-07178674]{text-align:start}.app .info h3[data-v-07178674]{margin-top:0}.app .checkbox-radio-switch[data-v-07178674]{margin-inline-start:auto;padding:0 2px}`, \"\",{\"version\":3,\"sources\":[\"webpack://./core/src/components/setup/RecommendedApps.vue\"],\"names\":[],\"mappings\":\"AACA,6BACC,YAAA,CACA,mBAAA,CACA,cAAA,CAIA,4DAEC,YAAA,CAGD,8BACC,eAAA,CAIF,8BACC,iBAAA,CAGD,sBACC,YAAA,CACA,kBAAA,CAEA,0BACC,WAAA,CACA,UAAA,CACA,uCAAA,CAGD,sDACC,YAAA,CAIA,6DACC,gBAAA,CAGD,+BACC,YAAA,CAIF,6CACC,wBAAA,CACA,aAAA\",\"sourcesContent\":[\"\\n.dialog-row {\\n\\tdisplay: flex;\\n\\tjustify-content: end;\\n\\tmargin-top: 8px;\\n}\\n\\np {\\n\\t&.loading,\\n\\t&.loading-error {\\n\\t\\theight: 100px;\\n\\t}\\n\\n\\t&:last-child {\\n\\t\\tmargin-top: 10px;\\n\\t}\\n}\\n\\n.text-center {\\n\\ttext-align: center;\\n}\\n\\n.app {\\n\\tdisplay: flex;\\n\\tflex-direction: row;\\n\\n\\timg {\\n\\t\\theight: 50px;\\n\\t\\twidth: 50px;\\n\\t\\tfilter: var(--background-invert-if-dark);\\n\\t}\\n\\n\\timg, .info {\\n\\t\\tpadding: 12px;\\n\\t}\\n\\n\\t.info {\\n\\t\\th3, p {\\n\\t\\t\\ttext-align: start;\\n\\t\\t}\\n\\n\\t\\th3 {\\n\\t\\t\\tmargin-top: 0;\\n\\t\\t}\\n\\t}\\n\\n\\t.checkbox-radio-switch {\\n\\t\\tmargin-inline-start: auto;\\n\\t\\tpadding: 0 2px;\\n\\t}\\n}\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { getCurrentUser } from '@nextcloud/auth'\nimport { getLoggerBuilder } from '@nextcloud/logger'\n\nconst getLogger = user => {\n\tif (user === null) {\n\t\treturn getLoggerBuilder()\n\t\t\t.setApp('core')\n\t\t\t.build()\n\t}\n\treturn getLoggerBuilder()\n\t\t.setApp('core')\n\t\t.setUid(user.uid)\n\t\t.build()\n}\n\nexport default getLogger(getCurrentUser())\n\nexport const unifiedSearchLogger = getLoggerBuilder()\n\t.setApp('unified-search')\n\t.detectUser()\n\t.build()\n","var render = function render(){var _vm=this,_c=_vm._self._c;return _c('div',{staticClass:\"guest-box\"},[_c('h2',[_vm._v(_vm._s(_vm.t('core', 'Recommended apps')))]),_vm._v(\" \"),(_vm.loadingApps)?_c('p',{staticClass:\"loading text-center\"},[_vm._v(\"\\n\\t\\t\"+_vm._s(_vm.t('core', 'Loading apps …'))+\"\\n\\t\")]):(_vm.loadingAppsError)?_c('p',{staticClass:\"loading-error text-center\"},[_vm._v(\"\\n\\t\\t\"+_vm._s(_vm.t('core', 'Could not fetch list of apps from the App Store.'))+\"\\n\\t\")]):_vm._e(),_vm._v(\" \"),_vm._l((_vm.recommendedApps),function(app){return _c('div',{key:app.id,staticClass:\"app\"},[(!_vm.isHidden(app.id))?[_c('img',{attrs:{\"src\":_vm.customIcon(app.id),\"alt\":\"\"}}),_vm._v(\" \"),_c('div',{staticClass:\"info\"},[_c('h3',[_vm._v(_vm._s(_vm.customName(app)))]),_vm._v(\" \"),_c('p',{domProps:{\"textContent\":_vm._s(_vm.customDescription(app.id))}}),_vm._v(\" \"),(app.installationError)?_c('p',[_c('strong',[_vm._v(_vm._s(_vm.t('core', 'App download or installation failed')))])]):(!app.isCompatible)?_c('p',[_c('strong',[_vm._v(_vm._s(_vm.t('core', 'Cannot install this app because it is not compatible')))])]):(!app.canInstall)?_c('p',[_c('strong',[_vm._v(_vm._s(_vm.t('core', 'Cannot install this app')))])]):_vm._e()]),_vm._v(\" \"),_c('NcCheckboxRadioSwitch',{attrs:{\"checked\":app.isSelected || app.active,\"disabled\":!app.isCompatible || app.active,\"loading\":app.loading},on:{\"update:checked\":function($event){return _vm.toggleSelect(app.id)}}})]:_vm._e()],2)}),_vm._v(\" \"),_c('div',{staticClass:\"dialog-row\"},[(_vm.showInstallButton && !_vm.installingApps)?_c('NcButton',{attrs:{\"type\":\"tertiary\",\"role\":\"link\",\"href\":_vm.defaultPageUrl}},[_vm._v(\"\\n\\t\\t\\t\"+_vm._s(_vm.t('core', 'Skip'))+\"\\n\\t\\t\")]):_vm._e(),_vm._v(\" \"),(_vm.showInstallButton)?_c('NcButton',{attrs:{\"type\":\"primary\",\"disabled\":_vm.installingApps || !_vm.isAnyAppSelected},on:{\"click\":function($event){$event.stopPropagation();$event.preventDefault();return _vm.installApps.apply(null, arguments)}}},[_vm._v(\"\\n\\t\\t\\t\"+_vm._s(_vm.installingApps ? _vm.t('core', 'Installing apps …') : _vm.t('core', 'Install recommended apps'))+\"\\n\\t\\t\")]):_vm._e()],1)],2)\n}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","/*\nHow it works:\n`this.#head` is an instance of `Node` which keeps track of its current value and nests another instance of `Node` that keeps the value that comes after it. When a value is provided to `.enqueue()`, the code needs to iterate through `this.#head`, going deeper and deeper to find the last value. However, iterating through every single item is slow. This problem is solved by saving a reference to the last value as `this.#tail` so that it can reference it to add a new value.\n*/\n\nclass Node {\n\tvalue;\n\tnext;\n\n\tconstructor(value) {\n\t\tthis.value = value;\n\t}\n}\n\nexport default class Queue {\n\t#head;\n\t#tail;\n\t#size;\n\n\tconstructor() {\n\t\tthis.clear();\n\t}\n\n\tenqueue(value) {\n\t\tconst node = new Node(value);\n\n\t\tif (this.#head) {\n\t\t\tthis.#tail.next = node;\n\t\t\tthis.#tail = node;\n\t\t} else {\n\t\t\tthis.#head = node;\n\t\t\tthis.#tail = node;\n\t\t}\n\n\t\tthis.#size++;\n\t}\n\n\tdequeue() {\n\t\tconst current = this.#head;\n\t\tif (!current) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#head = this.#head.next;\n\t\tthis.#size--;\n\t\treturn current.value;\n\t}\n\n\tpeek() {\n\t\tif (!this.#head) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn this.#head.value;\n\n\t\t// TODO: Node.js 18.\n\t\t// return this.#head?.value;\n\t}\n\n\tclear() {\n\t\tthis.#head = undefined;\n\t\tthis.#tail = undefined;\n\t\tthis.#size = 0;\n\t}\n\n\tget size() {\n\t\treturn this.#size;\n\t}\n\n\t* [Symbol.iterator]() {\n\t\tlet current = this.#head;\n\n\t\twhile (current) {\n\t\t\tyield current.value;\n\t\t\tcurrent = current.next;\n\t\t}\n\t}\n}\n","import Queue from 'yocto-queue';\n\nexport default function pLimit(concurrency) {\n\tvalidateConcurrency(concurrency);\n\n\tconst queue = new Queue();\n\tlet activeCount = 0;\n\n\tconst resumeNext = () => {\n\t\tif (activeCount < concurrency && queue.size > 0) {\n\t\t\tqueue.dequeue()();\n\t\t\t// Since `pendingCount` has been decreased by one, increase `activeCount` by one.\n\t\t\tactiveCount++;\n\t\t}\n\t};\n\n\tconst next = () => {\n\t\tactiveCount--;\n\n\t\tresumeNext();\n\t};\n\n\tconst run = async (function_, resolve, arguments_) => {\n\t\tconst result = (async () => function_(...arguments_))();\n\n\t\tresolve(result);\n\n\t\ttry {\n\t\t\tawait result;\n\t\t} catch {}\n\n\t\tnext();\n\t};\n\n\tconst enqueue = (function_, resolve, arguments_) => {\n\t\t// Queue `internalResolve` instead of the `run` function\n\t\t// to preserve asynchronous context.\n\t\tnew Promise(internalResolve => {\n\t\t\tqueue.enqueue(internalResolve);\n\t\t}).then(\n\t\t\trun.bind(undefined, function_, resolve, arguments_),\n\t\t);\n\n\t\t(async () => {\n\t\t\t// This function needs to wait until the next microtask before comparing\n\t\t\t// `activeCount` to `concurrency`, because `activeCount` is updated asynchronously\n\t\t\t// after the `internalResolve` function is dequeued and called. The comparison in the if-statement\n\t\t\t// needs to happen asynchronously as well to get an up-to-date value for `activeCount`.\n\t\t\tawait Promise.resolve();\n\n\t\t\tif (activeCount < concurrency) {\n\t\t\t\tresumeNext();\n\t\t\t}\n\t\t})();\n\t};\n\n\tconst generator = (function_, ...arguments_) => new Promise(resolve => {\n\t\tenqueue(function_, resolve, arguments_);\n\t});\n\n\tObject.defineProperties(generator, {\n\t\tactiveCount: {\n\t\t\tget: () => activeCount,\n\t\t},\n\t\tpendingCount: {\n\t\t\tget: () => queue.size,\n\t\t},\n\t\tclearQueue: {\n\t\t\tvalue() {\n\t\t\t\tqueue.clear();\n\t\t\t},\n\t\t},\n\t\tconcurrency: {\n\t\t\tget: () => concurrency,\n\n\t\t\tset(newConcurrency) {\n\t\t\t\tvalidateConcurrency(newConcurrency);\n\t\t\t\tconcurrency = newConcurrency;\n\n\t\t\t\tqueueMicrotask(() => {\n\t\t\t\t\t// eslint-disable-next-line no-unmodified-loop-condition\n\t\t\t\t\twhile (activeCount < concurrency && queue.size > 0) {\n\t\t\t\t\t\tresumeNext();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t},\n\t\t},\n\t});\n\n\treturn generator;\n}\n\nexport function limitFunction(function_, option) {\n\tconst {concurrency} = option;\n\tconst limit = pLimit(concurrency);\n\n\treturn (...arguments_) => limit(() => function_(...arguments_));\n}\n\nfunction validateConcurrency(concurrency) {\n\tif (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) {\n\t\tthrow new TypeError('Expected `concurrency` to be a number from 1 and up');\n\t}\n}\n","<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<template>\n\t<div class=\"guest-box\">\n\t\t<h2>{{ t('core', 'Recommended apps') }}</h2>\n\t\t<p v-if=\"loadingApps\" class=\"loading text-center\">\n\t\t\t{{ t('core', 'Loading apps …') }}\n\t\t</p>\n\t\t<p v-else-if=\"loadingAppsError\" class=\"loading-error text-center\">\n\t\t\t{{ t('core', 'Could not fetch list of apps from the App Store.') }}\n\t\t</p>\n\n\t\t<div v-for=\"app in recommendedApps\" :key=\"app.id\" class=\"app\">\n\t\t\t<template v-if=\"!isHidden(app.id)\">\n\t\t\t\t<img :src=\"customIcon(app.id)\" alt=\"\">\n\t\t\t\t<div class=\"info\">\n\t\t\t\t\t<h3>{{ customName(app) }}</h3>\n\t\t\t\t\t<p v-text=\"customDescription(app.id)\" />\n\t\t\t\t\t<p v-if=\"app.installationError\">\n\t\t\t\t\t\t<strong>{{ t('core', 'App download or installation failed') }}</strong>\n\t\t\t\t\t</p>\n\t\t\t\t\t<p v-else-if=\"!app.isCompatible\">\n\t\t\t\t\t\t<strong>{{ t('core', 'Cannot install this app because it is not compatible') }}</strong>\n\t\t\t\t\t</p>\n\t\t\t\t\t<p v-else-if=\"!app.canInstall\">\n\t\t\t\t\t\t<strong>{{ t('core', 'Cannot install this app') }}</strong>\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t\t<NcCheckboxRadioSwitch :checked=\"app.isSelected || app.active\"\n\t\t\t\t\t:disabled=\"!app.isCompatible || app.active\"\n\t\t\t\t\t:loading=\"app.loading\"\n\t\t\t\t\t@update:checked=\"toggleSelect(app.id)\" />\n\t\t\t</template>\n\t\t</div>\n\n\t\t<div class=\"dialog-row\">\n\t\t\t<NcButton v-if=\"showInstallButton && !installingApps\"\n\t\t\t\ttype=\"tertiary\"\n\t\t\t\trole=\"link\"\n\t\t\t\t:href=\"defaultPageUrl\">\n\t\t\t\t{{ t('core', 'Skip') }}\n\t\t\t</NcButton>\n\n\t\t\t<NcButton v-if=\"showInstallButton\"\n\t\t\t\ttype=\"primary\"\n\t\t\t\t:disabled=\"installingApps || !isAnyAppSelected\"\n\t\t\t\t@click.stop.prevent=\"installApps\">\n\t\t\t\t{{ installingApps ? t('core', 'Installing apps …') : t('core', 'Install recommended apps') }}\n\t\t\t</NcButton>\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport { t } from '@nextcloud/l10n'\nimport { loadState } from '@nextcloud/initial-state'\nimport { generateUrl, imagePath } from '@nextcloud/router'\nimport axios from '@nextcloud/axios'\nimport pLimit from 'p-limit'\nimport logger from '../../logger.js'\n\nimport NcButton from '@nextcloud/vue/components/NcButton'\nimport NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'\n\nconst recommended = {\n\tcalendar: {\n\t\tdescription: t('core', 'Schedule work & meetings, synced with all your devices.'),\n\t\ticon: imagePath('core', 'places/calendar.svg'),\n\t},\n\tcontacts: {\n\t\tdescription: t('core', 'Keep your colleagues and friends in one place without leaking their private info.'),\n\t\ticon: imagePath('core', 'places/contacts.svg'),\n\t},\n\tmail: {\n\t\tdescription: t('core', 'Simple email app nicely integrated with Files, Contacts and Calendar.'),\n\t\ticon: imagePath('core', 'actions/mail.svg'),\n\t},\n\tspreed: {\n\t\tdescription: t('core', 'Chatting, video calls, screen sharing, online meetings and web conferencing – in your browser and with mobile apps.'),\n\t\ticon: imagePath('core', 'apps/spreed.svg'),\n\t},\n\trichdocuments: {\n\t\tname: 'Nextcloud Office',\n\t\tdescription: t('core', 'Collaborative documents, spreadsheets and presentations, built on Collabora Online.'),\n\t\ticon: imagePath('core', 'apps/richdocuments.svg'),\n\t},\n\tnotes: {\n\t\tdescription: t('core', 'Distraction free note taking app.'),\n\t\ticon: imagePath('core', 'apps/notes.svg'),\n\t},\n\trichdocumentscode: {\n\t\thidden: true,\n\t},\n}\nconst recommendedIds = Object.keys(recommended)\n\nexport default {\n\tname: 'RecommendedApps',\n\tcomponents: {\n\t\tNcCheckboxRadioSwitch,\n\t\tNcButton,\n\t},\n\tdata() {\n\t\treturn {\n\t\t\tshowInstallButton: false,\n\t\t\tinstallingApps: false,\n\t\t\tloadingApps: true,\n\t\t\tloadingAppsError: false,\n\t\t\tapps: [],\n\t\t\tdefaultPageUrl: loadState('core', 'defaultPageUrl'),\n\t\t}\n\t},\n\tcomputed: {\n\t\trecommendedApps() {\n\t\t\treturn this.apps.filter(app => recommendedIds.includes(app.id))\n\t\t},\n\t\tisAnyAppSelected() {\n\t\t\treturn this.recommendedApps.some(app => app.isSelected)\n\t\t},\n\t},\n\tasync mounted() {\n\t\ttry {\n\t\t\tconst { data } = await axios.get(generateUrl('settings/apps/list'))\n\t\t\tlogger.info(`${data.apps.length} apps fetched`)\n\n\t\t\tthis.apps = data.apps.map(app => Object.assign(app, { loading: false, installationError: false, isSelected: app.isCompatible }))\n\t\t\tlogger.debug(`${this.recommendedApps.length} recommended apps found`, { apps: this.recommendedApps })\n\n\t\t\tthis.showInstallButton = true\n\t\t} catch (error) {\n\t\t\tlogger.error('could not fetch app list', { error })\n\n\t\t\tthis.loadingAppsError = true\n\t\t} finally {\n\t\t\tthis.loadingApps = false\n\t\t}\n\t},\n\tmethods: {\n\t\tinstallApps() {\n\t\t\tthis.installingApps = true\n\n\t\t\tconst limit = pLimit(1)\n\t\t\tconst installing = this.recommendedApps\n\t\t\t\t.filter(app => !app.active && app.isCompatible && app.canInstall && app.isSelected)\n\t\t\t\t.map(app => limit(async () => {\n\t\t\t\t\tlogger.info(`installing ${app.id}`)\n\t\t\t\t\tapp.loading = true\n\t\t\t\t\treturn axios.post(generateUrl('settings/apps/enable'), { appIds: [app.id], groups: [] })\n\t\t\t\t\t\t.catch(error => {\n\t\t\t\t\t\t\tlogger.error(`could not install ${app.id}`, { error })\n\t\t\t\t\t\t\tapp.isSelected = false\n\t\t\t\t\t\t\tapp.installationError = true\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.then(() => {\n\t\t\t\t\t\t\tlogger.info(`installed ${app.id}`)\n\t\t\t\t\t\t\tapp.loading = false\n\t\t\t\t\t\t\tapp.active = true\n\t\t\t\t\t\t})\n\t\t\t\t}))\n\t\t\tlogger.debug(`installing ${installing.length} recommended apps`)\n\t\t\tPromise.all(installing)\n\t\t\t\t.then(() => {\n\t\t\t\t\tlogger.info('all recommended apps installed, redirecting …')\n\n\t\t\t\t\twindow.location = this.defaultPageUrl\n\t\t\t\t})\n\t\t\t\t.catch(error => logger.error('could not install recommended apps', { error }))\n\t\t},\n\t\tcustomIcon(appId) {\n\t\t\tif (!(appId in recommended) || !recommended[appId].icon) {\n\t\t\t\tlogger.warn(`no app icon for recommended app ${appId}`)\n\t\t\t\treturn imagePath('core', 'places/default-app-icon.svg')\n\t\t\t}\n\t\t\treturn recommended[appId].icon\n\t\t},\n\t\tcustomName(app) {\n\t\t\tif (!(app.id in recommended)) {\n\t\t\t\treturn app.name\n\t\t\t}\n\t\t\treturn recommended[app.id].name || app.name\n\t\t},\n\t\tcustomDescription(appId) {\n\t\t\tif (!(appId in recommended)) {\n\t\t\t\tlogger.warn(`no app description for recommended app ${appId}`)\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn recommended[appId].description\n\t\t},\n\t\tisHidden(appId) {\n\t\t\tif (!(appId in recommended)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn !!recommended[appId].hidden\n\t\t},\n\t\ttoggleSelect(appId) {\n\t\t\t// disable toggle when installButton is disabled\n\t\t\tif (!(appId in recommended) || !this.showInstallButton) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst index = this.apps.findIndex(app => app.id === appId)\n\t\t\tthis.$set(this.apps[index], 'isSelected', !this.apps[index].isSelected)\n\t\t},\n\t},\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.dialog-row {\n\tdisplay: flex;\n\tjustify-content: end;\n\tmargin-top: 8px;\n}\n\np {\n\t&.loading,\n\t&.loading-error {\n\t\theight: 100px;\n\t}\n\n\t&:last-child {\n\t\tmargin-top: 10px;\n\t}\n}\n\n.text-center {\n\ttext-align: center;\n}\n\n.app {\n\tdisplay: flex;\n\tflex-direction: row;\n\n\timg {\n\t\theight: 50px;\n\t\twidth: 50px;\n\t\tfilter: var(--background-invert-if-dark);\n\t}\n\n\timg, .info {\n\t\tpadding: 12px;\n\t}\n\n\t.info {\n\t\th3, p {\n\t\t\ttext-align: start;\n\t\t}\n\n\t\th3 {\n\t\t\tmargin-top: 0;\n\t\t}\n\t}\n\n\t.checkbox-radio-switch {\n\t\tmargin-inline-start: auto;\n\t\tpadding: 0 2px;\n\t}\n}\n</style>\n","import mod from \"-!../../../../node_modules/babel-loader/lib/index.js!../../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./RecommendedApps.vue?vue&type=script&lang=js\"; export default mod; export * from \"-!../../../../node_modules/babel-loader/lib/index.js!../../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./RecommendedApps.vue?vue&type=script&lang=js\"","\n import API from \"!../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../../../node_modules/css-loader/dist/cjs.js!../../../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../../../node_modules/sass-loader/dist/cjs.js!../../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./RecommendedApps.vue?vue&type=style&index=0&id=07178674&prod&lang=scss&scoped=true\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\noptions.insert = insertFn.bind(null, \"head\");\noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../../../node_modules/css-loader/dist/cjs.js!../../../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../../../node_modules/sass-loader/dist/cjs.js!../../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./RecommendedApps.vue?vue&type=style&index=0&id=07178674&prod&lang=scss&scoped=true\";\n export default content && content.locals ? content.locals : undefined;\n","import { render, staticRenderFns } from \"./RecommendedApps.vue?vue&type=template&id=07178674&scoped=true\"\nimport script from \"./RecommendedApps.vue?vue&type=script&lang=js\"\nexport * from \"./RecommendedApps.vue?vue&type=script&lang=js\"\nimport style0 from \"./RecommendedApps.vue?vue&type=style&index=0&id=07178674&prod&lang=scss&scoped=true\"\n\n\n/* normalize component */\nimport normalizer from \"!../../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n \"07178674\",\n null\n \n)\n\nexport default component.exports","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { getCSPNonce } from '@nextcloud/auth'\nimport { translate as t } from '@nextcloud/l10n'\nimport Vue from 'vue'\n\nimport logger from './logger.js'\nimport RecommendedApps from './components/setup/RecommendedApps.vue'\n\n// eslint-disable-next-line camelcase\n__webpack_nonce__ = getCSPNonce()\n\nVue.mixin({\n\tmethods: {\n\t\tt,\n\t},\n})\n\nconst View = Vue.extend(RecommendedApps)\nnew View().$mount('#recommended-apps')\n\nlogger.debug('recommended apps view rendered')\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\tid: moduleId,\n\t\tloaded: false,\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Flag the module as loaded\n\tmodule.loaded = true;\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n// expose the modules object (__webpack_modules__)\n__webpack_require__.m = __webpack_modules__;\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","// The chunk loading function for additional chunks\n// Since all referenced chunks are already included\n// in this file, this function is empty here.\n__webpack_require__.e = () => (Promise.resolve());","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","__webpack_require__.nmd = (module) => {\n\tmodule.paths = [];\n\tif (!module.children) module.children = [];\n\treturn module;\n};","__webpack_require__.j = 2696;","__webpack_require__.b = document.baseURI || self.location.href;\n\n// object to store loaded and loading chunks\n// undefined = chunk not loaded, null = chunk preloaded/prefetched\n// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded\nvar installedChunks = {\n\t2696: 0\n};\n\n// no chunk on demand loading\n\n// no prefetching\n\n// no preloaded\n\n// no HMR\n\n// no HMR manifest\n\n__webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);\n\n// install a JSONP callback for chunk loading\nvar webpackJsonpCallback = (parentChunkLoadingFunction, data) => {\n\tvar chunkIds = data[0];\n\tvar moreModules = data[1];\n\tvar runtime = data[2];\n\t// add \"moreModules\" to the modules object,\n\t// then flag all \"chunkIds\" as loaded and fire callback\n\tvar moduleId, chunkId, i = 0;\n\tif(chunkIds.some((id) => (installedChunks[id] !== 0))) {\n\t\tfor(moduleId in moreModules) {\n\t\t\tif(__webpack_require__.o(moreModules, moduleId)) {\n\t\t\t\t__webpack_require__.m[moduleId] = moreModules[moduleId];\n\t\t\t}\n\t\t}\n\t\tif(runtime) var result = runtime(__webpack_require__);\n\t}\n\tif(parentChunkLoadingFunction) parentChunkLoadingFunction(data);\n\tfor(;i < chunkIds.length; i++) {\n\t\tchunkId = chunkIds[i];\n\t\tif(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {\n\t\t\tinstalledChunks[chunkId][0]();\n\t\t}\n\t\tinstalledChunks[chunkId] = 0;\n\t}\n\treturn __webpack_require__.O(result);\n}\n\nvar chunkLoadingGlobal = self[\"webpackChunknextcloud\"] = self[\"webpackChunknextcloud\"] || [];\nchunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));\nchunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));","__webpack_require__.nc = undefined;","// startup\n// Load entry module and return exports\n// This entry module depends on other loaded chunks and execution need to be delayed\nvar __webpack_exports__ = __webpack_require__.O(undefined, [4208], () => (__webpack_require__(93376)))\n__webpack_exports__ = __webpack_require__.O(__webpack_exports__);\n"],"names":["deferred","___CSS_LOADER_EXPORT___","push","module","id","user","getCurrentUser","getLoggerBuilder","setApp","build","setUid","uid","detectUser","Node","constructor","value","_defineProperty","this","_head","WeakMap","_tail","_size","Queue","_classPrivateFieldInitSpec","clear","enqueue","_this$size","node","_classPrivateFieldGet","next","_classPrivateFieldSet","dequeue","_this$size3","current","peek","undefined","size","Symbol","iterator","pLimit","concurrency","validateConcurrency","queue","activeCount","resumeNext","run","async","function_","resolve","arguments_","result","generator","_len","arguments","length","Array","_key","Promise","internalResolve","then","bind","Object","defineProperties","get","pendingCount","clearQueue","set","newConcurrency","queueMicrotask","Number","isInteger","POSITIVE_INFINITY","TypeError","recommended","calendar","description","t","icon","imagePath","contacts","mail","spreed","richdocuments","name","notes","richdocumentscode","hidden","recommendedIds","keys","components","NcCheckboxRadioSwitch","NcButton","data","showInstallButton","installingApps","loadingApps","loadingAppsError","apps","defaultPageUrl","loadState","computed","recommendedApps","filter","app","includes","isAnyAppSelected","some","isSelected","mounted","axios","generateUrl","logger","info","map","assign","loading","installationError","isCompatible","debug","error","methods","installApps","limit","installing","active","canInstall","post","appIds","groups","catch","all","window","location","customIcon","appId","warn","customName","customDescription","isHidden","toggleSelect","index","findIndex","$set","options","styleTagTransform","setAttributes","insert","domAPI","insertStyleElement","locals","_vm","_c","_self","staticClass","_v","_s","_e","_l","key","attrs","domProps","on","$event","stopPropagation","preventDefault","apply","__webpack_nonce__","getCSPNonce","Vue","mixin","extend","RecommendedApps","$mount","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","exports","loaded","__webpack_modules__","call","m","O","chunkIds","fn","priority","notFulfilled","Infinity","i","fulfilled","j","every","splice","r","n","getter","__esModule","d","a","definition","o","defineProperty","enumerable","e","g","globalThis","Function","obj","prop","prototype","hasOwnProperty","toStringTag","nmd","paths","children","b","document","baseURI","self","href","installedChunks","chunkId","webpackJsonpCallback","parentChunkLoadingFunction","moreModules","runtime","chunkLoadingGlobal","forEach","nc","__webpack_exports__"],"sourceRoot":""}
\ No newline at end of file +{"version":3,"file":"core-recommendedapps.js?v=22a85edc85db40d68272","mappings":"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","sources":["webpack:///nextcloud/webpack/runtime/chunk loaded","webpack:///nextcloud/core/src/logger.js","webpack://nextcloud/./core/src/components/setup/RecommendedApps.vue?5f06","webpack:///nextcloud/node_modules/yocto-queue/index.js","webpack:///nextcloud/node_modules/p-limit/index.js","webpack:///nextcloud/core/src/components/setup/RecommendedApps.vue","webpack:///nextcloud/core/src/components/setup/RecommendedApps.vue?vue&type=script&lang=js","webpack://nextcloud/./core/src/components/setup/RecommendedApps.vue?304a","webpack://nextcloud/./core/src/components/setup/RecommendedApps.vue?84e8","webpack:///nextcloud/core/src/recommendedapps.js","webpack:///nextcloud/core/src/components/setup/RecommendedApps.vue?vue&type=style&index=0&id=5b5c8ecc&prod&lang=scss&scoped=true","webpack:///nextcloud/webpack/bootstrap","webpack:///nextcloud/webpack/runtime/compat get default export","webpack:///nextcloud/webpack/runtime/define property getters","webpack:///nextcloud/webpack/runtime/ensure chunk","webpack:///nextcloud/webpack/runtime/global","webpack:///nextcloud/webpack/runtime/hasOwnProperty shorthand","webpack:///nextcloud/webpack/runtime/make namespace object","webpack:///nextcloud/webpack/runtime/node module decorator","webpack:///nextcloud/webpack/runtime/runtimeId","webpack:///nextcloud/webpack/runtime/jsonp chunk loading","webpack:///nextcloud/webpack/runtime/nonce","webpack:///nextcloud/webpack/startup"],"sourcesContent":["var deferred = [];\n__webpack_require__.O = (result, chunkIds, fn, priority) => {\n\tif(chunkIds) {\n\t\tpriority = priority || 0;\n\t\tfor(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];\n\t\tdeferred[i] = [chunkIds, fn, priority];\n\t\treturn;\n\t}\n\tvar notFulfilled = Infinity;\n\tfor (var i = 0; i < deferred.length; i++) {\n\t\tvar chunkIds = deferred[i][0];\n\t\tvar fn = deferred[i][1];\n\t\tvar priority = deferred[i][2];\n\t\tvar fulfilled = true;\n\t\tfor (var j = 0; j < chunkIds.length; j++) {\n\t\t\tif ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))) {\n\t\t\t\tchunkIds.splice(j--, 1);\n\t\t\t} else {\n\t\t\t\tfulfilled = false;\n\t\t\t\tif(priority < notFulfilled) notFulfilled = priority;\n\t\t\t}\n\t\t}\n\t\tif(fulfilled) {\n\t\t\tdeferred.splice(i--, 1)\n\t\t\tvar r = fn();\n\t\t\tif (r !== undefined) result = r;\n\t\t}\n\t}\n\treturn result;\n};","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { getCurrentUser } from '@nextcloud/auth'\nimport { getLoggerBuilder } from '@nextcloud/logger'\n\nconst getLogger = user => {\n\tif (user === null) {\n\t\treturn getLoggerBuilder()\n\t\t\t.setApp('core')\n\t\t\t.build()\n\t}\n\treturn getLoggerBuilder()\n\t\t.setApp('core')\n\t\t.setUid(user.uid)\n\t\t.build()\n}\n\nexport default getLogger(getCurrentUser())\n\nexport const unifiedSearchLogger = getLoggerBuilder()\n\t.setApp('unified-search')\n\t.detectUser()\n\t.build()\n","var render = function render(){var _vm=this,_c=_vm._self._c;return _c('div',{staticClass:\"guest-box\",attrs:{\"data-cy-setup-recommended-apps\":\"\"}},[_c('h2',[_vm._v(_vm._s(_vm.t('core', 'Recommended apps')))]),_vm._v(\" \"),(_vm.loadingApps)?_c('p',{staticClass:\"loading text-center\"},[_vm._v(\"\\n\\t\\t\"+_vm._s(_vm.t('core', 'Loading apps …'))+\"\\n\\t\")]):(_vm.loadingAppsError)?_c('p',{staticClass:\"loading-error text-center\"},[_vm._v(\"\\n\\t\\t\"+_vm._s(_vm.t('core', 'Could not fetch list of apps from the App Store.'))+\"\\n\\t\")]):_vm._e(),_vm._v(\" \"),_vm._l((_vm.recommendedApps),function(app){return _c('div',{key:app.id,staticClass:\"app\"},[(!_vm.isHidden(app.id))?[_c('img',{attrs:{\"src\":_vm.customIcon(app.id),\"alt\":\"\"}}),_vm._v(\" \"),_c('div',{staticClass:\"info\"},[_c('h3',[_vm._v(_vm._s(_vm.customName(app)))]),_vm._v(\" \"),_c('p',{domProps:{\"textContent\":_vm._s(_vm.customDescription(app.id))}}),_vm._v(\" \"),(app.installationError)?_c('p',[_c('strong',[_vm._v(_vm._s(_vm.t('core', 'App download or installation failed')))])]):(!app.isCompatible)?_c('p',[_c('strong',[_vm._v(_vm._s(_vm.t('core', 'Cannot install this app because it is not compatible')))])]):(!app.canInstall)?_c('p',[_c('strong',[_vm._v(_vm._s(_vm.t('core', 'Cannot install this app')))])]):_vm._e()]),_vm._v(\" \"),_c('NcCheckboxRadioSwitch',{attrs:{\"checked\":app.isSelected || app.active,\"disabled\":!app.isCompatible || app.active,\"loading\":app.loading},on:{\"update:checked\":function($event){return _vm.toggleSelect(app.id)}}})]:_vm._e()],2)}),_vm._v(\" \"),_c('div',{staticClass:\"dialog-row\"},[(_vm.showInstallButton && !_vm.installingApps)?_c('NcButton',{attrs:{\"type\":\"tertiary\",\"role\":\"link\",\"href\":_vm.defaultPageUrl,\"data-cy-setup-recommended-apps-skip\":\"\"}},[_vm._v(\"\\n\\t\\t\\t\"+_vm._s(_vm.t('core', 'Skip'))+\"\\n\\t\\t\")]):_vm._e(),_vm._v(\" \"),(_vm.showInstallButton)?_c('NcButton',{attrs:{\"type\":\"primary\",\"disabled\":_vm.installingApps || !_vm.isAnyAppSelected,\"data-cy-setup-recommended-apps-install\":\"\"}},[_vm._v(\"\\n\\t\\t\\t@click.stop.prevent=\\\"installApps\\\">\\n\\t\\t\\t\"+_vm._s(_vm.installingApps ? _vm.t('core', 'Installing apps …') : _vm.t('core', 'Install recommended apps'))+\"\\n\\t\\t\")]):_vm._e()],1)],2)\n}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","/*\nHow it works:\n`this.#head` is an instance of `Node` which keeps track of its current value and nests another instance of `Node` that keeps the value that comes after it. When a value is provided to `.enqueue()`, the code needs to iterate through `this.#head`, going deeper and deeper to find the last value. However, iterating through every single item is slow. This problem is solved by saving a reference to the last value as `this.#tail` so that it can reference it to add a new value.\n*/\n\nclass Node {\n\tvalue;\n\tnext;\n\n\tconstructor(value) {\n\t\tthis.value = value;\n\t}\n}\n\nexport default class Queue {\n\t#head;\n\t#tail;\n\t#size;\n\n\tconstructor() {\n\t\tthis.clear();\n\t}\n\n\tenqueue(value) {\n\t\tconst node = new Node(value);\n\n\t\tif (this.#head) {\n\t\t\tthis.#tail.next = node;\n\t\t\tthis.#tail = node;\n\t\t} else {\n\t\t\tthis.#head = node;\n\t\t\tthis.#tail = node;\n\t\t}\n\n\t\tthis.#size++;\n\t}\n\n\tdequeue() {\n\t\tconst current = this.#head;\n\t\tif (!current) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#head = this.#head.next;\n\t\tthis.#size--;\n\t\treturn current.value;\n\t}\n\n\tpeek() {\n\t\tif (!this.#head) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn this.#head.value;\n\n\t\t// TODO: Node.js 18.\n\t\t// return this.#head?.value;\n\t}\n\n\tclear() {\n\t\tthis.#head = undefined;\n\t\tthis.#tail = undefined;\n\t\tthis.#size = 0;\n\t}\n\n\tget size() {\n\t\treturn this.#size;\n\t}\n\n\t* [Symbol.iterator]() {\n\t\tlet current = this.#head;\n\n\t\twhile (current) {\n\t\t\tyield current.value;\n\t\t\tcurrent = current.next;\n\t\t}\n\t}\n}\n","import Queue from 'yocto-queue';\n\nexport default function pLimit(concurrency) {\n\tvalidateConcurrency(concurrency);\n\n\tconst queue = new Queue();\n\tlet activeCount = 0;\n\n\tconst resumeNext = () => {\n\t\tif (activeCount < concurrency && queue.size > 0) {\n\t\t\tqueue.dequeue()();\n\t\t\t// Since `pendingCount` has been decreased by one, increase `activeCount` by one.\n\t\t\tactiveCount++;\n\t\t}\n\t};\n\n\tconst next = () => {\n\t\tactiveCount--;\n\n\t\tresumeNext();\n\t};\n\n\tconst run = async (function_, resolve, arguments_) => {\n\t\tconst result = (async () => function_(...arguments_))();\n\n\t\tresolve(result);\n\n\t\ttry {\n\t\t\tawait result;\n\t\t} catch {}\n\n\t\tnext();\n\t};\n\n\tconst enqueue = (function_, resolve, arguments_) => {\n\t\t// Queue `internalResolve` instead of the `run` function\n\t\t// to preserve asynchronous context.\n\t\tnew Promise(internalResolve => {\n\t\t\tqueue.enqueue(internalResolve);\n\t\t}).then(\n\t\t\trun.bind(undefined, function_, resolve, arguments_),\n\t\t);\n\n\t\t(async () => {\n\t\t\t// This function needs to wait until the next microtask before comparing\n\t\t\t// `activeCount` to `concurrency`, because `activeCount` is updated asynchronously\n\t\t\t// after the `internalResolve` function is dequeued and called. The comparison in the if-statement\n\t\t\t// needs to happen asynchronously as well to get an up-to-date value for `activeCount`.\n\t\t\tawait Promise.resolve();\n\n\t\t\tif (activeCount < concurrency) {\n\t\t\t\tresumeNext();\n\t\t\t}\n\t\t})();\n\t};\n\n\tconst generator = (function_, ...arguments_) => new Promise(resolve => {\n\t\tenqueue(function_, resolve, arguments_);\n\t});\n\n\tObject.defineProperties(generator, {\n\t\tactiveCount: {\n\t\t\tget: () => activeCount,\n\t\t},\n\t\tpendingCount: {\n\t\t\tget: () => queue.size,\n\t\t},\n\t\tclearQueue: {\n\t\t\tvalue() {\n\t\t\t\tqueue.clear();\n\t\t\t},\n\t\t},\n\t\tconcurrency: {\n\t\t\tget: () => concurrency,\n\n\t\t\tset(newConcurrency) {\n\t\t\t\tvalidateConcurrency(newConcurrency);\n\t\t\t\tconcurrency = newConcurrency;\n\n\t\t\t\tqueueMicrotask(() => {\n\t\t\t\t\t// eslint-disable-next-line no-unmodified-loop-condition\n\t\t\t\t\twhile (activeCount < concurrency && queue.size > 0) {\n\t\t\t\t\t\tresumeNext();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t},\n\t\t},\n\t});\n\n\treturn generator;\n}\n\nexport function limitFunction(function_, option) {\n\tconst {concurrency} = option;\n\tconst limit = pLimit(concurrency);\n\n\treturn (...arguments_) => limit(() => function_(...arguments_));\n}\n\nfunction validateConcurrency(concurrency) {\n\tif (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) {\n\t\tthrow new TypeError('Expected `concurrency` to be a number from 1 and up');\n\t}\n}\n","<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<template>\n\t<div class=\"guest-box\" data-cy-setup-recommended-apps>\n\t\t<h2>{{ t('core', 'Recommended apps') }}</h2>\n\t\t<p v-if=\"loadingApps\" class=\"loading text-center\">\n\t\t\t{{ t('core', 'Loading apps …') }}\n\t\t</p>\n\t\t<p v-else-if=\"loadingAppsError\" class=\"loading-error text-center\">\n\t\t\t{{ t('core', 'Could not fetch list of apps from the App Store.') }}\n\t\t</p>\n\n\t\t<div v-for=\"app in recommendedApps\" :key=\"app.id\" class=\"app\">\n\t\t\t<template v-if=\"!isHidden(app.id)\">\n\t\t\t\t<img :src=\"customIcon(app.id)\" alt=\"\">\n\t\t\t\t<div class=\"info\">\n\t\t\t\t\t<h3>{{ customName(app) }}</h3>\n\t\t\t\t\t<p v-text=\"customDescription(app.id)\" />\n\t\t\t\t\t<p v-if=\"app.installationError\">\n\t\t\t\t\t\t<strong>{{ t('core', 'App download or installation failed') }}</strong>\n\t\t\t\t\t</p>\n\t\t\t\t\t<p v-else-if=\"!app.isCompatible\">\n\t\t\t\t\t\t<strong>{{ t('core', 'Cannot install this app because it is not compatible') }}</strong>\n\t\t\t\t\t</p>\n\t\t\t\t\t<p v-else-if=\"!app.canInstall\">\n\t\t\t\t\t\t<strong>{{ t('core', 'Cannot install this app') }}</strong>\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t\t<NcCheckboxRadioSwitch :checked=\"app.isSelected || app.active\"\n\t\t\t\t\t:disabled=\"!app.isCompatible || app.active\"\n\t\t\t\t\t:loading=\"app.loading\"\n\t\t\t\t\t@update:checked=\"toggleSelect(app.id)\" />\n\t\t\t</template>\n\t\t</div>\n\n\t\t<div class=\"dialog-row\">\n\t\t\t<NcButton v-if=\"showInstallButton && !installingApps\"\n\t\t\t\ttype=\"tertiary\"\n\t\t\t\trole=\"link\"\n\t\t\t\t:href=\"defaultPageUrl\"\n\t\t\t\tdata-cy-setup-recommended-apps-skip>\n\t\t\t\t{{ t('core', 'Skip') }}\n\t\t\t</NcButton>\n\n\t\t\t<NcButton v-if=\"showInstallButton\"\n\t\t\t\ttype=\"primary\"\n\t\t\t\t:disabled=\"installingApps || !isAnyAppSelected\"\n\t\t\t\tdata-cy-setup-recommended-apps-install>\n\t\t\t\t@click.stop.prevent=\"installApps\">\n\t\t\t\t{{ installingApps ? t('core', 'Installing apps …') : t('core', 'Install recommended apps') }}\n\t\t\t</NcButton>\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport { t } from '@nextcloud/l10n'\nimport { loadState } from '@nextcloud/initial-state'\nimport { generateUrl, imagePath } from '@nextcloud/router'\nimport axios from '@nextcloud/axios'\nimport pLimit from 'p-limit'\nimport logger from '../../logger.js'\n\nimport NcButton from '@nextcloud/vue/components/NcButton'\nimport NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'\n\nconst recommended = {\n\tcalendar: {\n\t\tdescription: t('core', 'Schedule work & meetings, synced with all your devices.'),\n\t\ticon: imagePath('core', 'places/calendar.svg'),\n\t},\n\tcontacts: {\n\t\tdescription: t('core', 'Keep your colleagues and friends in one place without leaking their private info.'),\n\t\ticon: imagePath('core', 'places/contacts.svg'),\n\t},\n\tmail: {\n\t\tdescription: t('core', 'Simple email app nicely integrated with Files, Contacts and Calendar.'),\n\t\ticon: imagePath('core', 'actions/mail.svg'),\n\t},\n\tspreed: {\n\t\tdescription: t('core', 'Chatting, video calls, screen sharing, online meetings and web conferencing – in your browser and with mobile apps.'),\n\t\ticon: imagePath('core', 'apps/spreed.svg'),\n\t},\n\trichdocuments: {\n\t\tname: 'Nextcloud Office',\n\t\tdescription: t('core', 'Collaborative documents, spreadsheets and presentations, built on Collabora Online.'),\n\t\ticon: imagePath('core', 'apps/richdocuments.svg'),\n\t},\n\tnotes: {\n\t\tdescription: t('core', 'Distraction free note taking app.'),\n\t\ticon: imagePath('core', 'apps/notes.svg'),\n\t},\n\trichdocumentscode: {\n\t\thidden: true,\n\t},\n}\nconst recommendedIds = Object.keys(recommended)\n\nexport default {\n\tname: 'RecommendedApps',\n\tcomponents: {\n\t\tNcCheckboxRadioSwitch,\n\t\tNcButton,\n\t},\n\tdata() {\n\t\treturn {\n\t\t\tshowInstallButton: false,\n\t\t\tinstallingApps: false,\n\t\t\tloadingApps: true,\n\t\t\tloadingAppsError: false,\n\t\t\tapps: [],\n\t\t\tdefaultPageUrl: loadState('core', 'defaultPageUrl'),\n\t\t}\n\t},\n\tcomputed: {\n\t\trecommendedApps() {\n\t\t\treturn this.apps.filter(app => recommendedIds.includes(app.id))\n\t\t},\n\t\tisAnyAppSelected() {\n\t\t\treturn this.recommendedApps.some(app => app.isSelected)\n\t\t},\n\t},\n\tasync mounted() {\n\t\ttry {\n\t\t\tconst { data } = await axios.get(generateUrl('settings/apps/list'))\n\t\t\tlogger.info(`${data.apps.length} apps fetched`)\n\n\t\t\tthis.apps = data.apps.map(app => Object.assign(app, { loading: false, installationError: false, isSelected: app.isCompatible }))\n\t\t\tlogger.debug(`${this.recommendedApps.length} recommended apps found`, { apps: this.recommendedApps })\n\n\t\t\tthis.showInstallButton = true\n\t\t} catch (error) {\n\t\t\tlogger.error('could not fetch app list', { error })\n\n\t\t\tthis.loadingAppsError = true\n\t\t} finally {\n\t\t\tthis.loadingApps = false\n\t\t}\n\t},\n\tmethods: {\n\t\tinstallApps() {\n\t\t\tthis.installingApps = true\n\n\t\t\tconst limit = pLimit(1)\n\t\t\tconst installing = this.recommendedApps\n\t\t\t\t.filter(app => !app.active && app.isCompatible && app.canInstall && app.isSelected)\n\t\t\t\t.map(app => limit(async () => {\n\t\t\t\t\tlogger.info(`installing ${app.id}`)\n\t\t\t\t\tapp.loading = true\n\t\t\t\t\treturn axios.post(generateUrl('settings/apps/enable'), { appIds: [app.id], groups: [] })\n\t\t\t\t\t\t.catch(error => {\n\t\t\t\t\t\t\tlogger.error(`could not install ${app.id}`, { error })\n\t\t\t\t\t\t\tapp.isSelected = false\n\t\t\t\t\t\t\tapp.installationError = true\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.then(() => {\n\t\t\t\t\t\t\tlogger.info(`installed ${app.id}`)\n\t\t\t\t\t\t\tapp.loading = false\n\t\t\t\t\t\t\tapp.active = true\n\t\t\t\t\t\t})\n\t\t\t\t}))\n\t\t\tlogger.debug(`installing ${installing.length} recommended apps`)\n\t\t\tPromise.all(installing)\n\t\t\t\t.then(() => {\n\t\t\t\t\tlogger.info('all recommended apps installed, redirecting …')\n\n\t\t\t\t\twindow.location = this.defaultPageUrl\n\t\t\t\t})\n\t\t\t\t.catch(error => logger.error('could not install recommended apps', { error }))\n\t\t},\n\t\tcustomIcon(appId) {\n\t\t\tif (!(appId in recommended) || !recommended[appId].icon) {\n\t\t\t\tlogger.warn(`no app icon for recommended app ${appId}`)\n\t\t\t\treturn imagePath('core', 'places/default-app-icon.svg')\n\t\t\t}\n\t\t\treturn recommended[appId].icon\n\t\t},\n\t\tcustomName(app) {\n\t\t\tif (!(app.id in recommended)) {\n\t\t\t\treturn app.name\n\t\t\t}\n\t\t\treturn recommended[app.id].name || app.name\n\t\t},\n\t\tcustomDescription(appId) {\n\t\t\tif (!(appId in recommended)) {\n\t\t\t\tlogger.warn(`no app description for recommended app ${appId}`)\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn recommended[appId].description\n\t\t},\n\t\tisHidden(appId) {\n\t\t\tif (!(appId in recommended)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn !!recommended[appId].hidden\n\t\t},\n\t\ttoggleSelect(appId) {\n\t\t\t// disable toggle when installButton is disabled\n\t\t\tif (!(appId in recommended) || !this.showInstallButton) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst index = this.apps.findIndex(app => app.id === appId)\n\t\t\tthis.$set(this.apps[index], 'isSelected', !this.apps[index].isSelected)\n\t\t},\n\t},\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.dialog-row {\n\tdisplay: flex;\n\tjustify-content: end;\n\tmargin-top: 8px;\n}\n\np {\n\t&.loading,\n\t&.loading-error {\n\t\theight: 100px;\n\t}\n\n\t&:last-child {\n\t\tmargin-top: 10px;\n\t}\n}\n\n.text-center {\n\ttext-align: center;\n}\n\n.app {\n\tdisplay: flex;\n\tflex-direction: row;\n\n\timg {\n\t\theight: 50px;\n\t\twidth: 50px;\n\t\tfilter: var(--background-invert-if-dark);\n\t}\n\n\timg, .info {\n\t\tpadding: 12px;\n\t}\n\n\t.info {\n\t\th3, p {\n\t\t\ttext-align: start;\n\t\t}\n\n\t\th3 {\n\t\t\tmargin-top: 0;\n\t\t}\n\t}\n\n\t.checkbox-radio-switch {\n\t\tmargin-inline-start: auto;\n\t\tpadding: 0 2px;\n\t}\n}\n</style>\n","import mod from \"-!../../../../node_modules/babel-loader/lib/index.js!../../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./RecommendedApps.vue?vue&type=script&lang=js\"; export default mod; export * from \"-!../../../../node_modules/babel-loader/lib/index.js!../../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./RecommendedApps.vue?vue&type=script&lang=js\"","\n import API from \"!../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../../../node_modules/css-loader/dist/cjs.js!../../../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../../../node_modules/sass-loader/dist/cjs.js!../../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./RecommendedApps.vue?vue&type=style&index=0&id=5b5c8ecc&prod&lang=scss&scoped=true\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\noptions.insert = insertFn.bind(null, \"head\");\noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../../../node_modules/css-loader/dist/cjs.js!../../../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../../../node_modules/sass-loader/dist/cjs.js!../../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./RecommendedApps.vue?vue&type=style&index=0&id=5b5c8ecc&prod&lang=scss&scoped=true\";\n export default content && content.locals ? content.locals : undefined;\n","import { render, staticRenderFns } from \"./RecommendedApps.vue?vue&type=template&id=5b5c8ecc&scoped=true\"\nimport script from \"./RecommendedApps.vue?vue&type=script&lang=js\"\nexport * from \"./RecommendedApps.vue?vue&type=script&lang=js\"\nimport style0 from \"./RecommendedApps.vue?vue&type=style&index=0&id=5b5c8ecc&prod&lang=scss&scoped=true\"\n\n\n/* normalize component */\nimport normalizer from \"!../../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n \"5b5c8ecc\",\n null\n \n)\n\nexport default component.exports","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { getCSPNonce } from '@nextcloud/auth'\nimport { translate as t } from '@nextcloud/l10n'\nimport Vue from 'vue'\n\nimport logger from './logger.js'\nimport RecommendedApps from './components/setup/RecommendedApps.vue'\n\n// eslint-disable-next-line camelcase\n__webpack_nonce__ = getCSPNonce()\n\nVue.mixin({\n\tmethods: {\n\t\tt,\n\t},\n})\n\nconst View = Vue.extend(RecommendedApps)\nnew View().$mount('#recommended-apps')\n\nlogger.debug('recommended apps view rendered')\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `.dialog-row[data-v-5b5c8ecc]{display:flex;justify-content:end;margin-top:8px}p.loading[data-v-5b5c8ecc],p.loading-error[data-v-5b5c8ecc]{height:100px}p[data-v-5b5c8ecc]:last-child{margin-top:10px}.text-center[data-v-5b5c8ecc]{text-align:center}.app[data-v-5b5c8ecc]{display:flex;flex-direction:row}.app img[data-v-5b5c8ecc]{height:50px;width:50px;filter:var(--background-invert-if-dark)}.app img[data-v-5b5c8ecc],.app .info[data-v-5b5c8ecc]{padding:12px}.app .info h3[data-v-5b5c8ecc],.app .info p[data-v-5b5c8ecc]{text-align:start}.app .info h3[data-v-5b5c8ecc]{margin-top:0}.app .checkbox-radio-switch[data-v-5b5c8ecc]{margin-inline-start:auto;padding:0 2px}`, \"\",{\"version\":3,\"sources\":[\"webpack://./core/src/components/setup/RecommendedApps.vue\"],\"names\":[],\"mappings\":\"AACA,6BACC,YAAA,CACA,mBAAA,CACA,cAAA,CAIA,4DAEC,YAAA,CAGD,8BACC,eAAA,CAIF,8BACC,iBAAA,CAGD,sBACC,YAAA,CACA,kBAAA,CAEA,0BACC,WAAA,CACA,UAAA,CACA,uCAAA,CAGD,sDACC,YAAA,CAIA,6DACC,gBAAA,CAGD,+BACC,YAAA,CAIF,6CACC,wBAAA,CACA,aAAA\",\"sourcesContent\":[\"\\n.dialog-row {\\n\\tdisplay: flex;\\n\\tjustify-content: end;\\n\\tmargin-top: 8px;\\n}\\n\\np {\\n\\t&.loading,\\n\\t&.loading-error {\\n\\t\\theight: 100px;\\n\\t}\\n\\n\\t&:last-child {\\n\\t\\tmargin-top: 10px;\\n\\t}\\n}\\n\\n.text-center {\\n\\ttext-align: center;\\n}\\n\\n.app {\\n\\tdisplay: flex;\\n\\tflex-direction: row;\\n\\n\\timg {\\n\\t\\theight: 50px;\\n\\t\\twidth: 50px;\\n\\t\\tfilter: var(--background-invert-if-dark);\\n\\t}\\n\\n\\timg, .info {\\n\\t\\tpadding: 12px;\\n\\t}\\n\\n\\t.info {\\n\\t\\th3, p {\\n\\t\\t\\ttext-align: start;\\n\\t\\t}\\n\\n\\t\\th3 {\\n\\t\\t\\tmargin-top: 0;\\n\\t\\t}\\n\\t}\\n\\n\\t.checkbox-radio-switch {\\n\\t\\tmargin-inline-start: auto;\\n\\t\\tpadding: 0 2px;\\n\\t}\\n}\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\tid: moduleId,\n\t\tloaded: false,\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Flag the module as loaded\n\tmodule.loaded = true;\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n// expose the modules object (__webpack_modules__)\n__webpack_require__.m = __webpack_modules__;\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","// The chunk loading function for additional chunks\n// Since all referenced chunks are already included\n// in this file, this function is empty here.\n__webpack_require__.e = () => (Promise.resolve());","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","__webpack_require__.nmd = (module) => {\n\tmodule.paths = [];\n\tif (!module.children) module.children = [];\n\treturn module;\n};","__webpack_require__.j = 2696;","__webpack_require__.b = document.baseURI || self.location.href;\n\n// object to store loaded and loading chunks\n// undefined = chunk not loaded, null = chunk preloaded/prefetched\n// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded\nvar installedChunks = {\n\t2696: 0\n};\n\n// no chunk on demand loading\n\n// no prefetching\n\n// no preloaded\n\n// no HMR\n\n// no HMR manifest\n\n__webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);\n\n// install a JSONP callback for chunk loading\nvar webpackJsonpCallback = (parentChunkLoadingFunction, data) => {\n\tvar chunkIds = data[0];\n\tvar moreModules = data[1];\n\tvar runtime = data[2];\n\t// add \"moreModules\" to the modules object,\n\t// then flag all \"chunkIds\" as loaded and fire callback\n\tvar moduleId, chunkId, i = 0;\n\tif(chunkIds.some((id) => (installedChunks[id] !== 0))) {\n\t\tfor(moduleId in moreModules) {\n\t\t\tif(__webpack_require__.o(moreModules, moduleId)) {\n\t\t\t\t__webpack_require__.m[moduleId] = moreModules[moduleId];\n\t\t\t}\n\t\t}\n\t\tif(runtime) var result = runtime(__webpack_require__);\n\t}\n\tif(parentChunkLoadingFunction) parentChunkLoadingFunction(data);\n\tfor(;i < chunkIds.length; i++) {\n\t\tchunkId = chunkIds[i];\n\t\tif(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {\n\t\t\tinstalledChunks[chunkId][0]();\n\t\t}\n\t\tinstalledChunks[chunkId] = 0;\n\t}\n\treturn __webpack_require__.O(result);\n}\n\nvar chunkLoadingGlobal = self[\"webpackChunknextcloud\"] = self[\"webpackChunknextcloud\"] || [];\nchunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));\nchunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));","__webpack_require__.nc = undefined;","// startup\n// Load entry module and return exports\n// This entry module depends on other loaded chunks and execution need to be delayed\nvar __webpack_exports__ = __webpack_require__.O(undefined, [4208], () => (__webpack_require__(10440)))\n__webpack_exports__ = __webpack_require__.O(__webpack_exports__);\n"],"names":["deferred","user","getCurrentUser","getLoggerBuilder","setApp","build","setUid","uid","detectUser","Node","constructor","value","_defineProperty","this","_head","WeakMap","_tail","_size","Queue","_classPrivateFieldInitSpec","clear","enqueue","_this$size","node","_classPrivateFieldGet","next","_classPrivateFieldSet","dequeue","_this$size3","current","peek","undefined","size","Symbol","iterator","pLimit","concurrency","validateConcurrency","queue","activeCount","resumeNext","run","async","function_","resolve","arguments_","result","generator","_len","arguments","length","Array","_key","Promise","internalResolve","then","bind","Object","defineProperties","get","pendingCount","clearQueue","set","newConcurrency","queueMicrotask","Number","isInteger","POSITIVE_INFINITY","TypeError","recommended","calendar","description","t","icon","imagePath","contacts","mail","spreed","richdocuments","name","notes","richdocumentscode","hidden","recommendedIds","keys","components","NcCheckboxRadioSwitch","NcButton","data","showInstallButton","installingApps","loadingApps","loadingAppsError","apps","defaultPageUrl","loadState","computed","recommendedApps","filter","app","includes","id","isAnyAppSelected","some","isSelected","mounted","axios","generateUrl","logger","info","map","assign","loading","installationError","isCompatible","debug","error","methods","installApps","limit","installing","active","canInstall","post","appIds","groups","catch","all","window","location","customIcon","appId","warn","customName","customDescription","isHidden","toggleSelect","index","findIndex","$set","options","styleTagTransform","setAttributes","insert","domAPI","insertStyleElement","locals","_vm","_c","_self","staticClass","attrs","_v","_s","_e","_l","key","domProps","on","$event","__webpack_nonce__","getCSPNonce","Vue","mixin","extend","RecommendedApps","$mount","___CSS_LOADER_EXPORT___","push","module","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","exports","loaded","__webpack_modules__","call","m","O","chunkIds","fn","priority","notFulfilled","Infinity","i","fulfilled","j","every","splice","r","n","getter","__esModule","d","a","definition","o","defineProperty","enumerable","e","g","globalThis","Function","obj","prop","prototype","hasOwnProperty","toStringTag","nmd","paths","children","b","document","baseURI","self","href","installedChunks","chunkId","webpackJsonpCallback","parentChunkLoadingFunction","moreModules","runtime","chunkLoadingGlobal","forEach","nc","__webpack_exports__"],"sourceRoot":""}
\ No newline at end of file diff --git a/lib/l10n/de_DE.js b/lib/l10n/de_DE.js index 8b00460854c..aa926c96d4f 100644 --- a/lib/l10n/de_DE.js +++ b/lib/l10n/de_DE.js @@ -273,7 +273,7 @@ OC.L10N.register( "A valid Login must be provided" : "Ein gültiger Anmeldename muss angegeben werden.", "Login contains whitespace at the beginning or at the end" : "Anmeldename enthält Leerzeichen am Anfang oder am Ende", "Login must not consist of dots only" : "Der Anmeldename darf nicht nur aus Punkten bestehen", - "Login is too long" : "Die Anmeldung dauert zu lange", + "Login is too long" : "Der Kontenname ist zu lang", "Login is invalid because files already exist for this user" : "Der Anmeldename ist ungültig, da bereits Dateien von diesem Benutzer existieren", "Account disabled" : "Konto deaktiviert", "Login canceled by app" : "Anmeldung durch die App abgebrochen", diff --git a/lib/l10n/de_DE.json b/lib/l10n/de_DE.json index 602206cda8d..f23493df570 100644 --- a/lib/l10n/de_DE.json +++ b/lib/l10n/de_DE.json @@ -271,7 +271,7 @@ "A valid Login must be provided" : "Ein gültiger Anmeldename muss angegeben werden.", "Login contains whitespace at the beginning or at the end" : "Anmeldename enthält Leerzeichen am Anfang oder am Ende", "Login must not consist of dots only" : "Der Anmeldename darf nicht nur aus Punkten bestehen", - "Login is too long" : "Die Anmeldung dauert zu lange", + "Login is too long" : "Der Kontenname ist zu lang", "Login is invalid because files already exist for this user" : "Der Anmeldename ist ungültig, da bereits Dateien von diesem Benutzer existieren", "Account disabled" : "Konto deaktiviert", "Login canceled by app" : "Anmeldung durch die App abgebrochen", diff --git a/lib/l10n/et_EE.js b/lib/l10n/et_EE.js index e14744dc6ee..7932c79256b 100644 --- a/lib/l10n/et_EE.js +++ b/lib/l10n/et_EE.js @@ -293,6 +293,7 @@ OC.L10N.register( "The audio to transcribe" : "Üleskirjutatav helifail", "Transcription" : "Üleskirjutus", "The transcribed text" : "Üleskirjutatud tekst", + "Confirmation" : "Kinnitus", "Context write" : "Kontekstuaalne kirjutamine", "Writes text in a given style based on the provided source material." : "Kirjutab etteantud lähtematerjali lausel teksti üles.", "Writing style" : "Kirjutamisstiil", diff --git a/lib/l10n/et_EE.json b/lib/l10n/et_EE.json index f6c46ab05cb..99c9583bf87 100644 --- a/lib/l10n/et_EE.json +++ b/lib/l10n/et_EE.json @@ -291,6 +291,7 @@ "The audio to transcribe" : "Üleskirjutatav helifail", "Transcription" : "Üleskirjutus", "The transcribed text" : "Üleskirjutatud tekst", + "Confirmation" : "Kinnitus", "Context write" : "Kontekstuaalne kirjutamine", "Writes text in a given style based on the provided source material." : "Kirjutab etteantud lähtematerjali lausel teksti üles.", "Writing style" : "Kirjutamisstiil", diff --git a/lib/private/Files/Storage/Wrapper/Encryption.php b/lib/private/Files/Storage/Wrapper/Encryption.php index 0de009f0894..bdaba57687a 100644 --- a/lib/private/Files/Storage/Wrapper/Encryption.php +++ b/lib/private/Files/Storage/Wrapper/Encryption.php @@ -905,4 +905,16 @@ class Encryption extends Wrapper { public function setEnabled(bool $enabled): void { $this->enabled = $enabled; } + + /** + * Check if the on-disk data for a file has a valid encrypted header + * + * @param string $path + * @return bool + */ + public function hasValidHeader(string $path): bool { + $firstBlock = $this->readFirstBlock($path); + $header = $this->util->parseRawHeader($firstBlock); + return (count($header) > 0); + } } diff --git a/lib/private/Files/Storage/Wrapper/Quota.php b/lib/private/Files/Storage/Wrapper/Quota.php index 3be77ba1b37..35a265f8c8e 100644 --- a/lib/private/Files/Storage/Wrapper/Quota.php +++ b/lib/private/Files/Storage/Wrapper/Quota.php @@ -21,6 +21,7 @@ class Quota extends Wrapper { protected string $sizeRoot; private SystemConfig $config; private bool $quotaIncludeExternalStorage; + private bool $enabled = true; /** * @param array $parameters @@ -46,6 +47,9 @@ class Quota extends Wrapper { } private function hasQuota(): bool { + if (!$this->enabled) { + return false; + } return $this->getQuota() !== FileInfo::SPACE_UNLIMITED; } @@ -197,4 +201,8 @@ class Quota extends Wrapper { return parent::touch($path, $mtime); } + + public function enableQuota(bool $enabled): void { + $this->enabled = $enabled; + } } diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php index f17ced1611b..e49043355e8 100644 --- a/lib/private/Files/View.php +++ b/lib/private/Files/View.php @@ -10,6 +10,7 @@ namespace OC\Files; use Icewind\Streams\CallbackWrapper; use OC\Files\Mount\MoveableMount; use OC\Files\Storage\Storage; +use OC\Files\Storage\Wrapper\Quota; use OC\Share\Share; use OC\User\LazyUser; use OC\User\Manager as UserManager; @@ -1578,12 +1579,22 @@ class View { // Create parent folders if the mountpoint is inside a subfolder that doesn't exist yet if (!isset($files[$entryName])) { try { + [$storage, ] = $this->resolvePath($path . '/' . $entryName); + // make sure we can create the mountpoint folder, even if the user has a quota of 0 + if ($storage->instanceOfStorage(Quota::class)) { + $storage->enableQuota(false); + } + if ($this->mkdir($path . '/' . $entryName) !== false) { $info = $this->getFileInfo($path . '/' . $entryName); if ($info !== false) { $files[$entryName] = $info; } } + + if ($storage->instanceOfStorage(Quota::class)) { + $storage->enableQuota(true); + } } catch (\Exception $e) { // Creating the parent folder might not be possible, for example due to a lack of permissions. $this->logger->debug('Failed to create non-existent parent', ['exception' => $e, 'path' => $path . '/' . $entryName]); |