feat: add option for users to select their preferred way of formatting date times

pull/3424/head
Joppe Koers 2024-08-25 15:28:47 +02:00
parent 83898d616f
commit 4bd630933e
No known key found for this signature in database
14 changed files with 148 additions and 72 deletions

View File

@ -161,6 +161,7 @@ func (a *HookAuth) SaveUser() (*users.User, error) {
Password: pass, Password: pass,
Scope: a.Settings.Defaults.Scope, Scope: a.Settings.Defaults.Scope,
Locale: a.Settings.Defaults.Locale, Locale: a.Settings.Defaults.Locale,
DateTimeFormat: a.Settings.Defaults.DateTimeFormat,
ViewMode: a.Settings.Defaults.ViewMode, ViewMode: a.Settings.Defaults.ViewMode,
SingleClick: a.Settings.Defaults.SingleClick, SingleClick: a.Settings.Defaults.SingleClick,
Sorting: a.Settings.Defaults.Sorting, Sorting: a.Settings.Defaults.Sorting,
@ -225,6 +226,7 @@ func (a *HookAuth) GetUser(d *users.User) *users.User {
Locale: a.Fields.GetString("user.locale", d.Locale), Locale: a.Fields.GetString("user.locale", d.Locale),
ViewMode: users.ViewMode(a.Fields.GetString("user.viewMode", string(d.ViewMode))), ViewMode: users.ViewMode(a.Fields.GetString("user.viewMode", string(d.ViewMode))),
SingleClick: a.Fields.GetBoolean("user.singleClick", d.SingleClick), SingleClick: a.Fields.GetBoolean("user.singleClick", d.SingleClick),
DateTimeFormat: a.Fields.GetString("user.dateTimeFormat", d.DateTimeFormat),
Sorting: files.Sorting{ Sorting: files.Sorting{
Asc: a.Fields.GetBoolean("user.sorting.asc", d.Sorting.Asc), Asc: a.Fields.GetBoolean("user.sorting.asc", d.Sorting.Asc),
By: a.Fields.GetString("user.sorting.by", d.Sorting.By), By: a.Fields.GetString("user.sorting.by", d.Sorting.By),

View File

@ -166,6 +166,7 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut
fmt.Fprintln(w, "\nDefaults:") fmt.Fprintln(w, "\nDefaults:")
fmt.Fprintf(w, "\tScope:\t%s\n", set.Defaults.Scope) fmt.Fprintf(w, "\tScope:\t%s\n", set.Defaults.Scope)
fmt.Fprintf(w, "\tLocale:\t%s\n", set.Defaults.Locale) fmt.Fprintf(w, "\tLocale:\t%s\n", set.Defaults.Locale)
fmt.Fprintf(w, "\tDateTimeFormat:\t%s\n", set.Defaults.DateTimeFormat)
fmt.Fprintf(w, "\tView mode:\t%s\n", set.Defaults.ViewMode) fmt.Fprintf(w, "\tView mode:\t%s\n", set.Defaults.ViewMode)
fmt.Fprintf(w, "\tSingle Click:\t%t\n", set.Defaults.SingleClick) fmt.Fprintf(w, "\tSingle Click:\t%t\n", set.Defaults.SingleClick)
fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " ")) fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " "))

View File

