updated styling (#1047)

This commit is contained in:
Graham Steffaniak authored and GitHub committed 2025-08-11 16:18:23 -05:00
1 parent 4f1797cced
commit adec56a120
35 files changed
+225 -269

No files matched your search

+4
View File
@@ -23,6 +23,10 @@ All notable changes to this project will be documented in this file. For commit
- share link public changes https://github.com/gtsteffaniak/filebrowser/issues/473
- public/private folder logic https://github.com/gtsteffaniak/filebrowser/issues/505
**BugFixes**:
- fix new file "true" content issue https://github.com/gtsteffaniak/filebrowser/issues/1048
- editor allows device default popup https://github.com/gtsteffaniak/filebrowser/issues/1049
## v0.7.18-beta
**Notes**:
-1
View File
@@ -331,7 +331,6 @@ func getContent(realPath string) (string, error) {
if err != nil {
return "", err
}
// Handle empty file (original logic - returns specific string)
if len(content) == 0 {
return "empty-file-x6OlSil", nil
+34 -27
View File
@@ -169,7 +169,7 @@ export default {
if (this.isMultiple || this.isSearchActive) {
return false;
}
if (state.user.showSelectMultiple) {
if (state.user?.showSelectMultiple) {
return true;
}
if (getters.isMobile()) {
@@ -177,20 +177,18 @@ export default {
}
return false
},
noItems() {
const hasItems = this.showEdit || this.showDelete || this.showSave || this.showGoToRaw;
mutations.setHasContextItems(!hasItems)
return !hasItems;
hasOverflowItems() {
return this.showEdit || this.showDelete || this.showSave || this.showGoToRaw;
},
showGoToRaw() {
return getters.currentView() == "preview" ||
getters.currentView() == "markdownViewer"
const cv = getters.currentView();
return cv == "preview" || cv == "markdownViewer" || cv == "editor";
},
showEdit() {
return getters.currentView() == "markdownViewer" && state.user.permissions.modify;
return getters.currentView() == "markdownViewer" && state.user?.permissions?.modify;
},
showDelete() {
return state.user.permissions.modify && this.isPreview;
return state.user?.permissions?.modify && this.isPreview;
},
isPreview() {
const cv = getters.currentView();
@@ -199,17 +197,18 @@ export default {
cv == "onlyOfficeEditor" ||
cv == "markdownViewer" ||
cv == "epubViewer" ||
cv == "docViewer"
cv == "docViewer" ||
cv == "editor"
);
},
showSave() {
return getters.currentView() == "editor" && state.user.permissions.modify;
return getters.currentView() == "editor" && state.user?.permissions?.modify;
},
showOverflow() {
return getters.currentPromptName() == "OverflowMenu";
},
showAccess() {
return state.user.permissions.admin && this.showCreate;
return state.user?.permissions?.admin && this.showCreate;
},
showShare() {
return (
@@ -238,6 +237,9 @@ export default {
centered() {
return this.showCentered || this.isMobileDevice || !this.posX || !this.posY;
},
isMobileDevice() {
return state.isMobile;
},
isDarkMode() {
return getters.isDarkMode();
},
@@ -246,13 +248,19 @@ export default {
},
userPerms() {
return {
upload: state.user.permissions?.modify && state.selected.length > 0,
share: state.user.permissions.share,
modify: state.user.permissions.modify,
upload: state.user?.permissions?.modify && state.selected.length > 0,
share: state.user?.permissions?.share,
modify: state.user?.permissions?.modify,
};
},
},
watch: {
hasOverflowItems: {
handler(hasItems) {
mutations.setContextMenuHasItems(hasItems);
},
immediate: true,
},
showContext: {
handler(newVal) {
if (newVal) {
@@ -279,8 +287,8 @@ export default {
name: "access",
props: {
sourceName: state.sources.current,
path: state.req.path
}
path: state.req?.path || "",
},
});
},
// Animation methods
@@ -373,17 +381,16 @@ export default {
},
startDownload() {
downloadFiles(state.selected);
mutations.closeHovers();
},
goToRaw() {
const downloadUrl = filesApi.getDownloadURL(
state.req.source,
state.req.path,
true,
false
);
window.open(downloadUrl, "_blank");
mutations.closeHovers();
state.req?.source || "",
state.req?.path || "",
true,
false
);
window.open(downloadUrl, "_blank");
mutations.closeHovers();
},
async edit() {
window.location.hash = "#edit";
@@ -397,7 +404,7 @@ export default {
notify.showSuccess("File Saved!");
} catch (e) {
buttons.done(button);
notify.showError("Error saving file: ", e);
notify.showError(`Error saving file: ${e}`);
}
mutations.closeHovers();
@@ -406,7 +413,7 @@ export default {
mutations.showHover({
name: "upload",
props: {
filesToReplace: state.selected.map((item) => item.name),
filesToReplace: state.selected.map((item) => item.name || ""),
},
});
},
@@ -25,4 +25,7 @@ export default {
canvas.notification-spinner {
color: #fff;
}
#popup-notification {
z-index: 6;
}
</style>
+5 -19
View File
@@ -20,17 +20,17 @@
{{ $t("search.path") }} {{ currentPath }}
</div>
<!-- Add Form -->
<div class="add-form" style="margin-bottom: 1em; margin-top: 1em">
<select v-model="addType">
<div class="form-flex-group" >
<select class="input flat-right form-compact" v-model="addType">
<option value="user">{{ $t("general.user") }}</option>
<option value="group">{{ $t("general.group") }}</option>
</select>
<select v-model="addListType">
<select class="input flat-right flat-left form-compact" v-model="addListType">
<option value="deny">{{ $t("access.deny") }}</option>
<option value="allow">{{ $t("access.allow") }}</option>
</select>
<input class="group-user-add-input" v-model="addName" :placeholder="$t('access.enterName')" />
<button class="action add-rule-button" @click="submitAdd">
<input class="input flat-right flat-left form-grow form-compact" v-model="addName" :placeholder="$t('access.enterName')" />
<button class="button form-button flat-left form-compact" @click="submitAdd">
<i class="material-icons">add</i>
</button>
</div>
@@ -212,17 +212,3 @@ export default {
}
};
</script>
<style scoped>
.add-form {
display: flex;
}
.add-rule-button {
max-width: 3em;
}
.group-user-add-input {
flex-grow: 1;
}
</style>
@@ -6,7 +6,7 @@
<div class="card-content">
<!-- API Key Name Input -->
<p>{{ $t('api.keyName') }}</p>
<input v-focus class="input input--block" type="text" v-model.trim="apiName"
<input v-focus class="input" type="text" v-model.trim="apiName"
:placeholder="$t('api.keyNamePlaceholder')" />
<!-- Duration Input -->
+1 -1
View File
@@ -6,7 +6,7 @@
{{ $t("prompts.destinationSource") }}
</label>
<select id="destinationSource" v-model="currentSource" @change="onSourceChange"
class="input input--block">
class="input">
<option v-for="source in availableSources" :key="source" :value="source">
{{ source }}
</option>
+1 -1
View File
@@ -5,7 +5,7 @@
<div class="card-content">
<p>{{ $t("prompts.newDirMessage") }}</p>
<input aria-label="New Folder Name" class="input input--block" type="text" @keyup.enter="submit" v-model.trim="name"
<input aria-label="New Folder Name" class="input" type="text" @keyup.enter="submit" v-model.trim="name"
v-focus />
</div>
+2 -1
View File
@@ -5,7 +5,7 @@
<div class="card-content">
<p>{{ $t("prompts.newFileMessage") }}</p>
<input class="input input--block" aria-label="FileName Field" v-focus type="text" @keyup.enter="submit"
<input class="input" aria-label="FileName Field" v-focus type="text" @keyup.enter="submit"
v-model.trim="name" />
</div>
@@ -53,6 +53,7 @@ export default {
await filesApi.post(
state.req.source,
state.req.path + "/" + this.name,
"",
true
);
goToItem(
+2 -2
View File
@@ -105,7 +105,7 @@ export default {
return getters.currentPromptName();
},
currentPrompt() {
if (getters.currentPrompt() == null) {
if (!getters.currentPrompt()) {
return {
props: {},
};
@@ -128,7 +128,7 @@ export default {
return state.plugins;
},
showOverlay() {
return getters.currentPromptName() !== "" && getters.currentPromptName() !== "ContextMenu";
return getters.currentPromptName() !== "" && getters.currentPromptName() !== "ContextMenu" && getters.currentPromptName() !== "OverflowMenu";
},
},
methods: {},
+2 -2
View File
@@ -5,7 +5,7 @@
<div class="card-content">
<p>{{ $t("prompts.renameMessage", { filename: oldName() }) }}</p>
<input class="input input--block" :class="{ 'invalid-form': !validateFileName(name) }" v-focus type="text"
<input class="input" :class="{ 'form-invalid': !validateFileName(name) }" v-focus type="text"
@keyup.enter="submit" v-model.trim="name" />
<p v-if="!validateFileName(name) && name.length > 0" class="validation-error">
{{ $t("prompts.invalidName") }}
@@ -124,7 +124,7 @@ export default {
</script>
<style scoped>
.invalid-form {
.form-invalid {
border-color: var(--red) !important;
}
+4 -6
View File
@@ -60,9 +60,9 @@
<template v-else>
<div class="card-content">
<p>{{ $t("settings.shareDuration") }}</p>
<div class="input-group input">
<input v-focus type="number" max="2147483647" min="1" @keyup.enter="submit" v-model.trim="time" />
<select class="right" v-model="unit" :aria-label="$t('time.unit')">
<div class="form-flex-group">
<input class="form-grow input flat-right" v-focus type="number" max="2147483647" min="1" @keyup.enter="submit" v-model.trim="time" />
<select class="flat-left input form-dropdown" v-model="unit" :aria-label="$t('time.unit')">
<option value="seconds">{{ $t("time.seconds") }}</option>
<option value="minutes">{{ $t("time.minutes") }}</option>
<option value="hours">{{ $t("time.hours") }}</option>
@@ -70,7 +70,7 @@
</select>
</div>
<p>{{ $t("prompts.optionalPassword") }}</p>
<input class="input input--block" type="password" v-model.trim="password" />
<input class="input" type="password" v-model.trim="password" />
</div>
<div class="card-action">
@@ -139,14 +139,12 @@ export default {
},
async beforeMount() {
let path = state.req.path;
console.log("state.req", state.req);
this.source = state.req.source;
if (state.isSearchActive) {
path = state.selected[0].path;
this.source = state.selected[0].source;
} else if (getters.selectedCount() === 1) {
const selected = getters.getFirstSelected();
console.log("selected", selected);
path = selected.path;
this.source = selected.source;
this.source = state.req.items[state.selected[0]].source;
+1 -1
View File
@@ -11,7 +11,7 @@
<qrcode-vue class="qrcode" :value="this.url" size="200" level="M"></qrcode-vue>
</div>
<p>{{ $t("otp.verifyInstructions") }}</p>
<input v-focus class="input input--block" type="text" v-model="code" @keyup.enter="verifyCode"
<input v-focus class="input" type="text" v-model="code" @keyup.enter="verifyCode"
:placeholder="$t('otp.codeInputPlaceholder')" />
</div>
@@ -74,7 +74,6 @@ export default {
return state.settings;
},
isNew() {
console.log("userId", this.userId);
return !this.userId;
},
},
+18 -18
View File
@@ -8,20 +8,20 @@
</h2>
<div v-if="user.loginMethod == 'password' && passwordAvailable && !isNew">
<label for="password">{{ $t("settings.password") }}</label>
<div class="form-group">
<div class="form-flex-group">
<input
class="input input--block form-form"
:class="{ 'invalid-form': invalidPassword }"
class="input form-form"
:class="{ 'form-invalid': invalidPassword }"
aria-label="Password1"
type="password"
:placeholder="$t('settings.enterPassword')"
v-model="passwordRef"
/>
</div>
<div class="form-group">
<div class="form-flex-group">
<input
class="input input--block form-form"
:class="{ 'flat-right': !isNew, 'invalid-form': invalidPassword }"
class="input form-form"
:class="{ 'flat-right': !isNew, 'form-invalid': invalidPassword }"
aria-label="Password2"
type="password"
:placeholder="$t('settings.enterPasswordAgain')"
@@ -31,7 +31,7 @@
<button
v-if="!isNew"
type="button"
class="button form-button"
class="button form-button flat-left"
@click="submitUpdatePassword"
>
{{ $t("buttons.update") }}
@@ -53,7 +53,7 @@
<p v-if="isNew">
<label for="username">{{ $t("settings.username") }}</label>
<input
class="input input--block"
class="input"
type="text"
v-model="user.username"
id="username"
@@ -63,20 +63,20 @@
<div v-if="user.loginMethod == 'password' && passwordAvailable && isNew">
<label for="password">{{ $t("settings.password") }}</label>
<div class="form-group">
<div class="form-flex-group">
<input
class="input input--block form-form"
:class="{ 'invalid-form': invalidPassword }"
class="input form-form"
:class="{ 'form-invalid': invalidPassword }"
aria-label="Password1"
type="password"
:placeholder="$t('settings.enterPassword')"
v-model="passwordRef"
/>
</div>
<div class="form-group">
<div class="form-flex-group">
<input
class="input input--block form-form"
:class="{ 'flat-right': !isNew, 'invalid-form': invalidPassword }"
class="input form-form"
:class="{ 'flat-right': !isNew, 'form-invalid': invalidPassword }"
type="password"
:placeholder="$t('settings.enterPasswordAgain')"
aria-label="Password2"
@@ -86,7 +86,7 @@
<button
v-if="!isNew"
type="button"
class="button form-button"
class="button form-button flat-left"
@click="submitUpdatePassword"
>
{{ $t("buttons.update") }}
@@ -111,7 +111,7 @@
<label for="scopes">{{ $t("settings.scopes") }}</label>
<div
class="scope-list"
:class="{ 'invalid-form': duplicateSources.includes(source.name) }"
:class="{ 'form-invalid': duplicateSources.includes(source.name) }"
v-for="(source, index) in selectedSources"
:key="index"
>
@@ -158,7 +158,7 @@
<p v-if="stateUser.username !== user.username">
<label for="locale">{{ $t("settings.language") }}</label>
<languages
class="input input--block"
class="input"
id="locale"
v-model:locale="user.locale"
@input="emitUpdate"
@@ -166,7 +166,7 @@
</p>
<div v-if="stateUser.permissions.admin">
<label for="loginMethod">{{ $t("settings.loginMethodDescription") }}</label>
<select v-model="user.loginMethod" class="input input--block" id="loginMethod">
<select v-model="user.loginMethod" class="input" id="loginMethod">
<option value="password">Password</option> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
<option value="oidc">OIDC</option> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
<option value="proxy">Proxy</option> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
@@ -41,6 +41,7 @@ export default {
},
active: (view) => state.activeSettingsView === view,
setView(view) {
mutations.closeHovers();
if (state.route.path != "/settings") {
router.push({ path: "/settings", hash: "#" + view }, () => {});
} else {
+14 -8
View File
@@ -1,11 +1,13 @@
.input {
border-radius: 1em;
padding: .5em 1em;
background: white;
border: 1px solid rgba(0, 0, 0, 0.1);
transition: .2s ease all;
color: #333;
margin: 0;
width: 100%;
background: var(--surfaceSecondary);
color: var(--textPrimary);
height: -webkit-fill-available;
}
.input:hover,
@@ -13,12 +15,6 @@
border-color: rgba(0, 0, 0, 0.2);
}
.input--block {
margin-bottom: .5em;
display: block;
width: 100%;
}
.input--textarea {
line-height: 1.15;
font-family: monospace;
@@ -33,3 +29,13 @@
.input--green {
background: #c9f2da;
}
/* Autofill hack to maintain style */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active {
-webkit-box-shadow: 0 0 0px 1000px var(--surfaceSecondary) inset !important;
-webkit-text-fill-color: var(--textPrimary) !important; /* Optional: Change text color to contrast */
}
-7
View File
@@ -124,13 +124,6 @@
color: var(--textPrimary);
}
.dark-mode .card#share input,
.dark-mode .card#share select,
.dark-mode .input {
background: var(--surfaceSecondary);
color: var(--textPrimary);
}
/* Input hover and focus */
.dark-mode .input:hover,
.dark-mode .input:focus {
+11 -73
View File
@@ -173,7 +173,7 @@ table tr>*:last-child {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 10;
z-index: 5;
max-width: 40em;
width: 90%;
max-height: 95%;
@@ -231,7 +231,6 @@ body.rtl .card-title>*:first-child {
}
.card h3 {
color: rgba(0, 0, 0, 0.53);
font-size: 1em;
font-weight: 500;
margin: 2em 0 1em;
@@ -245,77 +244,6 @@ body.rtl .card-title>*:first-child {
max-width: 15em;
}
.card#share ul {
list-style: none;
padding: 0;
margin: 0;
}
.card#share ul li {
display: flex;
justify-content: space-between;
align-items: center;
}
.card#share ul li a {
color: var(--primaryColor);
cursor: pointer;
margin-right: auto;
}
.card#share ul li .action i {
font-size: 1em;
}
.card#share ul li input,
.card#share ul li select {
padding: .2em;
margin-right: .5em;
border: 1px solid #dadada;
}
.card#share .action.copy-clipboard::after {
content: 'Copied!';
position: absolute;
left: -25%;
width: 150%;
font-size: .6em;
text-align: center;
background: #44a6f5;
color: #fff;
padding: .5em .2em;
border-radius: .4em;
top: -2em;
transition: .1s ease opacity;
opacity: 0;
}
.overlay {
background-color: rgba(0, 0, 0, 0.5);
position: fixed;
height: 100%;
width: 100%;
z-index: 4;
top: 0;
animation: .3s show ease-in;
}
.card#share .action.copy-clipboard.active::after {
opacity: 1;
}
.card#share .input-group {
display: flex;
}
.card#share .input-group * {
border: none;
}
.card#share .input-group input {
flex: 1;
}
.file-list {
max-height: 50vh;
overflow: auto;
@@ -477,3 +405,13 @@ body.rtl .credits {
text-align: right;
direction: ltr;
}
.overlay {
background-color: rgba(0, 0, 0, 0.5);
position: fixed;
height: 100%;
width: 100%;
z-index: 4;
top: 0;
animation: .3s show ease-in;
}
+44 -1
View File
@@ -356,4 +356,47 @@ button:hover,
/* Adjust shadow values as needed */
transform: scale(1.02);
/* Slightly enlarges the element */
}
}
.flat-right {
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
.flat-left {
border-top-left-radius: 0 !important;
border-bottom-left-radius: 0 !important;
}
.form-grow {
flex-grow: 1;
width: inherit;
min-width: 1em;
}
.form-flex-group {
display: flex;
flex-direction: row;
align-items: flex-start;
}
.form-flex-group > .form-compact {
min-height: 2em;
}
.form-button {
height: auto !important
}
.form-invalid {
border-color: red !important;
}
.form-compact {
padding: 0em;
}
.form-dropdown {
width: unset !important;
height: -webkit-fill-available;
}
+3 -2
View File
@@ -169,7 +169,7 @@ export const getters = {
if (currentView == 'settings') {
sticky = true
}
if (currentView == null && !getters.isLoading()) {
if (currentView == '' && !getters.isLoading()) {
sticky = true
}
if (getters.isShare()) {
@@ -207,7 +207,7 @@ export const getters = {
return "/" + removeLeadingSlash(parts.slice(2).join('/'))
},
currentView: () => {
let listingView = null
let listingView = ''
const pathname = getters.routePath()
if (pathname.startsWith(`/settings`)) {
listingView = 'settings'
@@ -289,6 +289,7 @@ export const getters = {
},
currentPromptName: () => {
console.log("currentPromptName", state.prompts);
// Ensure state.prompts is an array
if (!Array.isArray(state.prompts) || state.prompts.length === 0) {
return ""
+5 -3
View File
@@ -8,8 +8,9 @@ import { sortedItems } from "@/utils/sort.js";
import { serverHasMultipleSources } from "@/utils/constants.js";
export const mutations = {
setHasContextItems: (value) => {
state.contextMenuItems = value;
setContextMenuHasItems: (value) => {
state.contextMenuHasItems = value;
emitStateChanged();
},
setDeletedItem: (value) => {
state.deletedItem = value;
@@ -190,6 +191,7 @@ export const mutations = {
emitStateChanged();
},
showHover: (value) => {
console.log("showHover", value);
if (typeof value === "object") {
state.prompts.push({
name: value?.name,
@@ -205,6 +207,7 @@ export const mutations = {
props: value?.props,
});
}
console.log("showHover", state.prompts);
emitStateChanged();
},
setLoading: (loadType, status) => {
@@ -350,7 +353,6 @@ export const mutations = {
usersApi.update(value, updatedProperties);
}
}
console.log('updateCurrentUser4', state.user);
// Emit state change event
emitStateChanged();
},
+2 -1
View File
@@ -8,6 +8,7 @@ export const state = reactive({
x: 0,
y: 0,
},
contextMenuHasItems: false,
deletedItem: false,
previousHash: "",
multiButtonState: "menu",
@@ -116,4 +117,4 @@ export const state = reactive({
function stickyStartup() {
const stickyStatus = localStorage.getItem("stickySidebar");
return stickyStatus == "true"
}
}
+1 -25
View File
@@ -107,7 +107,7 @@ export default {
return getters.currentView();
},
currentViewLoaded() {
return getters.currentView() !== null;
return getters.currentView() != "";
},
reload() {
return state.reload;
@@ -127,7 +127,6 @@ export default {
mounted() {
window.addEventListener("hashchange", this.scrollToHash);
window.addEventListener("keydown", this.keyEvent);
console.log('Files mounted', state.user.username);
},
beforeUnmount() {
window.removeEventListener("keydown", this.keyEvent);
@@ -157,8 +156,6 @@ export default {
}
},
async fetchData() {
console.log('Fetching data', state.user.username);
if (state.deletedItem) {
return
}
@@ -177,7 +174,6 @@ export default {
try {
if (this.isShare) {
await this.fetchShareData();
console.log('Share data after fetch:')
} else {
await this.fetchFilesData();
}
@@ -212,12 +208,6 @@ export default {
this.shareHash = parts[1]
this.shareSubPath = "/" + parts.slice(2).join("/");
console.log('Share data:', {
hash: this.shareHash,
subPath: this.shareSubPath,
password: this.sharePassword
});
// Store share data in state for use by components
mutations.setShareData({
hash: this.shareHash,
@@ -244,24 +234,10 @@ export default {
// If not a directory, fetch content for preview components
if (file.type != "directory") {
const content = !getters.fileViewingDisabled(file.name);
console.log('Share file content fetch debug:', {
name: file.name,
type: file.type,
fileViewingDisabled: getters.fileViewingDisabled(file.name),
content: content,
disableViewingExt: state.user.disableViewingExt,
disableOfficePreviewExt: state.user.disableOfficePreviewExt
});
file = await publicApi.fetchPub(this.shareSubPath, this.shareHash, this.sharePassword, content);
file.hash = this.shareHash;
this.shareToken = file.token;
console.log('Share file after content fetch:', {
hasContent: 'content' in file,
contentLength: file.content ? file.content.length : 0,
contentPreview: file.content ? file.content.substring(0, 50) + '...' : null
});
}
mutations.replaceRequest(file);
+3 -3
View File
@@ -11,20 +11,20 @@
<div v-if="error !== ''" class="wrong-login card">{{ error }}</div>
<input
autofocus
class="input input--block"
class="input"
type="text"
autocapitalize="off"
v-model="username"
:placeholder="$t('general.username')"
/>
<input
class="input input--block"
class="input"
type="password"
v-model="password"
:placeholder="$t('general.password')"
/>
<input
class="input input--block"
class="input"
v-if="createMode"
type="password"
v-model="passwordConfirm"
-25
View File
@@ -96,31 +96,6 @@ export default {
<style>
.form-group {
display: flex;
flex-direction: row;
align-items: flex-start;
}
.form-button {
border-top-left-radius: 0 !important;
border-bottom-left-radius: 0 !important;
height: auto !important
}
.invalid-form {
border-color: red !important;
}
.flat-right {
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
.flat-left {
border-top-left-radius: 0 !important;
border-bottom-left-radius: 0 !important;
}
.dashboard {
display: flex;
flex-direction: column;
+1 -1
View File
@@ -89,7 +89,7 @@ export default {
return getters.isShare();
},
noItems() {
return !state.contextMenuItems;
return !state.contextMenuHasItems;
},
showEdit() {
return window.location.hash != "#edit" && state.user.permissions.modify;
+14 -2
View File
@@ -4,6 +4,12 @@
</div>
</template>
<style>
.ace_mobile-menu {
display: none !important;
}
</style>
<script>
import { eventBus } from "@/store/eventBus";
import { state, getters } from "@/store";
@@ -87,8 +93,8 @@ export default {
"basePath",
`https://cdn.jsdelivr.net/npm/ace-builds@${ace_version}/src-min-noconflict/`
);
const fileContent =
state.req.content == "empty-file-x6OlSil" ? "" : state.req.content || "";
const fileContent = state.req.content == "empty-file-x6OlSil" ? "" : state.req.content || "";
this.editor = ace.edit(editorEl, {
mode: modelist.getModeForPath(state.req.name).mode,
value: fileContent,
@@ -99,6 +105,12 @@ export default {
readOnly: state.req.type === "textImmutable",
wrap: false,
});
this.editor.container.addEventListener("contextmenu", (event) => {
event.stopPropagation();
}, true);
this.filename = decodeURIComponent(this.$route.path.split("/").pop());
} catch (error) {
notify.showError("Failed to initialize the editor. Please reload.");
@@ -42,9 +42,6 @@ export default {
async mounted() {
// Perform the setup and update the config
try {
if (getters.isShare()) {
console.log("state.share", state.share);
}
const refUrl = getters.isShare()
? publicApi.getDownloadURL({
path: state.share.subPath,
@@ -57,7 +54,6 @@ export default {
false,
true
);
console.log("refUrl", refUrl);
let configData;
let configUrl = `api/onlyoffice/config?url=${encodeURIComponent(refUrl)}`;
if (getters.isShare()) {
+4 -2
View File
@@ -29,7 +29,7 @@
</tr>
</tbody>
</table>
<div v-if="Object.keys(rules).length === 0">
<div v-if="Object.keys(rules).length === 0 && !loading">
<h2 class="message" v-if="Object.keys(rules).length === 0">
<i class="material-icons">sentiment_dissatisfied</i>
<span>{{ $t("files.lonely") }}</span>
@@ -70,9 +70,11 @@ export default {
} catch (e) {
this.error = e;
}
console.log(this.rules);
},
computed: {
loading() {
return state.loading;
},
},
methods: {
addAccess() {
+1 -1
View File
@@ -53,7 +53,7 @@
</table>
</div>
<h2 class="message" v-else>
<h2 class="message" v-else-if="!loading">
<i class="material-icons">sentiment_dissatisfied</i>
<span>{{ $t("files.lonely") }}</span>
</h2>
+1 -1
View File
@@ -27,7 +27,7 @@
</i>
</div>
<div class="no-padding">
<input class="sizeInput" v-model.number="localuser.fileLoading.uploadChunkSizeMb" type="number" min="0"
<input class="sizeInput input" v-model.number="localuser.fileLoading.uploadChunkSizeMb" type="number" min="0"
placeholder="number" />
</div>
</div>
+40 -27
View File
@@ -10,18 +10,21 @@
<ToggleSwitch
class="item"
v-model="localuser.disableQuickToggles"
@change="updateSettings"
:name="$t('profileSettings.disableQuickToggles')"
:description="$t('profileSettings.disableQuickTogglesDescription')"
/>
<ToggleSwitch
class="item"
v-model="localuser.preview.disableHideSidebar"
@change="updateSettings"
:name="$t('profileSettings.disableHideSidebar')"
:description="$t('profileSettings.disableHideSidebarDescription')"
/>
<ToggleSwitch
class="item"
v-model="localuser.hideSidebarFileActions"
@change="updateSettings"
:name="$t('profileSettings.hideSidebarFileActions')"
/>
@@ -33,29 +36,34 @@
<ToggleSwitch
class="item"
v-model="localuser.deleteWithoutConfirming"
@change="updateSettings"
:name="$t('profileSettings.deleteWithoutConfirming')"
:description="$t('profileSettings.deleteWithoutConfirmingDescription')"
/>
<ToggleSwitch
class="item"
v-model="localuser.dateFormat"
@change="updateSettings"
:name="$t('profileSettings.setDateFormat')"
/>
<ToggleSwitch
class="item"
v-model="localuser.showHidden"
@change="updateSettings"
:name="$t('profileSettings.showHiddenFiles')"
:description="$t('profileSettings.showHiddenFilesDescription')"
/>
<ToggleSwitch
class="item"
v-model="localuser.quickDownload"
@change="updateSettings"
:name="$t('profileSettings.showQuickDownload')"
:description="$t('profileSettings.showQuickDownloadDescription')"
/>
<ToggleSwitch
class="item"
v-model="localuser.preview.image"
@change="updateSettings"
:name="$t('profileSettings.previewImages')"
:description="$t('profileSettings.previewImagesDescription')"
/>
@@ -63,6 +71,7 @@
v-if="mediaEnabled"
class="item"
v-model="localuser.preview.video"
@change="updateSettings"
:name="$t('profileSettings.previewVideos')"
:description="$t('profileSettings.previewVideosDescription')"
/>
@@ -70,30 +79,35 @@
v-if="mediaEnabled"
class="item"
v-model="localuser.preview.motionVideoPreview"
@change="updateSettings"
:name="$t('profileSettings.previewMotionVideos')"
:description="$t('profileSettings.previewMotionVideosDescription')"
/>
<ToggleSwitch
class="item"
v-model="localuser.preview.highQuality"
@change="updateSettings"
:name="$t('profileSettings.highQualityPreview')"
:description="$t('profileSettings.highQualityPreviewDescription')"
/>
<ToggleSwitch
class="item"
v-model="localuser.preview.office"
@change="updateSettings"
:name="$t('profileSettings.previewOffice')"
:description="$t('profileSettings.previewOfficeDescription')"
/>
<ToggleSwitch
class="item"
v-model="localuser.preview.popup"
@change="updateSettings"
:name="$t('profileSettings.popupPreview')"
:description="$t('profileSettings.popupPreviewDescription')"
/>
<ToggleSwitch
class="item"
v-model="localuser.showSelectMultiple"
@change="updateSettings"
:name="$t('profileSettings.showSelectMultiple')"
:description="$t('profileSettings.showSelectMultipleDescription')"
/>
@@ -103,12 +117,14 @@
<ToggleSwitch
class="item"
v-model="localuser.preview.autoplayMedia"
@change="updateSettings"
:name="$t('profileSettings.autoplayMedia')"
:description="$t('profileSettings.autoplayMediaDescription')"
/>
<ToggleSwitch
class="item"
v-model="localuser.editorQuickSave"
@change="updateSettings"
:name="$t('profileSettings.editorQuickSave')"
:description="$t('profileSettings.editorQuickSaveDescription')"
/>
@@ -118,6 +134,7 @@
<ToggleSwitch
class="item"
v-model="localuser.disableSearchOptions"
@change="updateSettings"
:name="$t('profileSettings.disableSearchOptions')"
:description="$t('profileSettings.disableSearchOptionsDescription')"
/>
@@ -128,6 +145,7 @@
v-if="localuser.permissions?.admin"
class="item"
v-model="localuser.disableUpdateNotifications"
@change="updateSettings"
:name="$t('profileSettings.disableUpdateNotifications')"
:description="$t('profileSettings.disableUpdateNotificationsDescription')"
/>
@@ -140,10 +158,10 @@
help
</i>
</div>
<div class="form-group">
<div class="form-flex-group">
<input
class="input input--block form-form flat-right"
:class="{ 'invalid-form': !validateExtensions(formDisablePreviews) }"
class="input form-form flat-right"
:class="{ 'form-invalid': !validateExtensions(formDisablePreviews) }"
type="text"
placeholder="enter file extensions"
id="disablePreviews"
@@ -151,7 +169,7 @@
/>
<button
type="button"
class="button form-button"
class="button form-button flat-left"
@click="submitDisablePreviewsChange"
>
{{ $t("buttons.save") }}
@@ -166,10 +184,10 @@
help
</i>
</div>
<div class="form-group">
<div class="form-flex-group">
<input
class="input input--block form-form flat-right"
:class="{ 'invalid-form': !validateExtensions(formDisabledViewing) }"
class="input form-form flat-right"
:class="{ 'form-invalid': !validateExtensions(formDisabledViewing) }"
type="text"
placeholder="enter file extensions"
id="disableViewing"
@@ -177,7 +195,7 @@
/>
<button
type="button"
class="button form-button"
class="button form-button flat-left"
@click="submitDisabledViewingChange"
>
{{ $t("buttons.save") }}
@@ -192,10 +210,10 @@
help
</i>
</div>
<div class="form-group">
<div class="form-flex-group">
<input
class="input input--block form-form flat-right"
:class="{ 'invalid-form': !validateExtensions(formDisableOfficePreview) }"
class="input form-form flat-right"
:class="{ 'form-invalid': !validateExtensions(formDisableOfficePreview) }"
type="text"
placeholder="enter file extensions"
id="disableOfficePreview"
@@ -203,7 +221,7 @@
/>
<button
type="button"
class="button form-button"
class="button form-button flat-left"
@click="submitDisableOfficePreviewChange"
>
{{ $t("buttons.save") }}
@@ -217,9 +235,9 @@
:initialActive="localuser.themeColor"
/>
<h3 v-if="Object.keys(availableThemes).length > 0">{{ $t("profileSettings.customTheme") }}</h3>
<div v-if="Object.keys(availableThemes).length > 0" class="form-group">
<div v-if="Object.keys(availableThemes).length > 0" class="form-flex-group">
<select
class="input input--block"
class="input"
v-model="selectedTheme"
@change="updateCustomTheme"
>
@@ -234,7 +252,7 @@
</div>
<h3>{{ $t("settings.language") }}</h3>
<Languages
class="input input--block"
class="input"
:locale="localuser.locale"
@update:locale="updateLocale"
></Languages>
@@ -262,7 +280,7 @@ export default {
data() {
return {
localuser: { preview: {}, permissions: {} }, // Initialize localuser with empty objects to avoid undefined errors
initialized: false,
formDisablePreviews: "", // holds temporary input before saving
formDisabledViewing: "", // holds temporary input before saving
formDisableOfficePreview: "", // holds temporary input before saving
@@ -276,17 +294,7 @@ export default {
],
};
},
watch: {
localuser: {
handler: function () {
if (this.initialized) {
this.updateSettings(); // Ensure updateSettings() is called when localuser changes
}
this.initialized = true;
},
deep: true, // Watch nested properties of localuser
},
},
computed: {
availableThemes() {
return userSelectableThemes || {};
@@ -348,6 +356,7 @@ export default {
return;
}
this.localuser.disablePreviewExt = this.formDisablePreviews;
this.updateSettings();
},
submitDisabledViewingChange() {
if (!this.validateExtensions(this.formDisabledViewing)) {
@@ -355,6 +364,7 @@ export default {
return;
}
this.localuser.disableViewingExt = this.formDisabledViewing;
this.updateSettings();
},
submitDisableOfficePreviewChange() {
if (!this.validateExtensions(this.formDisableOfficePreview)) {
@@ -362,9 +372,11 @@ export default {
return;
}
this.localuser.disableOfficePreviewExt = this.formDisableOfficePreview;
this.updateSettings();
},
setColor(string) {
this.localuser.themeColor = string;
this.updateSettings();
},
async updateSettings(event) {
if (event !== undefined) {
@@ -409,6 +421,7 @@ export default {
},
updateLocale(updatedLocale) {
this.localuser.locale = updatedLocale;
this.updateSettings();
},
},
};
+1 -1
View File
@@ -41,7 +41,7 @@
</tbody>
</table>
</div>
<h2 class="message" v-else>
<h2 class="message" v-else-if="!loading">
<i class="material-icons">sentiment_dissatisfied</i>
<span>{{ $t("files.lonely") }}</span>
</h2>
@@ -14,7 +14,7 @@ test('create, check settings, and delete testuser2', async ({
await page.locator('input[aria-label="Password2"]').fill('testpass')
// check that the invalid-field class is added properly
await expect(page.locator('input[aria-label="Password2"]')).toHaveClass(
'input input--block form-form invalid-form'
'input form-form form-invalid'
)
await page.locator('input[aria-label="Password2"]').fill('testpassword')