diff options
author | skjnldsv <skjnldsv@protonmail.com> | 2025-03-13 08:55:37 +0100 |
---|---|---|
committer | skjnldsv <skjnldsv@protonmail.com> | 2025-03-13 15:44:37 +0100 |
commit | 4d0680b605d756f9ae0b14dce2db82155f2c17a5 (patch) | |
tree | 56c7e18401825b7b79f7b075b937e4f13cffd812 | |
parent | 9dea6185ada1f9f891f2c64d256551c6ad171d29 (diff) | |
download | nextcloud-server-feat/setup.tar.gz nextcloud-server-feat/setup.zip |
feat(core): migrate setup to vuefeat/setup
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
-rw-r--r-- | core/Controller/SetupController.php | 18 | ||||
-rw-r--r-- | core/src/install.js | 156 | ||||
-rw-r--r-- | core/src/install.ts | 49 | ||||
-rw-r--r-- | core/src/views/Setup.vue | 421 | ||||
-rw-r--r-- | core/templates/installation.php | 165 | ||||
-rw-r--r-- | webpack.modules.js | 2 |
6 files changed, 489 insertions, 322 deletions
diff --git a/core/Controller/SetupController.php b/core/Controller/SetupController.php index 4b5902fdd3c..8474f6edf87 100644 --- a/core/Controller/SetupController.php +++ b/core/Controller/SetupController.php @@ -8,6 +8,8 @@ namespace OC\Core\Controller; use OC\Setup; +use OCP\IInitialStateService; +use OCP\IURLGenerator; use OCP\Template\ITemplateManager; use OCP\Util; use Psr\Log\LoggerInterface; @@ -19,6 +21,8 @@ class SetupController { protected Setup $setupHelper, protected LoggerInterface $logger, protected ITemplateManager $templateManager, + protected IInitialStateService $initialStateService, + protected IURLGenerator $urlGenerator, ) { $this->autoConfigFile = \OC::$configDir . 'autoconfig.php'; } @@ -72,6 +76,8 @@ class SetupController { 'dbtablespace' => '', 'dbhost' => 'localhost', 'dbtype' => '', + 'hasAutoconfig' => false, + 'serverRoot' => \OC::$SERVERROOT, ]; $parameters = array_merge($defaults, $post); @@ -80,9 +86,18 @@ class SetupController { // include common nextcloud webpack bundle Util::addScript('core', 'common'); Util::addScript('core', 'main'); + Util::addScript('core', 'install'); Util::addTranslations('core'); - $this->templateManager->printGuestPage('', 'installation', $parameters); + $this->initialStateService->provideInitialState('core', 'config', $parameters); + $this->initialStateService->provideInitialState('core', 'data', false); + $this->initialStateService->provideInitialState('core', 'links', [ + 'adminInstall' => $this->urlGenerator->linkToDocs('admin-install'), + 'adminSourceInstall' => $this->urlGenerator->linkToDocs('admin-source_install'), + 'adminDBConfiguration' => $this->urlGenerator->linkToDocs('admin-db-configuration'), + ]); + + $this->templateManager->printGuestPage('', 'installation'); } private function finishSetup(): void { @@ -107,6 +122,7 @@ class SetupController { $this->logger->info('Autoconfig file found, setting up Nextcloud…'); $AUTOCONFIG = []; include $this->autoConfigFile; + $post['hasAutoconfig'] = count($AUTOCONFIG) > 0; $post = array_merge($post, $AUTOCONFIG); } diff --git a/core/src/install.js b/core/src/install.js deleted file mode 100644 index ea2e2996a2a..00000000000 --- a/core/src/install.js +++ /dev/null @@ -1,156 +0,0 @@ -/** - * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -import $ from 'jquery' -import { translate as t } from '@nextcloud/l10n' -import { linkTo } from '@nextcloud/router' - -import { getToken } from './OC/requesttoken.js' -import getURLParameter from './Util/get-url-parameter.js' - -import './jquery/showpassword.js' - -import 'jquery-ui/ui/widgets/button.js' -import 'jquery-ui/themes/base/theme.css' -import 'jquery-ui/themes/base/button.css' - -import 'strengthify' -import 'strengthify/strengthify.css' - -window.addEventListener('DOMContentLoaded', function() { - const dbtypes = { - sqlite: !!$('#hasSQLite').val(), - mysql: !!$('#hasMySQL').val(), - postgresql: !!$('#hasPostgreSQL').val(), - oracle: !!$('#hasOracle').val(), - } - - $('#selectDbType').buttonset() - // change links inside an info box back to their default appearance - $('#selectDbType p.info a').button('destroy') - - if ($('#hasSQLite').val()) { - $('#use_other_db').hide() - $('#use_oracle_db').hide() - } else { - $('#sqliteInformation').hide() - } - $('#adminlogin').change(function() { - $('#adminlogin').val($.trim($('#adminlogin').val())) - }) - $('#sqlite').click(function() { - $('#use_other_db').slideUp(250) - $('#use_oracle_db').slideUp(250) - $('#sqliteInformation').show() - $('#dbname').attr('pattern', '[0-9a-zA-Z$_-]+') - }) - - $('#mysql,#pgsql').click(function() { - $('#use_other_db').slideDown(250) - $('#use_oracle_db').slideUp(250) - $('#sqliteInformation').hide() - $('#dbname').attr('pattern', '[0-9a-zA-Z$_-]+') - }) - - $('#oci').click(function() { - $('#use_other_db').slideDown(250) - $('#use_oracle_db').show(250) - $('#sqliteInformation').hide() - $('#dbname').attr('pattern', '[0-9a-zA-Z$_-.]+') - }) - - $('#showAdvanced').click(function(e) { - e.preventDefault() - $('#datadirContent').slideToggle(250) - $('#databaseBackend').slideToggle(250) - $('#databaseField').slideToggle(250) - }) - $('form').submit(function() { - // Save form parameters - const post = $(this).serializeArray() - - // Show spinner while finishing setup - $('.float-spinner').show(250) - - // Disable inputs - $('input[type="submit"]').attr('disabled', 'disabled').val($('input[type="submit"]').data('finishing')) - $('input', this).addClass('ui-state-disabled').attr('disabled', 'disabled') - // only disable buttons if they are present - if ($('#selectDbType').find('.ui-button').length > 0) { - $('#selectDbType').buttonset('disable') - } - $('.strengthify-wrapper, .tipsy') - .css('filter', 'alpha(opacity=30)') - .css('opacity', 0.3) - - // Create the form - const form = $('<form>') - form.attr('action', $(this).attr('action')) - form.attr('method', 'POST') - - for (let i = 0; i < post.length; i++) { - const input = $('<input type="hidden">') - input.attr(post[i]) - form.append(input) - } - - // Add redirect_url - const redirectURL = getURLParameter('redirect_url') - if (redirectURL) { - const redirectURLInput = $('<input type="hidden">') - redirectURLInput.attr({ - name: 'redirect_url', - value: redirectURL, - }) - form.append(redirectURLInput) - } - - // Submit the form - form.appendTo(document.body) - form.submit() - return false - }) - - // Expand latest db settings if page was reloaded on error - const currentDbType = $('input[type="radio"]:checked').val() - - if (currentDbType === undefined) { - $('input[type="radio"]').first().click() - } - - if ( - currentDbType === 'sqlite' - || (dbtypes.sqlite && currentDbType === undefined) - ) { - $('#datadirContent').hide(250) - $('#databaseBackend').hide(250) - $('#databaseField').hide(250) - $('.float-spinner').hide(250) - } - - $('#adminpass').strengthify({ - zxcvbn: linkTo('core', 'vendor/zxcvbn/dist/zxcvbn.js'), - titles: [ - t('core', 'Very weak password'), - t('core', 'Weak password'), - t('core', 'So-so password'), - t('core', 'Good password'), - t('core', 'Strong password'), - ], - drawTitles: true, - nonce: btoa(getToken()), - }) - - $('#dbpass').showPassword().keyup() - $('.toggle-password').click(function(event) { - event.preventDefault() - const currentValue = $(this).parent().children('input').attr('type') - if (currentValue === 'password') { - $(this).parent().children('input').attr('type', 'text') - } else { - $(this).parent().children('input').attr('type', 'password') - } - }) -}) diff --git a/core/src/install.ts b/core/src/install.ts new file mode 100644 index 00000000000..61c3747d02a --- /dev/null +++ b/core/src/install.ts @@ -0,0 +1,49 @@ +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import Vue from 'vue' +import Setup from './views/Setup.vue' + +type Error = { + error: string + hint: string +} + +export type DbType = 'sqlite' | 'mysql' | 'pgsql' | 'oci' + +export type SetupConfig = { + adminlogin: string + adminpass: string + dbuser: string + dbpass: string + dbname: string + dbtablespace: string + dbhost: string + dbtype: DbType | '' + + hasSQLite: boolean + hasMySQL: boolean + hasPostgreSQL: boolean + hasOracle: boolean + databases: Record<DbType, string> + + dbIsSet: boolean + directory: string + directoryIsSet: boolean + hasAutoconfig: boolean + htaccessWorking: boolean + serverRoot: string + + errors: string[]|Error[] +} + +export type SetupLinks = { + adminInstall: string + adminSourceInstall: string + adminDBConfiguration: string +} + +const SetupVue = Vue.extend(Setup) +new SetupVue().$mount('#content') diff --git a/core/src/views/Setup.vue b/core/src/views/Setup.vue new file mode 100644 index 00000000000..c03fc81f99b --- /dev/null +++ b/core/src/views/Setup.vue @@ -0,0 +1,421 @@ +<!-- + - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later +--> +<template> + <form ref="form" + class="setup-form" + :class="{ 'setup-form--loading': loading }" + action="" + method="POST" + @submit="onSubmit"> + <!-- Autoconfig info --> + <NcNoteCard v-if="config.hasAutoconfig" + :heading="t('core', 'Autoconfig file detected')" + type="success"> + {{ t('core', 'The setup form below is pre-filled with the values from the config file.') }} + </NcNoteCard> + + <!-- Htaccess warning --> + <NcNoteCard v-if="config.htaccessWorking === false" + :heading="t('core', 'Security warning')" + type="warning"> + <p v-html="htaccessWarning" /> + </NcNoteCard> + + <!-- Various errors --> + <NcNoteCard v-for="(error, index) in errors" + :key="index" + :heading="error.heading" + type="error"> + {{ error.message }} + </NcNoteCard> + + <!-- Admin creation --> + <fieldset class="setup-form__administration"> + <legend>{{ t('core', 'Create administration account') }}</legend> + + <!-- Username --> + <NcTextField v-model="config.adminlogin" + :label="t('core', 'Administration account name')" + name="adminlogin" + required /> + + <!-- Password --> + <NcPasswordField v-model="config.adminpass" + :label="t('core', 'Administration account password')" + name="adminpass" + required /> + + <!-- Password entropy --> + <NcNoteCard v-show="config.adminpass !== ''" :type="passwordHelperType"> + {{ passwordHelperText }} + </NcNoteCard> + </fieldset> + + <!-- Autoconfig toggle --> + <details :open="!isValidAutoconfig"> + <summary>{{ t('core', 'Advanced settings') }}</summary> + + <!-- Data folder --> + <fieldset class="setup-form__data-folder"> + <legend>{{ t('core', 'Data folder') }}</legend> + <NcTextField v-model="config.directory" + :label="t('core', 'Data folder')" + :placeholder="config.serverRoot + '/data'" + required + autocomplete="off" + autocapitalize="none" + name="directory" + spellcheck="false" /> + </fieldset> + + <!-- Database --> + <fieldset class="setup-form__database"> + <legend>{{ t('core', 'Database configuration') }}</legend> + + <!-- Database type select --> + <fieldset class="setup-form__database-type"> + <legend>{{ t('core', 'Database type') }}</legend> + <p class="setup-form__database-type-select" v-if="Object.keys(config.databases).length > 1"> + <NcCheckboxRadioSwitch v-for="(name, db) in config.databases" + v-model="config.dbtype" + :key="db" + :button-variant="true" + :value="db" + name="dbtype" + button-variant-grouped="horizontal" + type="radio"> + {{ name }} + </NcCheckboxRadioSwitch> + </p> + + <NcNoteCard v-else type="warning"> + {{ t('core', 'Only {db} is available.', { db: Object.values(config.databases).at(0) }) }}<br> + {{ t('core', 'Install and activate additional PHP modules to choose other database types.') }}<br> + <a :href="links.adminSourceInstall" target="_blank" rel="noreferrer noopener"> + {{ t('core', 'For more details check out the documentation.') }} ↗ + </a> + </NcNoteCard> + + <NcNoteCard v-if="config.dbtype === 'sqlite'" + :heading="t('core', 'Performance warning')" + type="warning"> + {{ t('core', 'You chose SQLite as database.') }}<br> + {{ t('core', 'SQLite should only be used for minimal and development instances. For production we recommend a different database backend.') }}<br> + {{ t('core', 'If you use clients for file syncing, the use of SQLite is highly discouraged.') }} + </NcNoteCard> + </fieldset> + + <!-- Database configuration --> + <fieldset v-if="config.dbtype !== 'sqlite'"> + <NcTextField v-model="config.dbuser" + :label="t('core', 'Database user')" + autocapitalize="none" + autocomplete="off" + name="dbuser" + spellcheck="false" + required /> + + <NcPasswordField v-model="config.dbpass" + :label="t('core', 'Database password')" + autocapitalize="none" + autocomplete="off" + name="dbpass" + spellcheck="false" + required /> + + <NcTextField v-model="config.dbname" + :label="t('core', 'Database name')" + autocapitalize="none" + autocomplete="off" + name="dbname" + pattern="[0-9a-zA-Z\$_\-]+" + spellcheck="false" + required /> + + <NcTextField v-if="config.dbtype === 'oci'" + v-model="config.dbtablespace" + :label="t('core', 'Database tablespace')" + autocapitalize="none" + autocomplete="off" + name="dbtablespace" + spellcheck="false" /> + + <NcTextField v-model="config.dbhost" + :helper-text="t('core', 'Please specify the port number along with the host name (e.g., localhost:5432).')" + :label="t('core', 'Database host')" + :placeholder="t('core', 'localhost')" + autocapitalize="none" + autocomplete="off" + name="dbhost" + spellcheck="false" /> + </fieldset> + </fieldset> + </details> + + <!-- Submit --> + <NcButton + class="setup-form__button" + :class="{ 'setup-form__button--loading': loading }" + :disabled="loading" + :loading="loading" + :wide="true" + alignment="center-reverse" + native-type="submit" + type="primary"> + <template #icon> + <NcLoadingIcon v-if="loading" /> + <IconArrowRight v-else /> + </template> + {{ loading ? t('core', 'Installing …') : t('core', 'Install') }} + </NcButton> + + <!-- Help note --> + <NcNoteCard type="info"> + {{ t('core', 'Need help?') }} + <a target="_blank" rel="noreferrer noopener" :href="links.adminInstall">{{ t('core', 'See the documentation') }} ↗</a> + </NcNoteCard> + </form> +</template> +<script lang="ts"> +import type { DbType, SetupConfig, SetupLinks } from '../install' + +import { defineComponent } from 'vue' +import { loadState } from '@nextcloud/initial-state' +import { t } from '@nextcloud/l10n' +import DomPurify from 'dompurify' + +import NcButton from '@nextcloud/vue/components/NcButton' +import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch' +import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon' +import NcNoteCard from '@nextcloud/vue/components/NcNoteCard' +import NcPasswordField from '@nextcloud/vue/components/NcPasswordField' +import NcTextField from '@nextcloud/vue/components/NcTextField' + +import IconArrowRight from 'vue-material-design-icons/ArrowRight.vue' + +const config = loadState<SetupConfig>('core', 'config') +const links = loadState<SetupLinks>('core', 'links') + +enum PasswordStrength { + VeryWeak, + Weak, + Moderate, + Strong, + VeryStrong, + ExtremelyStrong, +} + +export default defineComponent({ + name: 'Setup', + + components: { + IconArrowRight, + NcButton, + NcCheckboxRadioSwitch, + NcLoadingIcon, + NcNoteCard, + NcPasswordField, + NcTextField, + }, + + setup() { + return { + links, + t, + } + }, + + data() { + return { + config, + isValidAutoconfig: false, + loading: false, + } + }, + + computed: { + passwordHelperText(): string { + if (this.config.adminpass === '') { + return '' + } + + const passwordStrength = this.checkPasswordEntropy(this.config.adminpass) + switch (passwordStrength) { + case PasswordStrength.VeryWeak: + return t('core', 'Password is too weak') + case PasswordStrength.Weak: + return t('core', 'Password is weak') + case PasswordStrength.Moderate: + return t('core', 'Password is average') + case PasswordStrength.Strong: + return t('core', 'Password is strong') + case PasswordStrength.VeryStrong: + return t('core', 'Password is very strong') + case PasswordStrength.ExtremelyStrong: + return t('core', 'Password is extremely strong') + } + + return t('core', 'Unknown password strength') + }, + passwordHelperType() { + if (this.checkPasswordEntropy(this.config.adminpass) < PasswordStrength.Moderate) { + return 'error' + } + if (this.checkPasswordEntropy(this.config.adminpass) < PasswordStrength.Strong) { + return 'warning' + } + return 'success' + }, + + htaccessWarning(): string { + // We use v-html, let's make sure we're safe + const message = [ + t('core', 'Your data directory and files are probably accessible from the internet because the <code>.htaccess</code> file does not work.'), + t('core', 'For information how to properly configure your server, please {linkStart}see the documentation{linkEnd}', { + linkStart: '<a href="' + links.adminInstall + '" target="_blank" rel="noreferrer noopener">', + linkEnd: '</a>', + }, { escape: false }), + ].join('<br>') + return DomPurify.sanitize(message) + }, + + errors() { + return this.config.errors.map(error => { + if (typeof error === 'string') { + return { + heading: '', + message: error, + } + } + + // f no hint is set, we don't want to show a heading + if (error.hint === '') { + return { + heading: '', + message: error.error, + } + } + + return { + heading: error.error, + message: error.hint, + } + }) + }, + }, + + mounted() { + if (this.config.dbtype === '') { + this.config.dbtype = Object.keys(this.config.databases).at(0) as DbType + } + + // Validate the legitimacy of the autoconfig + if (this.config.hasAutoconfig) { + const form = this.$refs.form as HTMLFormElement + + // Check the form without the administration account fields + form.querySelectorAll('input[name="adminlogin"], input[name="adminpass"]').forEach(input => { + input.removeAttribute('required') + }) + + if (form.checkValidity() && this.config.errors.length === 0) { + this.isValidAutoconfig = true + } else { + this.isValidAutoconfig = false + } + + // Restore the required attribute + // Check the form without the administration account fields + form.querySelectorAll('input[name="adminlogin"], input[name="adminpass"]').forEach(input => { + input.setAttribute('required', 'true') + }) + } + }, + + methods: { + async onSubmit() { + this.loading = true + }, + + checkPasswordEntropy(password: string): PasswordStrength { + const uniqueCharacters = new Set(password) + const entropy = parseInt(Math.log2(Math.pow(parseInt(uniqueCharacters.size.toString()), password.length)).toFixed(2)) + if (entropy < 16) { + return PasswordStrength.VeryWeak + } else if (entropy < 31) { + return PasswordStrength.Weak + } else if (entropy < 46) { + return PasswordStrength.Moderate + } else if (entropy < 61) { + return PasswordStrength.Strong + } else if (entropy < 76) { + return PasswordStrength.VeryStrong + } + + return PasswordStrength.ExtremelyStrong + }, + }, +}) +</script> +<style lang="scss"> +form { + padding: calc(3 * var(--default-grid-baseline)); + color: var(--color-main-text); + border-radius: var(--border-radius-container); + background-color: var(--color-main-background-blur); + box-shadow: 0 0 10px var(--color-box-shadow); + -webkit-backdrop-filter: var(--filter-background-blur); + backdrop-filter: var(--filter-background-blur); + + max-width: 300px; + margin-bottom: 30px; + + > fieldset:first-child, + > .notecard:first-child { + margin-top: 0; + } + + > .notecard:last-child { + margin-bottom: 0; + } + + > fieldset, + > details { + margin-block: 1rem; + } + + .setup-form__button:not(.setup-form__button--loading) { + .material-design-icon { + transition: all linear var(--animation-quick); + } + + &:hover .material-design-icon { + transform: translateX(0.2em); + } + } + + // Db select required styling + .setup-form__database-type-select { + display: flex; + } + +} + +code { + background-color: var(--color-background-dark); + margin-top: 1rem; + padding: 0 0.3em; + border-radius: var(--border-radius); +} + +// Various overrides +.input-field { + margin-block-start: 1rem !important; +} + +.notecard__heading { + font-size: inherit !important; +} +</style> diff --git a/core/templates/installation.php b/core/templates/installation.php index 320fb9df7b7..b002ee400cc 100644 --- a/core/templates/installation.php +++ b/core/templates/installation.php @@ -4,168 +4,5 @@ * SPDX-FileCopyrightText: 2011-2016 ownCloud, Inc. * SPDX-License-Identifier: AGPL-3.0-only */ -script('core', 'install'); ?> -<input type='hidden' id='hasMySQL' value='<?php p($_['hasMySQL']) ?>'> -<input type='hidden' id='hasSQLite' value='<?php p($_['hasSQLite']) ?>'> -<input type='hidden' id='hasPostgreSQL' value='<?php p($_['hasPostgreSQL']) ?>'> -<input type='hidden' id='hasOracle' value='<?php p($_['hasOracle']) ?>'> -<form method="post" class="guest-box install-form"> -<input type="hidden" name="install" value="true"> - <?php if (count($_['errors']) > 0): ?> - <fieldset class="warning"> - <legend><strong><?php p($l->t('Error'));?></strong></legend> - <?php foreach ($_['errors'] as $err): ?> - <p> - <?php if (is_array($err)):?> - <?php p($err['error']); ?> - <span class='hint'><?php p($err['hint']); ?></span> - <?php else: ?> - <?php p($err); ?> - <?php endif; ?> - </p> - <?php endforeach; ?> - </fieldset> - <?php endif; ?> - <?php if (!$_['htaccessWorking']): ?> - <fieldset class="warning"> - <legend><strong><?php p($l->t('Security warning'));?></strong></legend> - <p><?php p($l->t('Your data directory and files are probably accessible from the internet because the .htaccess file does not work.'));?><br> - <?php print_unescaped($l->t( - 'For information how to properly configure your server, please see the <a href="%s" target="_blank" rel="noreferrer noopener">documentation</a>.', - [link_to_docs('admin-install')] - )); ?></p> - </fieldset> - <?php endif; ?> - <fieldset id="adminaccount"> - <legend><?php print_unescaped($l->t('<strong>Create an admin account</strong>')); ?></legend> - <p> - <label for="adminlogin"><?php p($l->t('New admin account name')); ?></label> - <input type="text" name="adminlogin" id="adminlogin" - value="<?php p($_['adminlogin']); ?>" - autocomplete="off" autocapitalize="none" spellcheck="false" autofocus required> - </p> - <p class="groupbottom"> - <label for="adminpass"><?php p($l->t('New admin password')); ?></label> - <input type="password" name="adminpass" data-typetoggle="#show" id="adminpass" - value="<?php p($_['adminpass']); ?>" - autocomplete="off" autocapitalize="none" spellcheck="false" required> - <button id="show" class="toggle-password" aria-label="<?php p($l->t('Show password')); ?>"> - <img src="<?php print_unescaped(image_path('', 'actions/toggle.svg')); ?>" alt="<?php p($l->t('Toggle password visibility')); ?>"> - </button> - </p> - </fieldset> - - <?php if (!$_['directoryIsSet'] or !$_['dbIsSet'] or count($_['errors']) > 0): ?> - <fieldset id="advancedHeader"> - <legend><a id="showAdvanced" tabindex="0" href="#"><?php p($l->t('Storage & database')); ?><img src="<?php print_unescaped(image_path('core', 'actions/caret.svg')); ?>" /></a></legend> - </fieldset> - <?php endif; ?> - - <?php if (!$_['directoryIsSet'] or count($_['errors']) > 0): ?> - <fieldset id="datadirField"> - <div id="datadirContent"> - <label for="directory"><?php p($l->t('Data folder')); ?></label> - <input type="text" name="directory" id="directory" - placeholder="<?php p(OC::$SERVERROOT . '/data'); ?>" - value="<?php p($_['directory']); ?>" - autocomplete="off" autocapitalize="none" spellcheck="false"> - </div> - </fieldset> - <?php endif; ?> - - <?php if (!$_['dbIsSet'] or count($_['errors']) > 0): ?> - <fieldset id='databaseBackend'> - <?php if ($_['hasMySQL'] or $_['hasPostgreSQL'] or $_['hasOracle']) { - $hasOtherDB = true; - } else { - $hasOtherDB = false; - } //other than SQLite?> - <legend><?php p($l->t('Configure the database')); ?></legend> - <div id="selectDbType"> - <?php foreach ($_['databases'] as $type => $label): ?> - <?php if (count($_['databases']) === 1): ?> - <p class="info"> - <?php p($l->t('Only %s is available.', [$label])); ?> - <?php p($l->t('Install and activate additional PHP modules to choose other database types.')); ?><br> - <a href="<?php print_unescaped(link_to_docs('admin-source_install')); ?>" target="_blank" rel="noreferrer noopener"> - <?php p($l->t('For more details check out the documentation.')); ?> ↗</a> - </p> - <input type="hidden" id="dbtype" name="dbtype" value="<?php p($type) ?>"> - <?php else: ?> - <input type="radio" name="dbtype" value="<?php p($type) ?>" id="<?php p($type) ?>" - <?php print_unescaped($_['dbtype'] === $type ? 'checked="checked" ' : '') ?>/> - <label class="<?php p($type) ?>" for="<?php p($type) ?>"><?php p($label) ?></label> - <?php endif; ?> - <?php endforeach; ?> - </div> - </fieldset> - - <?php if ($hasOtherDB): ?> - <fieldset id='databaseField'> - <div id="use_other_db"> - <p class="grouptop"> - <label for="dbuser"><?php p($l->t('Database account')); ?></label> - <input type="text" name="dbuser" id="dbuser" - value="<?php p($_['dbuser']); ?>" - autocomplete="off" autocapitalize="none" spellcheck="false"> - </p> - <p class="groupmiddle"> - <label for="dbpass"><?php p($l->t('Database password')); ?></label> - <input type="password" name="dbpass" id="dbpass" - value="<?php p($_['dbpass']); ?>" - autocomplete="off" autocapitalize="none" spellcheck="false"> - <button id="show" class="toggle-password" aria-label="<?php p($l->t('Show password')); ?>"> - <img src="<?php print_unescaped(image_path('', 'actions/toggle.svg')); ?>" alt="<?php p($l->t('Toggle password visibility')); ?>"> - </button> - </p> - <p class="groupmiddle"> - <label for="dbname"><?php p($l->t('Database name')); ?></label> - <input type="text" name="dbname" id="dbname" - value="<?php p($_['dbname']); ?>" - autocomplete="off" autocapitalize="none" spellcheck="false" - pattern="[0-9a-zA-Z$_-]+"> - </p> - <?php if ($_['hasOracle']): ?> - <div id="use_oracle_db"> - <p class="groupmiddle"> - <label for="dbtablespace" class="infield"><?php p($l->t('Database tablespace')); ?></label> - <input type="text" name="dbtablespace" id="dbtablespace" - value="<?php p($_['dbtablespace']); ?>" - autocomplete="off" autocapitalize="none" spellcheck="false"> - </p> - </div> - <?php endif; ?> - <p class="groupbottom"> - <label for="dbhost"><?php p($l->t('Database host')); ?></label> - <input type="text" name="dbhost" id="dbhost" - value="<?php p($_['dbhost']); ?>" - autocomplete="off" autocapitalize="none" spellcheck="false"> - </p> - <p class="info"> - <?php p($l->t('Please specify the port number along with the host name (e.g., localhost:5432).')); ?> - </p> - </div> - </fieldset> - <?php endif; ?> - <?php endif; ?> - - <?php if (!$_['dbIsSet'] or count($_['errors']) > 0): ?> - <div id="sqliteInformation" class="notecard warning"> - <legend><?php p($l->t('Performance warning'));?></legend> - <p><?php p($l->t('You chose SQLite as database.'));?></p> - <p><?php p($l->t('SQLite should only be used for minimal and development instances. For production we recommend a different database backend.'));?></p> - <p><?php p($l->t('If you use clients for file syncing, the use of SQLite is highly discouraged.')); ?></p> - </div> - <?php endif ?> - - <div class="icon-loading-dark float-spinner"> </div> - - <div class="buttons"><input type="submit" class="primary" value="<?php p($l->t('Install')); ?>" data-finishing="<?php p($l->t('Installing …')); ?>"></div> - - <p class="info"> - <span class="icon-info-white"></span> - <?php p($l->t('Need help?'));?> - <a target="_blank" rel="noreferrer noopener" href="<?php p(link_to_docs('admin-install')); ?>"><?php p($l->t('See the documentation'));?> ↗</a> - </p> -</form> +<div id="content"></div> diff --git a/webpack.modules.js b/webpack.modules.js index 13ceea2b0cf..b05afa6d3f5 100644 --- a/webpack.modules.js +++ b/webpack.modules.js @@ -14,7 +14,7 @@ module.exports = { 'ajax-cron': path.join(__dirname, 'core/src', 'ajax-cron.ts'), files_client: path.join(__dirname, 'core/src', 'files/client.js'), files_fileinfo: path.join(__dirname, 'core/src', 'files/fileinfo.js'), - install: path.join(__dirname, 'core/src', 'install.js'), + install: path.join(__dirname, 'core/src', 'install.ts'), login: path.join(__dirname, 'core/src', 'login.js'), main: path.join(__dirname, 'core/src', 'main.js'), maintenance: path.join(__dirname, 'core/src', 'maintenance.js'), |