Merge pull request #300 from EdouardVanbelle/feat/show-shared

This commit is contained in:
Dionisio Pozo
2026-04-17 00:03:04 +02:00
committed by GitHub
7 changed files with 95 additions and 22 deletions
+26 -2
View File
@@ -61,6 +61,10 @@
background-color: var(--color-warning-ring);
}
.file-badge-shared {
color: var(--color-badge-blue-text);
}
/* ------------------File list View --------------------- */
.list-header {
@@ -95,7 +99,7 @@
}
.files-list-view {
--files-list-columns: 36px minmax(200px, 2fr) 100px 110px 130px 64px;
--files-list-columns: 36px minmax(200px, 2fr) 100px 110px 130px 72px;
display: flex;
flex-direction: column;
width: 100%;
@@ -174,7 +178,8 @@
text-align: right;
}
.files-list-view .file-item .action-cell button {
.files-list-view .file-item .action-cell button,
.files-list-view .file-item .action-cell div {
display: inline;
width: 28px;
height: 28px;
@@ -327,6 +332,25 @@
border: 2px dashed var(--color-warning-border);
}
.files-grid-view .file-item .file-badge-shared {
position: absolute;
top: 38px;
right: 38px;
width: 30px;
height: 30px;
border-radius: 8px;
border: none;
background: transparent;
display: flex;
align-items: center;
justify-content: center;
z-index: 12;
font-size: 15px;
padding: 0;
line-height: 1;
}
/* Favorite star (mirrors file-actions button pattern) */
.files-grid-view .file-item button.favorite-star {
position: absolute;
+1 -1
View File
@@ -70,7 +70,7 @@
</a>
<div class="nav-menu">
<div class="nav-item active">
<div class="nav-item">
<i class="fas fa-folder"></i>
<span data-i18n="nav.files">Files</span>
</div>
+3 -1
View File
@@ -376,7 +376,7 @@ function initApp() {
multiSelect.init();
}
window.addEventListener('authenticationDone', () => {
window.addEventListener('authenticationDone', async () => {
// Check if a context was provided in the URL
const hashContext = deserializeHash();
switchSectionTo(hashContext.section);
@@ -389,6 +389,7 @@ function initApp() {
if (hashContext.file !== null) {
app.viewFile = hashContext.file;
}
loadFiles();
}
});
@@ -604,6 +605,7 @@ function setupEventListeners() {
let _updateHistory = true;
const itemI18nKey = item.querySelector('span').getAttribute('data-i18n');
switch (itemI18nKey) {
case 'nav.shared':
// Switch to shared view
+14 -6
View File
@@ -190,10 +190,10 @@ function switchToSharedSection() {
toggleFileContainer(false);
// Show shared view
if (sharedView) {
sharedView.init();
sharedView.init().then(() => {
sharedView.show();
}
});
if (multiSelect) multiSelect.clear();
}
@@ -222,7 +222,10 @@ function switchToFilesSection() {
ui.updateBreadcrumb();
if (multiSelect) multiSelect.clear();
loadFiles();
// temp solution
sharedView.loadItems().then(() => {
loadFiles();
});
}
function switchToFavoritesSection() {
@@ -245,7 +248,10 @@ function switchToFavoritesSection() {
ui.resetFilesList();
if (favorites) {
favorites.displayFavorites();
// temp solution
sharedView.loadItems().then(() => {
favorites.displayFavorites();
});
} else {
console.error('Favorites module not loaded or initialized');
ui.showError(`
@@ -277,7 +283,9 @@ function switchToRecentFilesSection() {
ui.resetFilesList();
if (recent) {
recent.displayRecentFiles();
sharedView.loadItems().then(() => {
favorites.displayFavorites();
});
} else {
console.error('Recent files module not loaded or initialized');
ui.showError(`
+9 -3
View File
@@ -16,6 +16,7 @@ import { wopiEditor } from '../features/files/wopiEditor.js';
import { favorites } from '../features/library/favorites.js';
import { recent } from '../features/library/recent.js';
import { fileSharing } from '../features/sharing/fileSharing.js';
import { sharedView } from '../views/shared/sharedView.js';
import { loadFiles } from './filesView.js';
import { updateHistory } from './main.js';
import { syncViewContainers } from './navigation.js';
@@ -1209,6 +1210,7 @@ const ui = {
el.dataset.parentId = folder.parent_id || '';
const isFav = favorites?.isFavorite(folder.id, 'folder');
const isShared = sharedView.isShared(folder.id, 'folder');
const formattedDate = formatDateTime(folder.modified_at);
el.innerHTML = `
@@ -1219,15 +1221,16 @@ const ui = {
</div>
<span>${escapeHtml(folder.name)}</span>
${isFav ? '<i class="fas fa-star favorite-star-inline"></i>' : ''}
${isShared ? '<div class="file-badge-shared"><i class="fas fa-share-alt"></i></div>' : ''}
</div>
<div class="type-cell">${i18n ? i18n.t('files.file_types.folder') : 'Folder'}</div>
<div class="size-cell">--</div>
<div class="date-cell">${formattedDate}</div>
<div class="action-cell">
<button class="favorite-star${isFav ? ' active' : ''}" data-item-id="${folder.id}" data-item-type="folder" data-item-name="${escapeHtml(folder.name)}">
<button class="favorite-star${isFav ? ' active' : ''}" data-item-id="${folder.id}" data-item-type="folder" data-item-name="${escapeHtml(folder.name)}">
<i class="${isFav ? 'fas' : 'far'} fa-star"></i>
</button>
<button class="file-actions"><i class="fas fa-ellipsis-v"></i></button>
</button>
<button class="file-actions"><i class="fas fa-ellipsis-v"></i></button>
</div>
`;
@@ -1247,6 +1250,7 @@ const ui = {
const fileSize = file.size_formatted || formatFileSize(file.size);
const formattedDate = formatDateTime(file.modified_at);
const isFav = favorites?.isFavorite(file.id, 'file');
const isShared = sharedView.isShared(file.id, 'file');
const el = document.createElement('div');
el.className = 'file-item';
@@ -1265,6 +1269,8 @@ const ui = {
</div>
<span>${escapeHtml(file.name)}</span>
${isFav ? '<i class="fas fa-star favorite-star-inline"></i>' : ''}
${isShared ? '<div class="file-badge-shared"><i class="fas fa-share-alt"></i></div>' : ''}
</div>
<div class="type-cell">${typeLabel}</div>
<div class="size-cell">${fileSize}</div>
+40 -8
View File
@@ -10,9 +10,17 @@ import { formatDateShort } from '../../core/formatters.js';
import { i18n } from '../../core/i18n.js';
import { fileSharing } from '../../features/sharing/fileSharing.js';
const TTL = 5 * 60 * 1000; // 5 min
const sharedView = {
// State
items: [],
_expires: 0,
/** @type {Map<string, boolean>} key = "file:<id>" | "folder:<id>" */
_knownItemsId: new Map(),
filteredItems: [],
currentItem: null,
@@ -23,15 +31,15 @@ const sharedView = {
return h;
},
init() {
async init() {
console.log('Initializing shared view component (API-backed)');
this.loadItems();
await this.loadItems();
},
show() {
this.displayUI();
this.attachEventListeners();
this.loadItems().then(() => this.filterAndSortItems());
this.filterAndSortItems();
const c = document.getElementById('shared-container');
if (c) c.classList.remove('hidden');
},
@@ -41,8 +49,27 @@ const sharedView = {
if (c) c.classList.add('hidden');
},
// Load shared items from backend API
async loadItems() {
/**
* tells if item_id is shared
*
* @param {string} id the item_id
* @param {string} type folder|file
* @returns {boolean} true if this item is shared
*/
isShared(id, type) {
return this._knownItemsId.has(`${type}:${id}`);
},
// Load shared items from backend API,
// TODO cache entries to minimize calls
/**
* load shared items
*
* @param {boolean} force ignore cache
*/
async loadItems(force) {
if (this._expires > Date.now() && !force) return;
try {
const res = await fetch('/api/shares?page=1&per_page=1000', {
headers: this._headers()
@@ -53,11 +80,16 @@ const sharedView = {
} else {
this.items = [];
}
this.filteredItems = { ...this.items };
this._knownItemsId.clear();
this.items.forEach((item) => {
this._knownItemsId.set(`${item.item_type}:${item.item_id}`, true);
});
this._expires = Date.now() + TTL;
} catch (err) {
console.error('Error loading shared items:', err);
this.items = [];
}
this.filteredItems = [...this.items];
},
// Create and display the shared view UI
@@ -559,7 +591,7 @@ const sharedView = {
}
this.closeShareDialog();
await this.loadItems();
await this.loadItems(true);
this.filterAndSortItems();
},
@@ -580,7 +612,7 @@ const sharedView = {
}
this.closeShareDialog();
await this.loadItems();
await this.loadItems(true);
this.filterAndSortItems();
},
+2 -1
View File
@@ -1,5 +1,6 @@
// OxiCloud Service Worker
const CACHE_NAME = 'oxicloud-cache-v17';
// FIXME: generate cache name according build ?
const CACHE_NAME = 'oxicloud-cache-v19';
// Only cache static assets — NOT HTML files.
// HTML files are served network-first so browsers always get the latest