@ -325,6 +325,7 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) {
Defaults: settings.UserDefaults{ Defaults: settings.UserDefaults{
Scope: ".", Scope: ".",
Locale: "en", Locale: "en",
DateTimeFormat: "MM/DD/YYYY h:mm A",
SingleClick: false, SingleClick: false,
Perm: users.Permissions{ Perm: users.Permissions{
Admin: false, Admin: false,

View File

@ -27,10 +27,10 @@ var usersCmd = &cobra.Command{
func printUsers(usrs []*users.User) { func printUsers(usrs []*users.User) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintln(w, "ID\tUsername\tScope\tLocale\tV. Mode\tS.Click\tAdmin\tExecute\tCreate\tRename\tModify\tDelete\tShare\tDownload\tPwd Lock") fmt.Fprintln(w, "ID\tUsername\tScope\tLocale\tV. Mode\tS.Click\tAdmin\tExecute\tCreate\tRename\tModify\tDelete\tShare\tDownload\tPwd Lock\tDateTimeFormat")
for _, u := range usrs { for _, u := range usrs {
fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t\n", fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%s\t\n",
u.ID, u.ID,
u.Username, u.Username,
u.Scope, u.Scope,
@ -46,6 +46,7 @@ func printUsers(usrs []*users.User) {
u.Perm.Share, u.Perm.Share,
u.Perm.Download, u.Perm.Download,
u.LockPassword, u.LockPassword,
u.DateTimeFormat,
) )
} }
@ -75,6 +76,7 @@ func addUserFlags(flags *pflag.FlagSet) {
flags.StringSlice("commands", nil, "a list of the commands a user can execute") flags.StringSlice("commands", nil, "a list of the commands a user can execute")
flags.String("scope", ".", "scope for users") flags.String("scope", ".", "scope for users")
flags.String("locale", "en", "locale for users") flags.String("locale", "en", "locale for users")
flags.String("dateTimeFormat", "MM/DD/YYYY h:mm A", "date time format for users")
flags.String("viewMode", string(users.ListViewMode), "view mode for users") flags.String("viewMode", string(users.ListViewMode), "view mode for users")
flags.Bool("singleClick", false, "use single clicks only") flags.Bool("singleClick", false, "use single clicks only")
} }

View File

@ -43,6 +43,7 @@ options you want to change.`,
defaults := settings.UserDefaults{ defaults := settings.UserDefaults{
Scope: user.Scope, Scope: user.Scope,
Locale: user.Locale, Locale: user.Locale,
DateTimeFormat: user.DateTimeFormat,
ViewMode: user.ViewMode, ViewMode: user.ViewMode,
SingleClick: user.SingleClick, SingleClick: user.SingleClick,
Perm: user.Perm, Perm: user.Perm,
@ -52,6 +53,7 @@ options you want to change.`,
getUserDefaults(flags, &defaults, false) getUserDefaults(flags, &defaults, false)
user.Scope = defaults.Scope user.Scope = defaults.Scope
user.Locale = defaults.Locale user.Locale = defaults.Locale
user.DateTimeFormat = defaults.DateTimeFormat
user.ViewMode = defaults.ViewMode user.ViewMode = defaults.ViewMode
user.SingleClick = defaults.SingleClick user.SingleClick = defaults.SingleClick
user.Perm = defaults.Perm user.Perm = defaults.Perm

View File

@ -110,7 +110,8 @@ const humanSize = () => {
const humanTime = () => { const humanTime = () => {
if (!props.readOnly && authStore.user?.dateFormat) { if (!props.readOnly && authStore.user?.dateFormat) {
return dayjs(props.modified).format("L LT"); const format = authStore.user?.dateTimeFormat || "L LT";
return dayjs(props.modified).format(format);
} }
return dayjs(props.modified).fromNow(); return dayjs(props.modified).fromNow();
}; };

View File

@ -0,0 +1,48 @@
<template>
<select
name="selectDateTimeFormat"
v-on:change="change"
:value="dateTimeFormat"
>
<option
v-for="(dateTimeFormat, value) in dateTimeFormats"
:key="value"
:value="value"
>
{{ dateTimeFormat }}
</option>
</select>
</template>
<script>
import { markRaw } from "vue";
export default {
name: "dateTimeFormats",
props: ["dateTimeFormat"],
data() {
let dataObj = {};
const dateTimeFormats = {
"MM/DD/YYYY h:mm A": "02/21/2023 3:59 PM",
"YYYY/MM/DD HH:mm": "2023/02/21 15:59",
"DD/MM/YYYY HH:mm": "21/02/2023 15:59",
};
// Vue3 reactivity breaks with this configuration
// so we need to use markRaw as a workaround
// https://github.com/vuejs/core/issues/3024
Object.defineProperty(dataObj, "dateTimeFormats", {
value: markRaw(dateTimeFormats),
configurable: false,
writable: false,
});
return dataObj;
},
methods: {
change(event) {
this.$emit("update:dateTimeFormat", event.target.value);
},
},
};
</script>

View File

@ -191,6 +191,7 @@
"insertRegex": "Insert regex expression", "insertRegex": "Insert regex expression",
"instanceName": "Instance name", "instanceName": "Instance name",
"language": "Language", "language": "Language",
"dateTimeFormat": "Date and time format",
"lockPassword": "Prevent the user from changing the password", "lockPassword": "Prevent the user from changing the password",
"newPassword": "Your new password", "newPassword": "Your new password",
"newPasswordConfirm": "Confirm your new password", "newPasswordConfirm": "Confirm your new password",

View File

@ -13,6 +13,7 @@ interface ISettings {
interface SettingsDefaults { interface SettingsDefaults {
scope: string; scope: string;
locale: string; locale: string;
dateTimeFormat: string;
viewMode: ViewModeType; viewMode: ViewModeType;
singleClick: boolean; singleClick: boolean;
sorting: Sorting; sorting: Sorting;

View File

@ -4,6 +4,7 @@ interface IUser {
password: string; password: string;
scope: string; scope: string;
locale: string; locale: string;
dateTimeFormat: string;
perm: Permissions; perm: Permissions;
commands: string[]; commands: string[];
rules: IRule[]; rules: IRule[];
@ -23,6 +24,7 @@ interface IUserForm {
password?: string; password?: string;
scope?: string; scope?: string;
locale?: string; locale?: string;
dateTimeFormat?: string;
perm?: Permissions; perm?: Permissions;
commands?: string[]; commands?: string[];
rules?: IRule[]; rules?: IRule[];

View File

@ -24,6 +24,11 @@
class="input input--block" class="input input--block"
v-model:locale="locale" v-model:locale="locale"
></languages> ></languages>
<h3>{{ t("settings.dateTimeFormat") }}</h3>
<date-time-format
class="input input--block"
v-model:dateTimeFormat="dateTimeFormatValue"
></date-time-format>
</div> </div>
<div class="card-action"> <div class="card-action">
@ -82,6 +87,7 @@ import { useAuthStore } from "@/stores/auth";
import { useLayoutStore } from "@/stores/layout"; import { useLayoutStore } from "@/stores/layout";
import { users as api } from "@/api"; import { users as api } from "@/api";
import Languages from "@/components/settings/Languages.vue"; import Languages from "@/components/settings/Languages.vue";
import DateTimeFormat from "@/components/settings/DateTimeFormats.vue";
import { computed, inject, onMounted, ref } from "vue"; import { computed, inject, onMounted, ref } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
@ -97,6 +103,7 @@ const passwordConf = ref<string>("");
const hideDotfiles = ref<boolean>(false); const hideDotfiles = ref<boolean>(false);
const singleClick = ref<boolean>(false); const singleClick = ref<boolean>(false);
const dateFormat = ref<boolean>(false); const dateFormat = ref<boolean>(false);
const dateTimeFormatValue = ref<string>("");
const locale = ref<string>(""); const locale = ref<string>("");
const passwordClass = computed(() => { const passwordClass = computed(() => {
@ -117,6 +124,7 @@ onMounted(() => {
layoutStore.loading = true; layoutStore.loading = true;
if (authStore.user === null) return false; if (authStore.user === null) return false;
locale.value = authStore.user.locale; locale.value = authStore.user.locale;
dateTimeFormatValue.value = authStore.user.dateTimeFormat;
hideDotfiles.value = authStore.user.hideDotfiles; hideDotfiles.value = authStore.user.hideDotfiles;
singleClick.value = authStore.user.singleClick; singleClick.value = authStore.user.singleClick;
dateFormat.value = authStore.user.dateFormat; dateFormat.value = authStore.user.dateFormat;
@ -160,6 +168,7 @@ const updateSettings = async (event: Event) => {
...authStore.user, ...authStore.user,
id: authStore.user.id, id: authStore.user.id,
locale: locale.value, locale: locale.value,
dateTimeFormat: dateTimeFormatValue.value,
hideDotfiles: hideDotfiles.value, hideDotfiles: hideDotfiles.value,
singleClick: singleClick.value, singleClick: singleClick.value,
dateFormat: dateFormat.value, dateFormat: dateFormat.value,
@ -170,6 +179,7 @@ const updateSettings = async (event: Event) => {
"hideDotfiles", "hideDotfiles",
"singleClick", "singleClick",
"dateFormat", "dateFormat",
"dateTimeFormat",
]); ]);
authStore.updateUser(data); authStore.updateUser(data);
$showSuccess(t("settings.settingsUpdated")); $showSuccess(t("settings.settingsUpdated"));

View File

@ -23,6 +23,7 @@ const (
type userInfo struct { type userInfo struct {
ID uint `json:"id"` ID uint `json:"id"`
Locale string `json:"locale"` Locale string `json:"locale"`
DateTimeFormat string `json:"dateTimeFormat"`
ViewMode users.ViewMode `json:"viewMode"` ViewMode users.ViewMode `json:"viewMode"`
SingleClick bool `json:"singleClick"` SingleClick bool `json:"singleClick"`
Perm users.Permissions `json:"perm"` Perm users.Permissions `json:"perm"`
@ -188,6 +189,7 @@ func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.Use
User: userInfo{ User: userInfo{
ID: user.ID, ID: user.ID,
Locale: user.Locale, Locale: user.Locale,
DateTimeFormat: user.DateTimeFormat,
ViewMode: user.ViewMode, ViewMode: user.ViewMode,
SingleClick: user.SingleClick, SingleClick: user.SingleClick,
Perm: user.Perm, Perm: user.Perm,

View File

@ -10,6 +10,7 @@ import (
type UserDefaults struct { type UserDefaults struct {
Scope string `json:"scope"` Scope string `json:"scope"`
Locale string `json:"locale"` Locale string `json:"locale"`
DateTimeFormat string `json:"dateTimeFormat"`
ViewMode users.ViewMode `json:"viewMode"` ViewMode users.ViewMode `json:"viewMode"`
SingleClick bool `json:"singleClick"` SingleClick bool `json:"singleClick"`
Sorting files.Sorting `json:"sorting"` Sorting files.Sorting `json:"sorting"`
@ -23,6 +24,7 @@ type UserDefaults struct {
func (d *UserDefaults) Apply(u *users.User) { func (d *UserDefaults) Apply(u *users.User) {
u.Scope = d.Scope u.Scope = d.Scope
u.Locale = d.Locale u.Locale = d.Locale
u.DateTimeFormat = d.DateTimeFormat
u.ViewMode = d.ViewMode u.ViewMode = d.ViewMode
u.SingleClick = d.SingleClick u.SingleClick = d.SingleClick
u.Perm = d.Perm u.Perm = d.Perm

View File

@ -26,6 +26,7 @@ type User struct {
Password string `json:"password"` Password string `json:"password"`
Scope string `json:"scope"` Scope string `json:"scope"`
Locale string `json:"locale"` Locale string `json:"locale"`
DateTimeFormat string `json:"dateTimeFormat"`
LockPassword bool `json:"lockPassword"` LockPassword bool `json:"lockPassword"`
ViewMode ViewMode `json:"viewMode"` ViewMode ViewMode `json:"viewMode"`
SingleClick bool `json:"singleClick"` SingleClick bool `json:"singleClick"`