Merge pull request #300 from EdouardVanbelle/feat/show-shared
This commit is contained in:
@@ -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
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user