generated from Seekra/repository-template
Feat(settings): add renderer for settings configuration #142
2 Participants
Notifications
Due Date
No due date set.
Blocks
#138 Complete translations
Seekra/frontend
Reference: Seekra/frontend#142
Reference in New Issue
Block a user
Settings renderer
This pull request adds a renderer that renders any settings configuration.
Summary
Implementation
The settings renderer always shows the current section, which is recursively determined from the route subpath (the path after
/settings, for an example,/settings/section1/section2). There are components for each setting type which get information about their setting. The components do the actual work: They display the settings in the store and save the settings configured by the user in the store.Description
Pinia integration
This PR adds Pinia, Pinia test utils, and
pinia-plugin-persistedstateto the dependencies. The app now uses Pinia and Pinia usespinia-plugin-persistedstatefor persistence.Settings components
There are component for each setting type. Each component has been thoroughly tested (see the test files).
The settings components have props for their setting and their path. Each of them shows the value from the store or the default value as a fallback. If there is no default value, a value specific to the setting type is shown as a fallback for the fallback.
Switch
The component for boolean settings. It displays the translation of the setting on the left side and a box with a circle on the right. When the user clicks the component, the setting is toggled. The position of the circle indicates the setting value (left: false, right: true).
There are tests for the switch.
Input
The component for both number and string settings. These two setting types were combined as the difference is very small; only the type of the input element is either
numberortext. This type is set by the component, based on the setting type.The settings input component shows the translation on the left side and the input on the right side.
When the value of the input is different from the stored value, a done button is shown. There is an animation when it is shown and hidden. This done button is the button that submits the form the input is wrapped in. On form submit (either done button click or pressing the enter key), the entered value is stored.
When the stored value changes, the input value also updates if it there are no unsaved changes in the input.
There are tests for the input.
Selection
The component for selection settings. It shows the translation of the setting and a list of the options below that. It supports both multiple choice and single choice inputs.
If the setting allows multiple values, each option contains a radio input. If it does not, each option contains a checkbox input. A check mark icon indicated whether an option is selected or not.
If the user selects options, the value is immediately stored.
When the component is mounted, the value is retrieved from the settings store and the corresponding option(s) is/are selected.
There are tests for the selection.
Settings page link
The settings page link is used for sections. It is a button that shows the setting translation on the left and a chevron facing right on the right side.
When it is clicked, the settings page path is set to the link target (its settings section) using the
useSettingsPagecomposable.There are tests for the settings page link.
Settings page composable
As mentioned above, there is a composable for the settings page:
useSettingsPage. It provides the functiongoToSettingsPage, which is used to go to a settings page. It pushes the route for the specified settings page path to the history and settings view automatically updates the section shown as it watches the router.There are tests for this composable.
Settings store
The store for the settings is a Pinia store with persistence (it is stored locally using local storage). It provides functions to set, get, and remove values and to clear the store. The settings themselves are an object wrapped by Vue's
reactive.Settings getting utility
There are two utility functions to get settings: a one to get a setting of one level and one to get a setting recursively, based on its path.
Both are tested.
Settings pages utility
This utility provides a function to get the segments of a setting path.
Of course, there are tests for this utility.
Component mounting utility
A utility function to mount components in their context.
Related issues
Closes: #79
@@ -0,0 +48,4 @@},path: {required: true},Please remove this unnecessary comma.
@@ -0,0 +30,4 @@},path: {required: true},Please remove this unnecessary comma.
@@ -0,0 +20,4 @@import { expect, describe, test } from 'vitest';import { nextTick } from 'vue';const getWrapper = function getWrapper (options = {}) {I think object destructuring would make more sense here.
@@ -0,0 +55,4 @@describe('Selection', () => {test('displays options correctly', () => {const options = [Use the
exampleOptionsobject.@@ -0,0 +22,4 @@describe('Switch', () => {test('shows value from store', async () => {const wrapper = mountComponent(Switch, {Please add a function to get the wrapper and avoid repeating code.
99ae2725cdto312734233b@@ -0,0 +21,4 @@export const getSettingRecursively = function getSettingRecursively (sectionPath, settings) {const oneSettingsLevel = function oneSettingsLevel (cursor, acc) {const setting = getSetting(cursor[0], acc.content);if (!setting) {Put this in one line.
@@ -0,0 +18,4 @@return settings.filter((setting) => setting.name === name)[0];};export const getSettingRecursively = function getSettingRecursively (sectionPath, settings) {It makes more sense to pass the section path as an array.
@@ -0,0 +68,4 @@</div><ul class="options-list"><li v-for="option in props.setting.options" :key="option.name"><label class="settings-button">Please add a
titleandaria-labelattributes.@@ -0,0 +63,4 @@<template><div><div class="label">Please add a label relationship between
div.labelandul.options-list.@@ -0,0 +56,4 @@const optionType = computed(() => props.setting.allowMultiple ? 'checkbox' : 'radio');const selected = ref(normalizeSelectedValue(store.get(props.path) ?? props.setting.default));watch(selected, (newValue, oldValue) => {The
oldValueparameter is not necessary.This looks better.
Very good and very fast!
c1f2d31f4etoeb43e2f49f