diff --git a/.editorconfig b/.editorconfig index 6599be17..d01500bb 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,3 +3,7 @@ [*.xml] indent_size = 4 indent_style = space + +[*.js] +indent_size = 4 +indent_style = space diff --git a/.nextcloudignore b/.nextcloudignore index 51fb890e..9a2976d4 100644 --- a/.nextcloudignore +++ b/.nextcloudignore @@ -22,4 +22,4 @@ /scripts/ /.git/ /krankerl.toml - +/.editorconfig diff --git a/Makefile b/Makefile index aeae9a28..4dc1b47c 100644 --- a/Makefile +++ b/Makefile @@ -13,8 +13,8 @@ all: dev-setup build dev-setup: 3rdparty/riot npm i -3rdparty/riot: - (cd 3rdparty/riot-web && npm i && npm run build && cp config.sample.json webapp/ && mv webapp ../riot) +3rdparty/riot: 3rdparty/riot-web + (cd 3rdparty/riot-web && npm i && npm run build && cp config.sample.json webapp/ && cp riot.im/develop/config.json webapp/develop.config.json && mv webapp ../riot) .PHONY: build build: @@ -43,4 +43,4 @@ source: .PHONY: appstore appstore: - + diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 44c1709a..f95365c7 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -41,4 +41,10 @@ class Application extends App { public function __construct(array $urlParams = []) { parent::__construct(self::APP_ID, $urlParams); } + + public static function AvailableLabs() { + $developConfig = json_decode(file_get_contents(__DIR__ . '/../../3rdparty/riot/develop.config.json'), true); + $labs = $developConfig['features']; + return array_keys($labs); + } } diff --git a/lib/Controller/ConfigController.php b/lib/Controller/ConfigController.php index 991bc169..f6b86ea2 100644 --- a/lib/Controller/ConfigController.php +++ b/lib/Controller/ConfigController.php @@ -84,6 +84,7 @@ public function config() { 'branding' => [ 'authHeaderLogoUrl' => $this->defaults->getLogo(), ], + 'features' => [], ]; $jitsi_domain = $this->config->getAppValue(Application::APP_ID, 'jitsi_preferred_domain', Application::AvailableSettings['jitsi_preferred_domain']); if ($jitsi_domain !== "") { @@ -91,6 +92,9 @@ public function config() { 'preferredDomain' => $jitsi_domain, ]; } + foreach (Application::AvailableLabs() as $lab) { + $config['features'][$lab] = $this->config->getAppValue(Application::APP_ID, 'lab_' . $lab, 'disable'); + } return new JSONResponse($config); } diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index cedf5e31..2a66e60c 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -49,7 +49,11 @@ public function __construct($appName, IRequest $request, IConfig $config) { * @return JSONResponse */ public function setSetting(string $key, string $value): JSONResponse { - if (!array_key_exists($key, Application::AvailableSettings)) { + $labSettingNames = []; + foreach (Application::AvailableLabs() as $k) { + $labSettingNames[] = "lab_" . $k; + } + if (!array_key_exists($key, Application::AvailableSettings) && !in_array($key, $labSettingNames)) { return new JSONResponse([ 'message' => 'parameter does not exist', ], Http::STATUS_UNPROCESSABLE_ENTITY); diff --git a/lib/Settings/Admin.php b/lib/Settings/Admin.php index a6db9b05..49c57d3e 100644 --- a/lib/Settings/Admin.php +++ b/lib/Settings/Admin.php @@ -62,6 +62,12 @@ public function getForm() { $this->initialStateService->provideInitialState(Application::APP_ID, $key, $data); } + $labstr = []; + foreach (Application::AvailableLabs() as $k) { + $labstr['lab_' . $k] = $this->config->getAppValue(Application::APP_ID, 'lab_' . $k, 'disable'); + } + $this->initialStateService->provideInitialState(Application::APP_ID, 'labs', json_encode($labstr)); + return new TemplateResponse(Application::APP_ID, 'settings/admin'); } diff --git a/src/.eslintrc.json b/src/.eslintrc.json index d5e208b6..0018173d 100644 --- a/src/.eslintrc.json +++ b/src/.eslintrc.json @@ -11,7 +11,8 @@ ], "globals": { "t": true, - "n": true + "n": true, + "RIOT_WEB_HASH": true }, "parserOptions": { "parser": "babel-eslint", diff --git a/src/components/AdminSettings.vue b/src/components/AdminSettings.vue index 75b0dc3e..38ca7e05 100644 --- a/src/components/AdminSettings.vue +++ b/src/components/AdminSettings.vue @@ -87,6 +87,32 @@ @change="updateSetting('jitsi_preferred_domain')" > + +

+

{{ t('riotchat', '"enabled" enables the feature for all users. "disable" disables the feature for all users. "labs" adds the feature to the user\'s settings.') }}

+
+
+ + +
+
@@ -108,13 +134,29 @@ export default { "server_name": loadState('riotchat', 'server_name'), "disable_custom_urls": loadState('riotchat', 'disable_custom_urls') === 'true', "disable_login_language_selector": loadState('riotchat', 'disable_login_language_selector') === 'true', - "jitsi_preferred_domain": loadState('riotchat', 'jitsi_preferrred_domain'), + "jitsi_preferred_domain": loadState('riotchat', 'jitsi_preferred_domain'), + "labs": JSON.parse(loadState('riotchat', 'labs')), }; }, + computed: { + featureDocumentation () { + return t('riotchat', 'These are experimental features in Riot.im that you can enable. For information on what each feature is, check out the documentation for it {linkstart}here{linkend}') + .replace('{linkstart}', ``) + .replace('{linkend}', ``); + }, + + }, methods: { updateSetting (setting) { const value = this[setting].toString(); const settingName = this.$refs[setting].innerText.split("(")[0].split(":")[0].trim(); + this.sendUpdate(setting, settingName, value); + }, + updateLabSetting (setting) { + const value = this.labs[setting].toString(); + this.sendUpdate(setting, t('riotchat', 'Experimental feature {feature}', { feature: setting }), value); + }, + sendUpdate (setting, settingName, value) { Axios.put(generateUrl(`apps/riotchat/settings/${setting}`), { value, }).then(() => { diff --git a/webpack.config.js b/webpack.config.js index c89ecec8..5708d4d2 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,5 +1,7 @@ const path = require('path'); +const { execSync } = require('child_process'); const { VueLoaderPlugin } = require('vue-loader'); +const webpack = require('webpack'); module.exports = { entry: { @@ -35,6 +37,9 @@ module.exports = { }, plugins: [ new VueLoaderPlugin(), + new webpack.DefinePlugin({ + RIOT_WEB_HASH: JSON.stringify(execSync('git rev-parse HEAD', { cwd: path.resolve(__dirname, './3rdparty/riot-web') }).toString()), + }), ], resolve: { extensions: ['.js', '.vue'],