feat(ui): add section 'Shared with me'
This commit is contained in:
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* Shared-with-me view styles.
|
||||||
|
*
|
||||||
|
* The grid/list rendering reuses the standard `.files-container` / `#files-list`
|
||||||
|
* styles from filesView.css. Only view-specific additions are defined here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ── "Load more" button row ───────────────────────────────────────────────── */
|
||||||
|
.swm-load-more-wrapper {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 16px 0 24px;
|
||||||
|
}
|
||||||
+6
-1
@@ -14,6 +14,7 @@
|
|||||||
<link rel="stylesheet" href="/css/views/favorites.css">
|
<link rel="stylesheet" href="/css/views/favorites.css">
|
||||||
<link rel="stylesheet" href="/css/views/recent.css">
|
<link rel="stylesheet" href="/css/views/recent.css">
|
||||||
<link rel="stylesheet" href="/css/views/shared.css">
|
<link rel="stylesheet" href="/css/views/shared.css">
|
||||||
|
<link rel="stylesheet" href="/css/views/sharedWithMe.css">
|
||||||
<link rel="stylesheet" href="/css/views/trash.css">
|
<link rel="stylesheet" href="/css/views/trash.css">
|
||||||
<link rel="stylesheet" href="/css/views/photos.css">
|
<link rel="stylesheet" href="/css/views/photos.css">
|
||||||
<link rel="stylesheet" href="/css/views/photosLightbox.css">
|
<link rel="stylesheet" href="/css/views/photosLightbox.css">
|
||||||
@@ -76,9 +77,13 @@
|
|||||||
<span data-i18n="nav.files">Files</span>
|
<span data-i18n="nav.files">Files</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-item" id="nav-shared">
|
<div class="nav-item" id="nav-shared">
|
||||||
<i class="fas fa-share-alt"></i>
|
<i class="fas fa-oxiexport"></i>
|
||||||
<span data-i18n="nav.shared">Shared</span>
|
<span data-i18n="nav.shared">Shared</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="nav-item" id="nav-sharedwithme">
|
||||||
|
<i class="fas fa-oxiimport"></i>
|
||||||
|
<span data-i18n="nav.sharedwithme">Shared with me</span>
|
||||||
|
</div>
|
||||||
<div class="nav-item">
|
<div class="nav-item">
|
||||||
<i class="fas fa-clock"></i>
|
<i class="fas fa-clock"></i>
|
||||||
<span data-i18n="nav.recent">Recent</span>
|
<span data-i18n="nav.recent">Recent</span>
|
||||||
|
|||||||
@@ -42,7 +42,17 @@ async function getFolder(id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rebuild breadcrumb from selected folder (iterate up to root)
|
* Rebuild breadcrumb from selected folder (iterate up to root).
|
||||||
|
*
|
||||||
|
* Stops traversal gracefully when a parent folder is not accessible
|
||||||
|
* (e.g. the user entered via a "Shared with me" grant whose parent
|
||||||
|
* folder they have no permission on). In that case the partial
|
||||||
|
* breadcrumb built so far is kept — the deepest reachable ancestor
|
||||||
|
* acts as the visual root, matching how Google Drive / Dropbox handle
|
||||||
|
* shared subtrees.
|
||||||
|
*
|
||||||
|
* An error on the *target folder itself* (first iteration) is still
|
||||||
|
* treated as a real error and redirects to the home folder.
|
||||||
*/
|
*/
|
||||||
async function rebuildBreadCrumb() {
|
async function rebuildBreadCrumb() {
|
||||||
/**
|
/**
|
||||||
@@ -80,12 +90,19 @@ async function rebuildBreadCrumb() {
|
|||||||
// iterate to parent folder
|
// iterate to parent folder
|
||||||
id = folderInfo.parent_id;
|
id = folderInfo.parent_id;
|
||||||
} catch (_e) {
|
} catch (_e) {
|
||||||
console.log(`Error loading information from folder ${app.currentPath}, falling back to ${app.userHomeFolderId}`);
|
if (currentFolderInfo === null) {
|
||||||
// fallback of root
|
// Failed on the target folder itself — real error, fall back to home.
|
||||||
|
console.warn(`Cannot access target folder ${app.currentPath}, falling back to home`);
|
||||||
uiNotifications.show('error: folder not found or permission denied', 'the given folder is not available or you do not have sufficient rights');
|
uiNotifications.show('error: folder not found or permission denied', 'the given folder is not available or you do not have sufficient rights');
|
||||||
app.breadcrumbPath = [];
|
app.breadcrumbPath = [];
|
||||||
id = app.userHomeFolderId;
|
id = app.userHomeFolderId;
|
||||||
if (id) app.currentPath = id;
|
if (id) app.currentPath = id;
|
||||||
|
} else {
|
||||||
|
// Failed on a parent — hit the permission boundary of a shared subtree.
|
||||||
|
// Stop traversal; the partial breadcrumb is the best we can show.
|
||||||
|
console.log(`Stopped breadcrumb traversal at permission boundary (parent of ${currentFolderInfo.id} is not accessible)`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+21
-1
@@ -16,10 +16,12 @@ import { multiSelect } from '../features/files/multiSelect.js';
|
|||||||
import { favorites } from '../features/library/favorites.js';
|
import { favorites } from '../features/library/favorites.js';
|
||||||
import { recent } from '../features/library/recent.js';
|
import { recent } from '../features/library/recent.js';
|
||||||
import { fileSharing } from '../features/sharing/fileSharing.js';
|
import { fileSharing } from '../features/sharing/fileSharing.js';
|
||||||
|
import { grants } from '../model/grants.js';
|
||||||
import { sharedView } from '../views/shared/sharedView.js';
|
import { sharedView } from '../views/shared/sharedView.js';
|
||||||
import { checkAuthentication } from './authSession.js';
|
import { checkAuthentication } from './authSession.js';
|
||||||
import { loadFiles } from './filesView.js';
|
import { loadFiles } from './filesView.js';
|
||||||
import {
|
import {
|
||||||
|
activateFilesUI,
|
||||||
SECTIONS_MAPPER,
|
SECTIONS_MAPPER,
|
||||||
switchToFavoritesSection,
|
switchToFavoritesSection,
|
||||||
switchToFilesSection,
|
switchToFilesSection,
|
||||||
@@ -27,6 +29,7 @@ import {
|
|||||||
switchToPhotosSection,
|
switchToPhotosSection,
|
||||||
switchToRecentFilesSection,
|
switchToRecentFilesSection,
|
||||||
switchToSharedSection,
|
switchToSharedSection,
|
||||||
|
switchToSharedWithMeSection,
|
||||||
switchToTrashSection
|
switchToTrashSection
|
||||||
} from './navigation.js';
|
} from './navigation.js';
|
||||||
import { performSearch } from './searchView.js';
|
import { performSearch } from './searchView.js';
|
||||||
@@ -140,12 +143,16 @@ const ACTIONS_BAR_TEMPLATES = {
|
|||||||
</div>
|
</div>
|
||||||
${_multiSelectButons}
|
${_multiSelectButons}
|
||||||
${_toggleButtons}
|
${_toggleButtons}
|
||||||
|
`,
|
||||||
|
sharedwithme: `
|
||||||
|
<div class="action-buttons" id="default-buttons"></div>
|
||||||
|
${_toggleButtons}
|
||||||
`
|
`
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {'files' | 'trash' | 'favorites' | 'recent' | 'hidden'} mode
|
* @param {'files' | 'trash' | 'favorites' | 'recent' | 'sharedwithme' | 'hidden'} mode
|
||||||
* @param {boolean} [force=false]
|
* @param {boolean} [force=false]
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
@@ -398,6 +405,9 @@ function initApp() {
|
|||||||
app.viewFile = hashContext.file;
|
app.viewFile = hashContext.file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get grants (xxx: async methods)
|
||||||
|
await grants.fetchIncomingGrants();
|
||||||
|
await grants.fetchOutgoingGrants();
|
||||||
loadFiles();
|
loadFiles();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -652,6 +662,10 @@ function setupEventListeners() {
|
|||||||
switchToSharedSection();
|
switchToSharedSection();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'nav.sharedwithme':
|
||||||
|
switchToSharedWithMeSection();
|
||||||
|
break;
|
||||||
|
|
||||||
case 'nav.favorites':
|
case 'nav.favorites':
|
||||||
// Switch to favorites view
|
// Switch to favorites view
|
||||||
switchToFavoritesSection();
|
switchToFavoritesSection();
|
||||||
@@ -723,6 +737,12 @@ function setupEventListeners() {
|
|||||||
* @param {string} name
|
* @param {string} name
|
||||||
*/
|
*/
|
||||||
export function selectFolder(id, name) {
|
export function selectFolder(id, name) {
|
||||||
|
// When entering from a non-files section (e.g. "Shared with me"),
|
||||||
|
// activate the Files UI (nav active state, breadcrumb, action bar,
|
||||||
|
// container) without resetting the current path.
|
||||||
|
if (app.currentSection !== 'files') {
|
||||||
|
activateFilesUI();
|
||||||
|
}
|
||||||
app.breadcrumbPath.push({ id, name });
|
app.breadcrumbPath.push({ id, name });
|
||||||
app.currentPath = id;
|
app.currentPath = id;
|
||||||
ui.updateBreadcrumb();
|
ui.updateBreadcrumb();
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { musicView } from '../features/library/music.js';
|
|||||||
import { photosView } from '../features/library/photos.js';
|
import { photosView } from '../features/library/photos.js';
|
||||||
import { recent } from '../features/library/recent.js';
|
import { recent } from '../features/library/recent.js';
|
||||||
import { sharedView } from '../views/shared/sharedView.js';
|
import { sharedView } from '../views/shared/sharedView.js';
|
||||||
|
import { sharedWithMeView } from '../views/sharedWithMe/sharedWithMeView.js';
|
||||||
import { loadFiles } from './filesView.js';
|
import { loadFiles } from './filesView.js';
|
||||||
import { setActionsBarMode } from './main.js';
|
import { setActionsBarMode } from './main.js';
|
||||||
import { app, appElements } from './state.js';
|
import { app, appElements } from './state.js';
|
||||||
@@ -122,6 +123,7 @@ function getSectionFromNavItem(navItem) {
|
|||||||
export const SECTIONS_MAPPER = {
|
export const SECTIONS_MAPPER = {
|
||||||
files: switchToFilesSection,
|
files: switchToFilesSection,
|
||||||
shared: switchToSharedSection,
|
shared: switchToSharedSection,
|
||||||
|
sharedwithme: switchToSharedWithMeSection,
|
||||||
recent: switchToRecentFilesSection,
|
recent: switchToRecentFilesSection,
|
||||||
favorites: switchToFavoritesSection,
|
favorites: switchToFavoritesSection,
|
||||||
trash: switchToTrashSection,
|
trash: switchToTrashSection,
|
||||||
@@ -157,6 +159,11 @@ function setCurrentSection(section) {
|
|||||||
sharedView.hide();
|
sharedView.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hide "Load more" button when leaving the sharedwithme section
|
||||||
|
if (section !== 'sharedwithme' && sharedWithMeView) {
|
||||||
|
sharedWithMeView.hide();
|
||||||
|
}
|
||||||
|
|
||||||
// Hide photosView when switching to any other section
|
// Hide photosView when switching to any other section
|
||||||
if (section !== 'photos' && photosView) {
|
if (section !== 'photos' && photosView) {
|
||||||
photosView.hide();
|
photosView.hide();
|
||||||
@@ -194,6 +201,26 @@ function switchToSharedSection() {
|
|||||||
if (multiSelect) multiSelect.clear();
|
if (multiSelect) multiSelect.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function switchToSharedWithMeSection() {
|
||||||
|
if (!setCurrentSection('sharedwithme')) return;
|
||||||
|
|
||||||
|
// Hide breadcrumb (only shown in Files view)
|
||||||
|
const breadcrumb = document.querySelector('.breadcrumb');
|
||||||
|
breadcrumb?.classList.add('hidden');
|
||||||
|
|
||||||
|
// Show actions-bar with view toggle (no upload / new-folder in this view)
|
||||||
|
setActionsBarMode('sharedwithme');
|
||||||
|
|
||||||
|
// Show the standard files container and respect grid/list preference
|
||||||
|
toggleFileContainer(true);
|
||||||
|
syncViewContainers();
|
||||||
|
|
||||||
|
if (multiSelect) multiSelect.clear();
|
||||||
|
|
||||||
|
// Load and render items into the files container
|
||||||
|
sharedWithMeView.init();
|
||||||
|
}
|
||||||
|
|
||||||
function switchToFilesSection() {
|
function switchToFilesSection() {
|
||||||
if (!setCurrentSection('files')) return;
|
if (!setCurrentSection('files')) return;
|
||||||
|
|
||||||
@@ -368,13 +395,34 @@ function switchToMusicSection() {
|
|||||||
if (multiSelect) multiSelect.clear();
|
if (multiSelect) multiSelect.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activate the Files section UI (nav state, breadcrumb, actions bar,
|
||||||
|
* files container, grid/list sync) WITHOUT resetting `app.currentPath`
|
||||||
|
* or `app.breadcrumbPath`.
|
||||||
|
*
|
||||||
|
* Used by `selectFolder` when the user clicks a folder from a
|
||||||
|
* non-files section (e.g. "Shared with me") so the Files view is
|
||||||
|
* fully set up before the folder content loads.
|
||||||
|
*/
|
||||||
|
function activateFilesUI() {
|
||||||
|
setCurrentSection('files');
|
||||||
|
setActionsBarMode('files', true);
|
||||||
|
const breadcrumb = document.querySelector('.breadcrumb');
|
||||||
|
breadcrumb?.classList.remove('hidden');
|
||||||
|
toggleFileContainer(true);
|
||||||
|
syncViewContainers();
|
||||||
|
if (multiSelect) multiSelect.clear();
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
activateFilesUI,
|
||||||
switchToFavoritesSection,
|
switchToFavoritesSection,
|
||||||
switchToFilesSection,
|
switchToFilesSection,
|
||||||
switchToMusicSection,
|
switchToMusicSection,
|
||||||
switchToPhotosSection,
|
switchToPhotosSection,
|
||||||
switchToRecentFilesSection,
|
switchToRecentFilesSection,
|
||||||
switchToSharedSection,
|
switchToSharedSection,
|
||||||
|
switchToSharedWithMeSection,
|
||||||
switchToTrashSection,
|
switchToTrashSection,
|
||||||
syncViewContainers
|
syncViewContainers
|
||||||
};
|
};
|
||||||
|
|||||||
+15
-9
@@ -17,10 +17,10 @@ import { favorites } from '../features/library/favorites.js';
|
|||||||
import { recent } from '../features/library/recent.js';
|
import { recent } from '../features/library/recent.js';
|
||||||
import { fileSharing } from '../features/sharing/fileSharing.js';
|
import { fileSharing } from '../features/sharing/fileSharing.js';
|
||||||
import { thumbnail } from '../features/thumbnail.js';
|
import { thumbnail } from '../features/thumbnail.js';
|
||||||
import { sharedView } from '../views/shared/sharedView.js';
|
import { grants } from '../model/grants.js';
|
||||||
import { loadFiles } from './filesView.js';
|
import { loadFiles } from './filesView.js';
|
||||||
import { updateHistory } from './main.js';
|
import { updateHistory } from './main.js';
|
||||||
import { switchToFilesSection, syncViewContainers } from './navigation.js';
|
import { activateFilesUI, switchToFilesSection, syncViewContainers } from './navigation.js';
|
||||||
import { app } from './state.js';
|
import { app } from './state.js';
|
||||||
import { uiFileTypes } from './uiFileTypes.js';
|
import { uiFileTypes } from './uiFileTypes.js';
|
||||||
import { uiNotifications } from './uiNotifications.js';
|
import { uiNotifications } from './uiNotifications.js';
|
||||||
@@ -54,7 +54,7 @@ const ui = {
|
|||||||
<i class="fas fa-star"></i> <span data-i18n="actions.favorite">Add to favorites</span>
|
<i class="fas fa-star"></i> <span data-i18n="actions.favorite">Add to favorites</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="context-menu-item" id="share-folder-option">
|
<div class="context-menu-item" id="share-folder-option">
|
||||||
<i class="fas fa-share-alt"></i> <span data-i18n="actions.share">Share</span>
|
<i class="fas fa-oxiexport"></i> <span data-i18n="actions.share">Share</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="context-menu-separator"></div>
|
<div class="context-menu-separator"></div>
|
||||||
<div class="context-menu-item" id="rename-folder-option">
|
<div class="context-menu-item" id="rename-folder-option">
|
||||||
@@ -98,7 +98,7 @@ const ui = {
|
|||||||
<i class="fas fa-star"></i> <span data-i18n="actions.favorite">Add to favorites</span>
|
<i class="fas fa-star"></i> <span data-i18n="actions.favorite">Add to favorites</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="context-menu-item" id="share-file-option">
|
<div class="context-menu-item" id="share-file-option">
|
||||||
<i class="fas fa-share-alt"></i> <span data-i18n="actions.share">Share</span>
|
<i class="fas fa-oxiexport"></i> <span data-i18n="actions.share">Share</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="context-menu-item hidden" id="add-to-playlist-option">
|
<div class="context-menu-item hidden" id="add-to-playlist-option">
|
||||||
<i class="fas fa-compact-disc"></i> <span data-i18n="music.add_to_playlist">Add to Playlist</span>
|
<i class="fas fa-compact-disc"></i> <span data-i18n="music.add_to_playlist">Add to Playlist</span>
|
||||||
@@ -154,7 +154,7 @@ const ui = {
|
|||||||
shareDialog.innerHTML = `
|
shareDialog.innerHTML = `
|
||||||
<div class="share-dialog-content">
|
<div class="share-dialog-content">
|
||||||
<div class="share-dialog-header">
|
<div class="share-dialog-header">
|
||||||
<i class="fas fa-share-alt dialog-header-icon"></i>
|
<i class="fas fa-oxiexport dialog-header-icon"></i>
|
||||||
<span data-i18n="dialogs.share_file">Share file</span>
|
<span data-i18n="dialogs.share_file">Share file</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="shared-item-info">
|
<div class="shared-item-info">
|
||||||
@@ -937,6 +937,11 @@ const ui = {
|
|||||||
loadFiles();
|
loadFiles();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (app.currentSection === 'sharedwithme') {
|
||||||
|
// Activate Files UI (nav, breadcrumb, actions bar) without
|
||||||
|
// resetting the path — the shared folder becomes the entry point.
|
||||||
|
activateFilesUI();
|
||||||
|
}
|
||||||
app.breadcrumbPath.push({ id: folderId, name: folderName });
|
app.breadcrumbPath.push({ id: folderId, name: folderName });
|
||||||
app.currentPath = folderId;
|
app.currentPath = folderId;
|
||||||
this.updateBreadcrumb();
|
this.updateBreadcrumb();
|
||||||
@@ -1334,7 +1339,7 @@ const ui = {
|
|||||||
if (folder.path) el.dataset.path = folder.path;
|
if (folder.path) el.dataset.path = folder.path;
|
||||||
|
|
||||||
const isFav = favorites?.isFavorite(folder.id, 'folder');
|
const isFav = favorites?.isFavorite(folder.id, 'folder');
|
||||||
const isShared = sharedView.isShared(folder.id, 'folder');
|
const isShared = grants.getOutgoingGrantsFor('folder', folder.id).length > 0; //sharedView.isShared(folder.id, 'folder');
|
||||||
const formattedDate = formatDateTime(folder.modified_at);
|
const formattedDate = formatDateTime(folder.modified_at);
|
||||||
|
|
||||||
el.innerHTML = `
|
el.innerHTML = `
|
||||||
@@ -1345,7 +1350,7 @@ const ui = {
|
|||||||
</div>
|
</div>
|
||||||
<span>${escapeHtml(folder.name)}</span>
|
<span>${escapeHtml(folder.name)}</span>
|
||||||
<div class="file-badge file-badge-favorite ${isFav ? '' : 'hidden'}"><i class="fas fa-star favorite-star-inline"></i></div>
|
<div class="file-badge file-badge-favorite ${isFav ? '' : 'hidden'}"><i class="fas fa-star favorite-star-inline"></i></div>
|
||||||
<div class="file-badge file-badge-shared ${isShared ? '' : 'hidden'}"><i class="fas fa-share-alt"></i></div>
|
<div class="file-badge file-badge-shared ${isShared ? '' : 'hidden'}"><i class="fas fa-oxiexport"></i></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="type-cell">${i18n.t('files.file_types.folder')}</div>
|
<div class="type-cell">${i18n.t('files.file_types.folder')}</div>
|
||||||
<div class="size-cell">--</div>
|
<div class="size-cell">--</div>
|
||||||
@@ -1377,7 +1382,8 @@ const ui = {
|
|||||||
const fileSize = file.size_formatted || formatFileSize(file.size);
|
const fileSize = file.size_formatted || formatFileSize(file.size);
|
||||||
const formattedDate = formatDateTime(file.modified_at);
|
const formattedDate = formatDateTime(file.modified_at);
|
||||||
const isFav = favorites?.isFavorite(file.id, 'file');
|
const isFav = favorites?.isFavorite(file.id, 'file');
|
||||||
const isShared = sharedView.isShared(file.id, 'file');
|
const isShared = grants.getOutgoingGrantsFor('file', file.id).length > 0;
|
||||||
|
//const isShared = sharedView.isShared(file.id, 'file');
|
||||||
const canThumbnail = thumbnail.canHandle(file);
|
const canThumbnail = thumbnail.canHandle(file);
|
||||||
|
|
||||||
const el = document.createElement('div');
|
const el = document.createElement('div');
|
||||||
@@ -1398,7 +1404,7 @@ const ui = {
|
|||||||
</div>
|
</div>
|
||||||
<span>${escapeHtml(file.name)}</span>
|
<span>${escapeHtml(file.name)}</span>
|
||||||
<div class="file-badge file-badge-favorite ${isFav ? '' : 'hidden'}"><i class="fas fa-star favorite-star-inline"></i></div>
|
<div class="file-badge file-badge-favorite ${isFav ? '' : 'hidden'}"><i class="fas fa-star favorite-star-inline"></i></div>
|
||||||
<div class="file-badge file-badge-shared ${isShared ? '' : 'hidden'}"><i class="fas fa-share-alt"></i></div>
|
<div class="file-badge file-badge-shared ${isShared ? '' : 'hidden'}"><i class="fas fa-oxiexport"></i></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="type-cell">${typeLabel}</div>
|
<div class="type-cell">${typeLabel}</div>
|
||||||
<div class="size-cell">${fileSize}</div>
|
<div class="size-cell">${fileSize}</div>
|
||||||
|
|||||||
@@ -246,6 +246,14 @@ const OxiIcons = {
|
|||||||
384,
|
384,
|
||||||
'M223.5 32C100 32 0 132.3 0 256S100 480 223.5 480c60.6 0 115.5-24.2 155.8-63.4c5-4.9 6.3-12.5 3.1-18.7s-10.1-9.7-17-8.5c-9.8 1.7-19.8 2.6-30.1 2.6c-96.9 0-175.5-78.8-175.5-176c0-65.8 36-123.1 89.3-153.3c6.1-3.5 9.2-10.5 7.7-17.3s-7.3-11.9-14.3-12.5c-6.3-.5-12.6-.8-19-.8z'
|
'M223.5 32C100 32 0 132.3 0 256S100 480 223.5 480c60.6 0 115.5-24.2 155.8-63.4c5-4.9 6.3-12.5 3.1-18.7s-10.1-9.7-17-8.5c-9.8 1.7-19.8 2.6-30.1 2.6c-96.9 0-175.5-78.8-175.5-176c0-65.8 36-123.1 89.3-153.3c6.1-3.5 9.2-10.5 7.7-17.3s-7.3-11.9-14.3-12.5c-6.3-.5-12.6-.8-19-.8z'
|
||||||
],
|
],
|
||||||
|
oxiexport: [
|
||||||
|
576,
|
||||||
|
'M384.5 24l0 72-64 0c-79.5 0-144 64.5-144 144 0 93.4 82.8 134.8 100.6 142.6 2.2 1 4.6 1.4 7.1 1.4l2.5 0c9.8 0 17.8-8 17.8-17.8 0-8.3-5.9-15.5-12.8-20.3-8.9-6.2-19.2-18.2-19.2-40.5 0-45 36.5-81.5 81.5-81.5l30.5 0 0 72c0 9.7 5.8 18.5 14.8 22.2s19.3 1.7 26.2-5.2l136-136c9.4-9.4 9.4-24.6 0-33.9L425.5 7c-6.9-6.9-17.2-8.9-26.2-5.2S384.5 14.3 384.5 24zm-272 72c-44.2 0-80 35.8-80 80l0 256c0 44.2 35.8 80 80 80l256 0c44.2 0 80-35.8 80-80l0-32c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 32c0 8.8-7.2 16-16 16l-256 0c-8.8 0-16-7.2-16-16l0-256c0-8.8 7.2-16 16-16l16 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-16 0z'
|
||||||
|
],
|
||||||
|
oxiimport: [
|
||||||
|
576,
|
||||||
|
'm 360.55,24 v 72 h 64 c 79.5,0 144,64.5 144,144 0,93.4 -82.8,134.8 -100.6,142.6 -2.2,1 -4.6,1.4 -7.1,1.4 h -2.5 c -9.8,0 -17.8,-8 -17.8,-17.8 0,-8.3 5.9,-15.5 12.8,-20.3 8.9,-6.2 19.2,-18.2 19.2,-40.5 0,-45 -36.5,-81.5 -81.5,-81.5 h -30.5 v 72 c 0,9.7 -5.8,18.5 -14.8,22.2 -9,3.7 -19.3,1.7 -26.2,-5.2 l -136,-136 c -9.4,-9.4 -9.4,-24.6 0,-33.9 l 136,-136 c 6.9,-6.9 17.2,-8.9 26.2,-5.2 9,3.7 14.8,12.5 14.8,22.2 z M 112.5,96 c -44.2,0 -80,35.8 -80,80 v 256 c 0,44.2 35.8,80 80,80 h 256 c 44.2,0 80,-35.8 80,-80 v -32 c 0,-17.7 -14.3,-32 -32,-32 -17.7,0 -32,14.3 -32,32 v 32 c 0,8.8 -7.2,16 -16,16 h -256 c -8.8,0 -16,-7.2 -16,-16 V 176 c 0,-8.8 7.2,-16 16,-16 h 16 c 17.7,0 32,-14.3 32,-32 0,-17.7 -14.3,-32 -32,-32 z'
|
||||||
|
],
|
||||||
pen: [
|
pen: [
|
||||||
512,
|
512,
|
||||||
'M362.7 19.3L314.3 67.7 444.3 197.7l48.4-48.4c25-25 25-65.5 0-90.5L453.3 19.3c-25-25-65.5-25-90.5 0zm-71 71L58.6 323.5c-10.4 10.4-18 23.3-22.2 37.4L1 481.2C-1.5 489.7 .8 498.8 7 505s15.3 8.5 23.7 6.1l120.3-35.4c14.1-4.2 27-11.8 37.4-22.2L421.7 220.3 291.7 90.3z'
|
'M362.7 19.3L314.3 67.7 444.3 197.7l48.4-48.4c25-25 25-65.5 0-90.5L453.3 19.3c-25-25-65.5-25-90.5 0zm-71 71L58.6 323.5c-10.4 10.4-18 23.3-22.2 37.4L1 481.2C-1.5 489.7 .8 498.8 7 505s15.3 8.5 23.7 6.1l120.3-35.4c14.1-4.2 27-11.8 37.4-22.2L421.7 220.3 291.7 90.3z'
|
||||||
|
|||||||
@@ -253,3 +253,63 @@
|
|||||||
* @property {number|null} width
|
* @property {number|null} width
|
||||||
* @property {number|null} height
|
* @property {number|null} height
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// ------------------- grants
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {'read'|'create'|'share'|'comment'|'delete'|'update'} PermissionTypeEnum
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {'folder'|'file'} ResourceTypeEnum
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} Resource
|
||||||
|
* @property {ResourceTypeEnum} type
|
||||||
|
* @property {String} id
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {'user'|'group'|'external'} SubjectTypeEnum
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} Subject
|
||||||
|
* @property {SubjectTypeEnum} type
|
||||||
|
* @property {String} id
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} Grant
|
||||||
|
* @property {string} id
|
||||||
|
* @property {number} granted_at
|
||||||
|
* @property {string} granted_by
|
||||||
|
* @property {Subject} subject
|
||||||
|
* @property {PermissionTypeEnum} permission
|
||||||
|
* @property {Resource} resource
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Roles: `viewer`, `commenter`, `editor`, `manager`, `admin`
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One item returned by `GET /api/grants/incoming/resources`.
|
||||||
|
* Exactly one of `file` / `folder` is populated (indicated by `resource_type`).
|
||||||
|
* @typedef {Object} SharedWithMeItem
|
||||||
|
* @property {ResourceTypeEnum} resource_type
|
||||||
|
* @property {PermissionTypeEnum[]} permissions - All permissions the caller holds on this resource.
|
||||||
|
* @property {string} granted_at - ISO-8601 timestamp of the earliest grant.
|
||||||
|
* @property {string} granted_by - UUID of the user who created the grant.
|
||||||
|
* @property {FileItem|undefined} [file] - Populated when resource_type === 'file'.
|
||||||
|
* @property {FolderItem|undefined} [folder] - Populated when resource_type === 'folder'.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response for `GET /api/grants/incoming/resources`.
|
||||||
|
* @typedef {Object} SharedWithMeResponse
|
||||||
|
* @property {SharedWithMeItem[]} items
|
||||||
|
* @property {string|undefined} [next_cursor] - Absent when the last page is reached.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
/**
|
||||||
|
* @import {Grant, ResourceTypeEnum, SharedWithMeResponse} from '../core/types.js'
|
||||||
|
*/
|
||||||
|
|
||||||
|
const grants = {
|
||||||
|
/** @type {Record<String, Record<String, Grant[]>>} */
|
||||||
|
outgoingGrants: {},
|
||||||
|
|
||||||
|
/** @type {Record<String, Record<String, Grant[]>>} */
|
||||||
|
incomingGrants: {},
|
||||||
|
|
||||||
|
async fetchOutgoingGrants() {
|
||||||
|
const response = await fetch('/api/grants/outgoing');
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
console.log(`error ${response.status} while fetching /api/grants/outgoing:`, await response.json());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {Grant[]} */
|
||||||
|
const outgoingGrants = await response.json();
|
||||||
|
|
||||||
|
console.log(outgoingGrants);
|
||||||
|
|
||||||
|
// store grants by type, then by id
|
||||||
|
outgoingGrants.forEach((grant) => {
|
||||||
|
this.outgoingGrants[grant.resource.type] ??= {};
|
||||||
|
this.outgoingGrants[grant.resource.type][grant.resource.id] ??= [];
|
||||||
|
this.outgoingGrants[grant.resource.type][grant.resource.id].push(grant);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`outgoing grants: `, this.outgoingGrants);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get grant for a resource
|
||||||
|
* @param {ResourceTypeEnum} resourceType
|
||||||
|
* @param {String} id
|
||||||
|
* @returns {Grant[] | null}
|
||||||
|
*/
|
||||||
|
getOutgoingGrantsFor(resourceType, id) {
|
||||||
|
try {
|
||||||
|
return this.outgoingGrants[resourceType][id] ?? [];
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async fetchIncomingGrants() {
|
||||||
|
const response = await fetch('/api/grants/incoming');
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
console.log(`error ${response.status} while fetching /api/grants/incoming:`, await response.json);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {Grant[]} */
|
||||||
|
const incomingGrants = await response.json();
|
||||||
|
|
||||||
|
// store grants by type, then by id
|
||||||
|
incomingGrants.forEach((grant) => {
|
||||||
|
this.incomingGrants[grant.resource.type] ??= {};
|
||||||
|
this.incomingGrants[grant.resource.type][grant.resource.id] ??= [];
|
||||||
|
this.incomingGrants[grant.resource.type][grant.resource.id].push(grant);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`incoming grants: `, this.incomingGrants);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get grant for a resource
|
||||||
|
* @param {ResourceTypeEnum} resourceType
|
||||||
|
* @param {String} id
|
||||||
|
* @returns {Grant[] | null}
|
||||||
|
*/
|
||||||
|
getIncomingGrantsFor(resourceType, id) {
|
||||||
|
try {
|
||||||
|
return this.incomingGrants[resourceType][id] ?? [];
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a cursor-paginated list of resources shared with the current user,
|
||||||
|
* with full file / folder metadata resolved server-side.
|
||||||
|
*
|
||||||
|
* @param {object} [opts]
|
||||||
|
* @param {ResourceTypeEnum[]} [opts.resourceTypes] - Resource types to include (default: ['file','folder']).
|
||||||
|
* @param {number} [opts.limit] - Max items per page (1–200, default 50).
|
||||||
|
* @param {string} [opts.cursor] - Opaque cursor from a previous call; omit for first page.
|
||||||
|
* @returns {Promise<SharedWithMeResponse>}
|
||||||
|
*/
|
||||||
|
async fetchSharedWithMe({ resourceTypes = ['file', 'folder'], limit = 50, cursor } = {}) {
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
limit: String(limit),
|
||||||
|
resource_types: resourceTypes.join(',')
|
||||||
|
});
|
||||||
|
if (cursor) params.set('cursor', cursor);
|
||||||
|
|
||||||
|
const response = await fetch(`/api/grants/incoming/resources?${params}`);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Failed to fetch shared-with-me items: HTTP ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export { grants };
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
/**
|
||||||
|
* OxiCloud – "Shared with me" view.
|
||||||
|
*
|
||||||
|
* Renders files and folders that other users have explicitly granted the
|
||||||
|
* current user access to, using the cursor-paginated
|
||||||
|
* `GET /api/grants/incoming/resources` endpoint.
|
||||||
|
*
|
||||||
|
* Reuses the existing `#files-list` container and `ui.renderFolders` /
|
||||||
|
* `ui.renderFiles` so the grid ↔ list toggle and all card components work
|
||||||
|
* out of the box. A "Load more" button is injected below the files container
|
||||||
|
* for cursor-based pagination.
|
||||||
|
*
|
||||||
|
* NOTE: the grid/list container will be extracted into a reusable component
|
||||||
|
* in a future refactor — this view is intentionally kept thin.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ui } from '../../app/ui.js';
|
||||||
|
import { i18n } from '../../core/i18n.js';
|
||||||
|
import { ownerTooltip } from '../../features/ownerTooltip.js';
|
||||||
|
import { multiSelect } from '../../features/files/multiSelect.js';
|
||||||
|
import { grants } from '../../model/grants.js';
|
||||||
|
import { systemUsers } from '../../model/systemUsers.js';
|
||||||
|
|
||||||
|
/** @import {SharedWithMeItem, FileItem, FolderItem, ResourceTypeEnum} from '../../core/types.js' */
|
||||||
|
|
||||||
|
/** ID of the "Load more" wrapper injected below `.files-container`. */
|
||||||
|
const LOAD_MORE_ID = 'swm-load-more-wrapper';
|
||||||
|
|
||||||
|
const sharedWithMeView = {
|
||||||
|
// ── State ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/** @type {string|null} */
|
||||||
|
_nextCursor: null,
|
||||||
|
|
||||||
|
_loading: false,
|
||||||
|
|
||||||
|
// ── Public API ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Re-)load from page 1 and render into the existing files container.
|
||||||
|
* Called every time the user switches to this section.
|
||||||
|
*/
|
||||||
|
async init() {
|
||||||
|
this._nextCursor = null;
|
||||||
|
this._loading = false;
|
||||||
|
|
||||||
|
this._ensureLoadMoreButton();
|
||||||
|
|
||||||
|
// Start fetching system users in background so tooltips resolve instantly
|
||||||
|
// by the time the user hovers over an item.
|
||||||
|
systemUsers.prefetch();
|
||||||
|
|
||||||
|
// Standard files-view setup: clear list, show container, init multiselect
|
||||||
|
ui.resetFilesList();
|
||||||
|
multiSelect.init();
|
||||||
|
ui.updateBreadcrumb();
|
||||||
|
|
||||||
|
await this._loadPage();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide the "Load more" button when leaving this section.
|
||||||
|
* The files container itself is managed by navigation.js.
|
||||||
|
*/
|
||||||
|
hide() {
|
||||||
|
const w = document.getElementById(LOAD_MORE_ID);
|
||||||
|
if (w) w.classList.add('hidden');
|
||||||
|
|
||||||
|
const filesList = document.getElementById('files-list');
|
||||||
|
if (filesList) ownerTooltip.destroy(filesList);
|
||||||
|
},
|
||||||
|
|
||||||
|
// ── Internal helpers ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch one page, map items → FileItem / FolderItem, render them, then
|
||||||
|
* stamp `data-owner-id` and wire the owner tooltip.
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async _loadPage() {
|
||||||
|
if (this._loading) return;
|
||||||
|
this._loading = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await grants.fetchSharedWithMe({
|
||||||
|
resourceTypes: /** @type {ResourceTypeEnum[]} */ (['file', 'folder']),
|
||||||
|
limit: 50,
|
||||||
|
cursor: this._nextCursor ?? undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
this._nextCursor = data.next_cursor ?? null;
|
||||||
|
|
||||||
|
if (data.items.length === 0 && !this._nextCursor) {
|
||||||
|
// First page came back empty
|
||||||
|
ui.showError(`
|
||||||
|
<i class="fas fa-inbox empty-state-icon"></i>
|
||||||
|
<p>${i18n.t('sharedwithme_emptyStateTitle', 'Nothing shared with you yet')}</p>
|
||||||
|
<p>${i18n.t('sharedwithme_emptyStateDesc', 'Items shared with you by other users will appear here')}</p>
|
||||||
|
`);
|
||||||
|
this._setLoadMoreVisible(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { folders, files, ownerMap } = this._mapItems(data.items);
|
||||||
|
if (folders.length) ui.renderFolders(folders);
|
||||||
|
if (files.length) ui.renderFiles(files);
|
||||||
|
|
||||||
|
// Stamp data-owner-id on the freshly-rendered cards and attach tooltips.
|
||||||
|
const filesList = document.getElementById('files-list');
|
||||||
|
if (filesList) {
|
||||||
|
this._stampOwnerIds(filesList, ownerMap);
|
||||||
|
ownerTooltip.init(filesList);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._setLoadMoreVisible(!!this._nextCursor);
|
||||||
|
} catch (err) {
|
||||||
|
ui.showError(`
|
||||||
|
<i class="fas fa-exclamation-circle empty-state-icon error"></i>
|
||||||
|
<p>${i18n.t('errors_loadFailed', 'Failed to load items')}</p>
|
||||||
|
`);
|
||||||
|
console.error('sharedWithMeView: load error', err);
|
||||||
|
} finally {
|
||||||
|
this._loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map `SharedWithMeItem[]` to separate arrays for rendering plus an
|
||||||
|
* `ownerMap` (itemId → grantedBy userId) used to stamp `data-owner-id`
|
||||||
|
* after the cards are in the DOM.
|
||||||
|
*
|
||||||
|
* The backend already includes all display fields (`icon_class`,
|
||||||
|
* `icon_special_class`, `category`, `size_formatted`) inside the nested
|
||||||
|
* `file` / `folder` objects, so no client-side enrichment is needed.
|
||||||
|
*
|
||||||
|
* @param {SharedWithMeItem[]} items
|
||||||
|
* @returns {{ folders: FolderItem[], files: FileItem[], ownerMap: Map<string,string> }}
|
||||||
|
*/
|
||||||
|
_mapItems(items) {
|
||||||
|
/** @type {FolderItem[]} */
|
||||||
|
const folders = [];
|
||||||
|
|
||||||
|
/** @type {FileItem[]} */
|
||||||
|
const files = [];
|
||||||
|
|
||||||
|
/** @type {Map<string, string>} itemId → grantedBy userId */
|
||||||
|
const ownerMap = new Map();
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
if (item.resource_type === 'folder' && item.folder) {
|
||||||
|
const f = item.folder;
|
||||||
|
folders.push(
|
||||||
|
/** @type {FolderItem} */ ({
|
||||||
|
id: f.id,
|
||||||
|
name: f.name,
|
||||||
|
path: f.path ?? '',
|
||||||
|
parent_id: f.parent_id ?? '',
|
||||||
|
owner_id: f.owner_id ?? '',
|
||||||
|
is_root: f.is_root ?? false,
|
||||||
|
created_at: f.created_at,
|
||||||
|
modified_at: f.modified_at,
|
||||||
|
icon_class: f.icon_class,
|
||||||
|
icon_special_class: f.icon_special_class ?? '',
|
||||||
|
category: 'folder'
|
||||||
|
})
|
||||||
|
);
|
||||||
|
ownerMap.set(f.id, item.granted_by);
|
||||||
|
} else if (item.resource_type === 'file' && item.file) {
|
||||||
|
const f = item.file;
|
||||||
|
files.push(
|
||||||
|
/** @type {FileItem} */ ({
|
||||||
|
id: f.id,
|
||||||
|
name: f.name,
|
||||||
|
path: f.path ?? '',
|
||||||
|
folder_id: f.folder_id ?? '',
|
||||||
|
owner_id: f.owner_id ?? '',
|
||||||
|
mime_type: f.mime_type,
|
||||||
|
size: f.size,
|
||||||
|
size_formatted: f.size_formatted,
|
||||||
|
created_at: f.created_at,
|
||||||
|
modified_at: f.modified_at,
|
||||||
|
sort_date: f.modified_at,
|
||||||
|
icon_class: f.icon_class,
|
||||||
|
icon_special_class: f.icon_special_class ?? '',
|
||||||
|
category: f.category
|
||||||
|
})
|
||||||
|
);
|
||||||
|
ownerMap.set(f.id, item.granted_by);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { folders, files, ownerMap };
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Walk `ownerMap` and set `data-owner-id` on matching `.file-item` cards
|
||||||
|
* inside `container`. Must be called after `renderFolders`/`renderFiles`.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} container
|
||||||
|
* @param {Map<string,string>} ownerMap itemId → grantedBy userId
|
||||||
|
*/
|
||||||
|
_stampOwnerIds(container, ownerMap) {
|
||||||
|
for (const [itemId, ownerId] of ownerMap) {
|
||||||
|
const el = container.querySelector(
|
||||||
|
`[data-folder-id="${itemId}"], [data-file-id="${itemId}"]`
|
||||||
|
);
|
||||||
|
if (el instanceof HTMLElement) {
|
||||||
|
el.dataset.ownerId = ownerId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// ── "Load more" button ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the "Load more" wrapper once and attach it below `.files-container`.
|
||||||
|
* Subsequent calls are no-ops.
|
||||||
|
*/
|
||||||
|
_ensureLoadMoreButton() {
|
||||||
|
if (document.getElementById(LOAD_MORE_ID)) return;
|
||||||
|
|
||||||
|
const filesContainer = document.querySelector('.files-container');
|
||||||
|
if (!filesContainer) return;
|
||||||
|
|
||||||
|
const wrapper = document.createElement('div');
|
||||||
|
wrapper.id = LOAD_MORE_ID;
|
||||||
|
wrapper.className = 'swm-load-more-wrapper hidden';
|
||||||
|
|
||||||
|
const btn = document.createElement('button');
|
||||||
|
btn.id = 'swm-load-more';
|
||||||
|
btn.className = 'button secondary';
|
||||||
|
btn.textContent = i18n.t('sharedwithme_loadMore', 'Load more');
|
||||||
|
btn.addEventListener('click', () => this._loadPage());
|
||||||
|
|
||||||
|
wrapper.appendChild(btn);
|
||||||
|
filesContainer.after(wrapper);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean} visible
|
||||||
|
*/
|
||||||
|
_setLoadMoreVisible(visible) {
|
||||||
|
const w = document.getElementById(LOAD_MORE_ID);
|
||||||
|
if (w) w.classList.toggle('hidden', !visible);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export { sharedWithMeView };
|
||||||
+17
-3
@@ -5,12 +5,13 @@
|
|||||||
},
|
},
|
||||||
"nav": {
|
"nav": {
|
||||||
"files": "الملفات",
|
"files": "الملفات",
|
||||||
"shared": "المشترك",
|
"shared": "مشاركاتي",
|
||||||
"recent": "الأخيرة",
|
"recent": "الأخيرة",
|
||||||
"favorites": "المفضلة",
|
"favorites": "المفضلة",
|
||||||
"photos": "الصور",
|
"photos": "الصور",
|
||||||
"music": "الموسيقى",
|
"music": "الموسيقى",
|
||||||
"trash": "سلة المهملات"
|
"trash": "سلة المهملات",
|
||||||
|
"sharedwithme": "مشتركة معي"
|
||||||
},
|
},
|
||||||
"photos": {
|
"photos": {
|
||||||
"empty_state": "لا توجد صور بعد",
|
"empty_state": "لا توجد صور بعد",
|
||||||
@@ -682,5 +683,18 @@
|
|||||||
"files": "ملفات",
|
"files": "ملفات",
|
||||||
"complete": "{{count}} / {{total}} تم الرفع"
|
"complete": "{{count}} / {{total}} تم الرفع"
|
||||||
},
|
},
|
||||||
"storage_quota_exceeded": "تجاوز حصة التخزين"
|
"storage_quota_exceeded": "تجاوز حصة التخزين",
|
||||||
|
"sharedwithme": {
|
||||||
|
"pageTitle": "مشترك معي",
|
||||||
|
"pageDescription": "الملفات والمجلدات التي شاركها معك مستخدمون آخرون",
|
||||||
|
"emptyStateTitle": "لم يُشارك معك أي شيء بعد",
|
||||||
|
"emptyStateDesc": "ستظهر هنا العناصر التي يشاركها معك مستخدمون آخرون",
|
||||||
|
"loadMore": "تحميل المزيد",
|
||||||
|
"sharedBy": "مشترك من قِبل",
|
||||||
|
"colName": "الاسم",
|
||||||
|
"colType": "النوع",
|
||||||
|
"colSharedBy": "مشترك من قِبل",
|
||||||
|
"colDate": "تاريخ المشاركة",
|
||||||
|
"colPermissions": "الصلاحيات"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-3
@@ -5,12 +5,13 @@
|
|||||||
},
|
},
|
||||||
"nav": {
|
"nav": {
|
||||||
"files": "Dateien",
|
"files": "Dateien",
|
||||||
"shared": "Geteilt",
|
"shared": "Freigaben",
|
||||||
"recent": "Zuletzt verwendet",
|
"recent": "Zuletzt verwendet",
|
||||||
"favorites": "Favoriten",
|
"favorites": "Favoriten",
|
||||||
"photos": "Fotos",
|
"photos": "Fotos",
|
||||||
"music": "Musik",
|
"music": "Musik",
|
||||||
"trash": "Papierkorb"
|
"trash": "Papierkorb",
|
||||||
|
"sharedwithme": "Mit mir geteilt"
|
||||||
},
|
},
|
||||||
"photos": {
|
"photos": {
|
||||||
"empty_state": "Noch keine Fotos",
|
"empty_state": "Noch keine Fotos",
|
||||||
@@ -682,5 +683,18 @@
|
|||||||
"files": "Dateien",
|
"files": "Dateien",
|
||||||
"complete": "{{count}} / {{total}} hochgeladen"
|
"complete": "{{count}} / {{total}} hochgeladen"
|
||||||
},
|
},
|
||||||
"storage_quota_exceeded": "Speicherplatz erschöpft"
|
"storage_quota_exceeded": "Speicherplatz erschöpft",
|
||||||
|
"sharedwithme": {
|
||||||
|
"pageTitle": "Mit mir geteilt",
|
||||||
|
"pageDescription": "Dateien und Ordner, die andere Benutzer mit Ihnen geteilt haben",
|
||||||
|
"emptyStateTitle": "Noch nichts mit Ihnen geteilt",
|
||||||
|
"emptyStateDesc": "Elemente, die andere Benutzer mit Ihnen teilen, erscheinen hier",
|
||||||
|
"loadMore": "Mehr laden",
|
||||||
|
"sharedBy": "Geteilt von",
|
||||||
|
"colName": "Name",
|
||||||
|
"colType": "Typ",
|
||||||
|
"colSharedBy": "Geteilt von",
|
||||||
|
"colDate": "Datum der Freigabe",
|
||||||
|
"colPermissions": "Berechtigungen"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-2
@@ -5,7 +5,8 @@
|
|||||||
},
|
},
|
||||||
"nav": {
|
"nav": {
|
||||||
"files": "Files",
|
"files": "Files",
|
||||||
"shared": "Shared",
|
"shared": "My shares",
|
||||||
|
"sharedwithme": "Shared with me",
|
||||||
"recent": "Recent",
|
"recent": "Recent",
|
||||||
"favorites": "Favorites",
|
"favorites": "Favorites",
|
||||||
"photos": "Photos",
|
"photos": "Photos",
|
||||||
@@ -682,5 +683,18 @@
|
|||||||
"files": "files",
|
"files": "files",
|
||||||
"complete": "{{count}} / {{total}} uploaded"
|
"complete": "{{count}} / {{total}} uploaded"
|
||||||
},
|
},
|
||||||
"storage_quota_exceeded": "Storage quota exceeded"
|
"storage_quota_exceeded": "Storage quota exceeded",
|
||||||
|
"sharedwithme": {
|
||||||
|
"pageTitle": "Shared with me",
|
||||||
|
"pageDescription": "Files and folders others have shared with you",
|
||||||
|
"emptyStateTitle": "Nothing shared with you yet",
|
||||||
|
"emptyStateDesc": "Items shared with you by other users will appear here",
|
||||||
|
"loadMore": "Load more",
|
||||||
|
"sharedBy": "Shared by",
|
||||||
|
"colName": "Name",
|
||||||
|
"colType": "Type",
|
||||||
|
"colSharedBy": "Shared by",
|
||||||
|
"colDate": "Date shared",
|
||||||
|
"colPermissions": "Permissions"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-2
@@ -10,7 +10,8 @@
|
|||||||
"favorites": "Favoritos",
|
"favorites": "Favoritos",
|
||||||
"photos": "Fotos",
|
"photos": "Fotos",
|
||||||
"music": "Música",
|
"music": "Música",
|
||||||
"trash": "Papelera"
|
"trash": "Papelera",
|
||||||
|
"sharedwithme": "Compartidos conmigo"
|
||||||
},
|
},
|
||||||
"photos": {
|
"photos": {
|
||||||
"empty_state": "Aún no hay fotos",
|
"empty_state": "Aún no hay fotos",
|
||||||
@@ -682,5 +683,18 @@
|
|||||||
"files": "archivos",
|
"files": "archivos",
|
||||||
"complete": "{{count}} / {{total}} subidos"
|
"complete": "{{count}} / {{total}} subidos"
|
||||||
},
|
},
|
||||||
"storage_quota_exceeded": "Cuota de almacenamiento superada"
|
"storage_quota_exceeded": "Cuota de almacenamiento superada",
|
||||||
|
"sharedwithme": {
|
||||||
|
"pageTitle": "Compartido conmigo",
|
||||||
|
"pageDescription": "Archivos y carpetas que otros usuarios han compartido contigo",
|
||||||
|
"emptyStateTitle": "Aún no hay nada compartido contigo",
|
||||||
|
"emptyStateDesc": "Los elementos que otros usuarios compartan contigo aparecerán aquí",
|
||||||
|
"loadMore": "Cargar más",
|
||||||
|
"sharedBy": "Compartido por",
|
||||||
|
"colName": "Nombre",
|
||||||
|
"colType": "Tipo",
|
||||||
|
"colSharedBy": "Compartido por",
|
||||||
|
"colDate": "Fecha de compartición",
|
||||||
|
"colPermissions": "Permisos"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-3
@@ -5,12 +5,13 @@
|
|||||||
},
|
},
|
||||||
"nav": {
|
"nav": {
|
||||||
"files": "پروندهها",
|
"files": "پروندهها",
|
||||||
"shared": "همرسانی شده",
|
"shared": "همرسانیهای من",
|
||||||
"recent": "اخیر",
|
"recent": "اخیر",
|
||||||
"favorites": "موردعلاقهها",
|
"favorites": "موردعلاقهها",
|
||||||
"photos": "عکسها",
|
"photos": "عکسها",
|
||||||
"music": "موسیقی",
|
"music": "موسیقی",
|
||||||
"trash": "سطل زباله"
|
"trash": "سطل زباله",
|
||||||
|
"sharedwithme": "به اشتراکگذاشته شده با من"
|
||||||
},
|
},
|
||||||
"photos": {
|
"photos": {
|
||||||
"empty_state": "هنوز عکسی نیست",
|
"empty_state": "هنوز عکسی نیست",
|
||||||
@@ -682,5 +683,18 @@
|
|||||||
"files": "فایلها",
|
"files": "فایلها",
|
||||||
"complete": "{{count}} / {{total}} آپلود شد"
|
"complete": "{{count}} / {{total}} آپلود شد"
|
||||||
},
|
},
|
||||||
"storage_quota_exceeded": "سهمیه فضای ذخیرهسازی تجاوز کرده است"
|
"storage_quota_exceeded": "سهمیه فضای ذخیرهسازی تجاوز کرده است",
|
||||||
|
"sharedwithme": {
|
||||||
|
"pageTitle": "به اشتراکگذاشته شده با من",
|
||||||
|
"pageDescription": "فایلها و پوشههایی که کاربران دیگر با شما به اشتراک گذاشتهاند",
|
||||||
|
"emptyStateTitle": "هنوز چیزی با شما به اشتراک گذاشته نشده",
|
||||||
|
"emptyStateDesc": "مواردی که کاربران دیگر با شما به اشتراک میگذارند اینجا نمایش داده میشوند",
|
||||||
|
"loadMore": "بارگذاری بیشتر",
|
||||||
|
"sharedBy": "به اشتراکگذاشته توسط",
|
||||||
|
"colName": "نام",
|
||||||
|
"colType": "نوع",
|
||||||
|
"colSharedBy": "به اشتراکگذاشته توسط",
|
||||||
|
"colDate": "تاریخ اشتراکگذاری",
|
||||||
|
"colPermissions": "مجوزها"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-3
@@ -5,12 +5,13 @@
|
|||||||
},
|
},
|
||||||
"nav": {
|
"nav": {
|
||||||
"files": "Fichiers",
|
"files": "Fichiers",
|
||||||
"shared": "Partagés",
|
"shared": "Partages",
|
||||||
"recent": "Récents",
|
"recent": "Récents",
|
||||||
"favorites": "Favoris",
|
"favorites": "Favoris",
|
||||||
"photos": "Photos",
|
"photos": "Photos",
|
||||||
"music": "Musique",
|
"music": "Musique",
|
||||||
"trash": "Corbeille"
|
"trash": "Corbeille",
|
||||||
|
"sharedwithme": "Partages avec moi"
|
||||||
},
|
},
|
||||||
"photos": {
|
"photos": {
|
||||||
"empty_state": "Pas encore de photos",
|
"empty_state": "Pas encore de photos",
|
||||||
@@ -682,5 +683,18 @@
|
|||||||
"files": "fichiers",
|
"files": "fichiers",
|
||||||
"complete": "{{count}} / {{total}} téléchargés"
|
"complete": "{{count}} / {{total}} téléchargés"
|
||||||
},
|
},
|
||||||
"storage_quota_exceeded": "Quota de stockage dépassé"
|
"storage_quota_exceeded": "Quota de stockage dépassé",
|
||||||
|
"sharedwithme": {
|
||||||
|
"pageTitle": "Partagé avec moi",
|
||||||
|
"pageDescription": "Fichiers et dossiers que d'autres utilisateurs ont partagés avec vous",
|
||||||
|
"emptyStateTitle": "Rien n'a encore été partagé avec vous",
|
||||||
|
"emptyStateDesc": "Les éléments partagés avec vous par d'autres utilisateurs apparaîtront ici",
|
||||||
|
"loadMore": "Charger plus",
|
||||||
|
"sharedBy": "Partagé par",
|
||||||
|
"colName": "Nom",
|
||||||
|
"colType": "Type",
|
||||||
|
"colSharedBy": "Partagé par",
|
||||||
|
"colDate": "Date de partage",
|
||||||
|
"colPermissions": "Permissions"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-2
@@ -10,7 +10,8 @@
|
|||||||
"favorites": "पसंदीदा",
|
"favorites": "पसंदीदा",
|
||||||
"photos": "फ़ोटो",
|
"photos": "फ़ोटो",
|
||||||
"music": "संगीत",
|
"music": "संगीत",
|
||||||
"trash": "रद्दी"
|
"trash": "रद्दी",
|
||||||
|
"sharedwithme": "मेरे साथ साझा किए गए"
|
||||||
},
|
},
|
||||||
"photos": {
|
"photos": {
|
||||||
"empty_state": "अभी कोई फ़ोटो नहीं",
|
"empty_state": "अभी कोई फ़ोटो नहीं",
|
||||||
@@ -682,5 +683,18 @@
|
|||||||
"files": "फ़ाइलें",
|
"files": "फ़ाइलें",
|
||||||
"complete": "{{count}} / {{total}} अपलोड हुए"
|
"complete": "{{count}} / {{total}} अपलोड हुए"
|
||||||
},
|
},
|
||||||
"storage_quota_exceeded": "स्टोरेज कोटा पार हो गया"
|
"storage_quota_exceeded": "स्टोरेज कोटा पार हो गया",
|
||||||
|
"sharedwithme": {
|
||||||
|
"pageTitle": "मेरे साथ साझा किया",
|
||||||
|
"pageDescription": "फ़ाइलें और फ़ोल्डर जो अन्य उपयोगकर्ताओं ने आपके साथ साझा किए हैं",
|
||||||
|
"emptyStateTitle": "अभी तक आपके साथ कुछ भी साझा नहीं किया गया",
|
||||||
|
"emptyStateDesc": "अन्य उपयोगकर्ताओं द्वारा आपके साथ साझा किए गए आइटम यहाँ दिखाई देंगे",
|
||||||
|
"loadMore": "और लोड करें",
|
||||||
|
"sharedBy": "द्वारा साझा किया",
|
||||||
|
"colName": "नाम",
|
||||||
|
"colType": "प्रकार",
|
||||||
|
"colSharedBy": "द्वारा साझा किया",
|
||||||
|
"colDate": "साझाकरण तिथि",
|
||||||
|
"colPermissions": "अनुमतियाँ"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-3
@@ -5,12 +5,13 @@
|
|||||||
},
|
},
|
||||||
"nav": {
|
"nav": {
|
||||||
"files": "File",
|
"files": "File",
|
||||||
"shared": "Condivisi",
|
"shared": "Condivisioni",
|
||||||
"recent": "Recenti",
|
"recent": "Recenti",
|
||||||
"favorites": "Preferiti",
|
"favorites": "Preferiti",
|
||||||
"photos": "Foto",
|
"photos": "Foto",
|
||||||
"music": "Musica",
|
"music": "Musica",
|
||||||
"trash": "Cestino"
|
"trash": "Cestino",
|
||||||
|
"sharedwithme": "Condivisi con me"
|
||||||
},
|
},
|
||||||
"photos": {
|
"photos": {
|
||||||
"empty_state": "Nessuna foto ancora",
|
"empty_state": "Nessuna foto ancora",
|
||||||
@@ -682,5 +683,18 @@
|
|||||||
"files": "file",
|
"files": "file",
|
||||||
"complete": "{{count}} / {{total}} caricati"
|
"complete": "{{count}} / {{total}} caricati"
|
||||||
},
|
},
|
||||||
"storage_quota_exceeded": "Quota di archiviazione superata"
|
"storage_quota_exceeded": "Quota di archiviazione superata",
|
||||||
|
"sharedwithme": {
|
||||||
|
"pageTitle": "Condiviso con me",
|
||||||
|
"pageDescription": "File e cartelle che altri utenti hanno condiviso con te",
|
||||||
|
"emptyStateTitle": "Niente è ancora condiviso con te",
|
||||||
|
"emptyStateDesc": "Gli elementi condivisi con te da altri utenti appariranno qui",
|
||||||
|
"loadMore": "Carica altri",
|
||||||
|
"sharedBy": "Condiviso da",
|
||||||
|
"colName": "Nome",
|
||||||
|
"colType": "Tipo",
|
||||||
|
"colSharedBy": "Condiviso da",
|
||||||
|
"colDate": "Data condivisione",
|
||||||
|
"colPermissions": "Permessi"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-2
@@ -10,7 +10,8 @@
|
|||||||
"favorites": "お気に入り",
|
"favorites": "お気に入り",
|
||||||
"photos": "写真",
|
"photos": "写真",
|
||||||
"music": "音楽",
|
"music": "音楽",
|
||||||
"trash": "ゴミ箱"
|
"trash": "ゴミ箱",
|
||||||
|
"sharedwithme": "自分と共有"
|
||||||
},
|
},
|
||||||
"photos": {
|
"photos": {
|
||||||
"empty_state": "写真はまだありません",
|
"empty_state": "写真はまだありません",
|
||||||
@@ -682,5 +683,18 @@
|
|||||||
"files": "ファイル",
|
"files": "ファイル",
|
||||||
"complete": "{{count}} / {{total}} アップロード済み"
|
"complete": "{{count}} / {{total}} アップロード済み"
|
||||||
},
|
},
|
||||||
"storage_quota_exceeded": "ストレージ容量を超過しました"
|
"storage_quota_exceeded": "ストレージ容量を超過しました",
|
||||||
|
"sharedwithme": {
|
||||||
|
"pageTitle": "自分と共有",
|
||||||
|
"pageDescription": "他のユーザーがあなたと共有したファイルとフォルダー",
|
||||||
|
"emptyStateTitle": "まだ何も共有されていません",
|
||||||
|
"emptyStateDesc": "他のユーザーがあなたと共有したアイテムがここに表示されます",
|
||||||
|
"loadMore": "さらに読み込む",
|
||||||
|
"sharedBy": "共有者",
|
||||||
|
"colName": "名前",
|
||||||
|
"colType": "タイプ",
|
||||||
|
"colSharedBy": "共有者",
|
||||||
|
"colDate": "共有日",
|
||||||
|
"colPermissions": "権限"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-2
@@ -10,7 +10,8 @@
|
|||||||
"favorites": "즐겨찾기",
|
"favorites": "즐겨찾기",
|
||||||
"photos": "사진",
|
"photos": "사진",
|
||||||
"music": "음악",
|
"music": "음악",
|
||||||
"trash": "휴지통"
|
"trash": "휴지통",
|
||||||
|
"sharedwithme": "나와 공유됨"
|
||||||
},
|
},
|
||||||
"photos": {
|
"photos": {
|
||||||
"empty_state": "아직 사진이 없습니다",
|
"empty_state": "아직 사진이 없습니다",
|
||||||
@@ -682,5 +683,18 @@
|
|||||||
"files": "파일",
|
"files": "파일",
|
||||||
"complete": "{{count}} / {{total}} 업로드됨"
|
"complete": "{{count}} / {{total}} 업로드됨"
|
||||||
},
|
},
|
||||||
"storage_quota_exceeded": "저장 공간 할당량 초과"
|
"storage_quota_exceeded": "저장 공간 할당량 초과",
|
||||||
|
"sharedwithme": {
|
||||||
|
"pageTitle": "나와 공유됨",
|
||||||
|
"pageDescription": "다른 사용자가 나와 공유한 파일 및 폴더",
|
||||||
|
"emptyStateTitle": "아직 공유된 항목이 없습니다",
|
||||||
|
"emptyStateDesc": "다른 사용자가 공유한 항목이 여기에 표시됩니다",
|
||||||
|
"loadMore": "더 불러오기",
|
||||||
|
"sharedBy": "공유한 사람",
|
||||||
|
"colName": "이름",
|
||||||
|
"colType": "유형",
|
||||||
|
"colSharedBy": "공유한 사람",
|
||||||
|
"colDate": "공유 날짜",
|
||||||
|
"colPermissions": "권한"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-2
@@ -10,7 +10,8 @@
|
|||||||
"favorites": "Favorieten",
|
"favorites": "Favorieten",
|
||||||
"photos": "Foto's",
|
"photos": "Foto's",
|
||||||
"music": "Muziek",
|
"music": "Muziek",
|
||||||
"trash": "Prullenbak"
|
"trash": "Prullenbak",
|
||||||
|
"sharedwithme": "Gedeeld met mij"
|
||||||
},
|
},
|
||||||
"photos": {
|
"photos": {
|
||||||
"empty_state": "Nog geen foto's",
|
"empty_state": "Nog geen foto's",
|
||||||
@@ -682,5 +683,18 @@
|
|||||||
"files": "bestanden",
|
"files": "bestanden",
|
||||||
"complete": "{{count}} / {{total}} geüpload"
|
"complete": "{{count}} / {{total}} geüpload"
|
||||||
},
|
},
|
||||||
"storage_quota_exceeded": "Opslagquotum overschreden"
|
"storage_quota_exceeded": "Opslagquotum overschreden",
|
||||||
|
"sharedwithme": {
|
||||||
|
"pageTitle": "Gedeeld met mij",
|
||||||
|
"pageDescription": "Bestanden en mappen die andere gebruikers met u hebben gedeeld",
|
||||||
|
"emptyStateTitle": "Er is nog niets met u gedeeld",
|
||||||
|
"emptyStateDesc": "Items die andere gebruikers met u delen, verschijnen hier",
|
||||||
|
"loadMore": "Meer laden",
|
||||||
|
"sharedBy": "Gedeeld door",
|
||||||
|
"colName": "Naam",
|
||||||
|
"colType": "Type",
|
||||||
|
"colSharedBy": "Gedeeld door",
|
||||||
|
"colDate": "Datum gedeeld",
|
||||||
|
"colPermissions": "Machtigingen"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-2
@@ -10,7 +10,8 @@
|
|||||||
"favorites": "Ulubione",
|
"favorites": "Ulubione",
|
||||||
"photos": "Zdjęcia",
|
"photos": "Zdjęcia",
|
||||||
"music": "Muzyka",
|
"music": "Muzyka",
|
||||||
"trash": "Kosz"
|
"trash": "Kosz",
|
||||||
|
"sharedwithme": "Udostępnione dla mnie"
|
||||||
},
|
},
|
||||||
"photos": {
|
"photos": {
|
||||||
"empty_state": "Brak zdjęć",
|
"empty_state": "Brak zdjęć",
|
||||||
@@ -682,5 +683,18 @@
|
|||||||
"files": "plików",
|
"files": "plików",
|
||||||
"complete": "{{count}} / {{total}} przesłano"
|
"complete": "{{count}} / {{total}} przesłano"
|
||||||
},
|
},
|
||||||
"storage_quota_exceeded": "Przekroczono limit pamięci masowej"
|
"storage_quota_exceeded": "Przekroczono limit pamięci masowej",
|
||||||
|
"sharedwithme": {
|
||||||
|
"pageTitle": "Udostępnione dla mnie",
|
||||||
|
"pageDescription": "Pliki i foldery, które inni użytkownicy udostępnili Ci",
|
||||||
|
"emptyStateTitle": "Nic nie zostało Ci jeszcze udostępnione",
|
||||||
|
"emptyStateDesc": "Elementy udostępnione Ci przez innych użytkowników pojawią się tutaj",
|
||||||
|
"loadMore": "Załaduj więcej",
|
||||||
|
"sharedBy": "Udostępnione przez",
|
||||||
|
"colName": "Nazwa",
|
||||||
|
"colType": "Typ",
|
||||||
|
"colSharedBy": "Udostępnione przez",
|
||||||
|
"colDate": "Data udostępnienia",
|
||||||
|
"colPermissions": "Uprawnienia"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-3
@@ -5,12 +5,13 @@
|
|||||||
},
|
},
|
||||||
"nav": {
|
"nav": {
|
||||||
"files": "Arquivos",
|
"files": "Arquivos",
|
||||||
"shared": "Compartilhados",
|
"shared": "Compartilhamentos",
|
||||||
"recent": "Recentes",
|
"recent": "Recentes",
|
||||||
"favorites": "Favoritos",
|
"favorites": "Favoritos",
|
||||||
"photos": "Fotos",
|
"photos": "Fotos",
|
||||||
"music": "Música",
|
"music": "Música",
|
||||||
"trash": "Lixeira"
|
"trash": "Lixeira",
|
||||||
|
"sharedwithme": "Compartilhados comigo"
|
||||||
},
|
},
|
||||||
"photos": {
|
"photos": {
|
||||||
"empty_state": "Nenhuma foto ainda",
|
"empty_state": "Nenhuma foto ainda",
|
||||||
@@ -682,5 +683,18 @@
|
|||||||
"files": "ficheiros",
|
"files": "ficheiros",
|
||||||
"complete": "{{count}} / {{total}} carregados"
|
"complete": "{{count}} / {{total}} carregados"
|
||||||
},
|
},
|
||||||
"storage_quota_exceeded": "Cota de armazenamento excedida"
|
"storage_quota_exceeded": "Cota de armazenamento excedida",
|
||||||
|
"sharedwithme": {
|
||||||
|
"pageTitle": "Compartilhado comigo",
|
||||||
|
"pageDescription": "Arquivos e pastas que outros usuários compartilharam com você",
|
||||||
|
"emptyStateTitle": "Nada compartilhado com você ainda",
|
||||||
|
"emptyStateDesc": "Itens compartilhados com você por outros usuários aparecerão aqui",
|
||||||
|
"loadMore": "Carregar mais",
|
||||||
|
"sharedBy": "Compartilhado por",
|
||||||
|
"colName": "Nome",
|
||||||
|
"colType": "Tipo",
|
||||||
|
"colSharedBy": "Compartilhado por",
|
||||||
|
"colDate": "Data de compartilhamento",
|
||||||
|
"colPermissions": "Permissões"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-2
@@ -10,7 +10,8 @@
|
|||||||
"favorites": "Избранное",
|
"favorites": "Избранное",
|
||||||
"photos": "Фото",
|
"photos": "Фото",
|
||||||
"music": "Музыка",
|
"music": "Музыка",
|
||||||
"trash": "Корзина"
|
"trash": "Корзина",
|
||||||
|
"sharedwithme": "Доступно мне"
|
||||||
},
|
},
|
||||||
"photos": {
|
"photos": {
|
||||||
"empty_state": "Фотографий пока нет",
|
"empty_state": "Фотографий пока нет",
|
||||||
@@ -682,5 +683,18 @@
|
|||||||
"files": "файлов",
|
"files": "файлов",
|
||||||
"complete": "{{count}} / {{total}} загружено"
|
"complete": "{{count}} / {{total}} загружено"
|
||||||
},
|
},
|
||||||
"storage_quota_exceeded": "Превышена квота хранилища"
|
"storage_quota_exceeded": "Превышена квота хранилища",
|
||||||
|
"sharedwithme": {
|
||||||
|
"pageTitle": "Доступно мне",
|
||||||
|
"pageDescription": "Файлы и папки, которые другие пользователи предоставили вам",
|
||||||
|
"emptyStateTitle": "Вам ещё ничего не предоставлено",
|
||||||
|
"emptyStateDesc": "Элементы, которые другие пользователи предоставят вам, появятся здесь",
|
||||||
|
"loadMore": "Загрузить ещё",
|
||||||
|
"sharedBy": "Предоставлено",
|
||||||
|
"colName": "Имя",
|
||||||
|
"colType": "Тип",
|
||||||
|
"colSharedBy": "Предоставлено",
|
||||||
|
"colDate": "Дата предоставления",
|
||||||
|
"colPermissions": "Права"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,8 @@
|
|||||||
"favorites": "收藏",
|
"favorites": "收藏",
|
||||||
"photos": "照片",
|
"photos": "照片",
|
||||||
"music": "音樂",
|
"music": "音樂",
|
||||||
"trash": "回收站"
|
"trash": "回收站",
|
||||||
|
"sharedwithme": "與我共享"
|
||||||
},
|
},
|
||||||
"photos": {
|
"photos": {
|
||||||
"empty_state": "還沒有照片",
|
"empty_state": "還沒有照片",
|
||||||
@@ -682,5 +683,18 @@
|
|||||||
"files": "個檔案",
|
"files": "個檔案",
|
||||||
"complete": "已上傳 {{count}} / {{total}}"
|
"complete": "已上傳 {{count}} / {{total}}"
|
||||||
},
|
},
|
||||||
"storage_quota_exceeded": "儲存配額已超限"
|
"storage_quota_exceeded": "儲存配額已超限",
|
||||||
|
"sharedwithme": {
|
||||||
|
"pageTitle": "與我共享",
|
||||||
|
"pageDescription": "其他使用者與您共享的檔案和資料夾",
|
||||||
|
"emptyStateTitle": "目前沒有內容與您共享",
|
||||||
|
"emptyStateDesc": "其他使用者與您共享的項目將顯示在這裡",
|
||||||
|
"loadMore": "載入更多",
|
||||||
|
"sharedBy": "共享者",
|
||||||
|
"colName": "名稱",
|
||||||
|
"colType": "類型",
|
||||||
|
"colSharedBy": "共享者",
|
||||||
|
"colDate": "共享日期",
|
||||||
|
"colPermissions": "權限"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-2
@@ -10,7 +10,8 @@
|
|||||||
"favorites": "收藏",
|
"favorites": "收藏",
|
||||||
"photos": "照片",
|
"photos": "照片",
|
||||||
"music": "音乐",
|
"music": "音乐",
|
||||||
"trash": "回收站"
|
"trash": "回收站",
|
||||||
|
"sharedwithme": "与我共享"
|
||||||
},
|
},
|
||||||
"photos": {
|
"photos": {
|
||||||
"empty_state": "还没有照片",
|
"empty_state": "还没有照片",
|
||||||
@@ -682,5 +683,18 @@
|
|||||||
"files": "个文件",
|
"files": "个文件",
|
||||||
"complete": "已上传 {{count}} / {{total}}"
|
"complete": "已上传 {{count}} / {{total}}"
|
||||||
},
|
},
|
||||||
"storage_quota_exceeded": "存储配额已超限"
|
"storage_quota_exceeded": "存储配额已超限",
|
||||||
|
"sharedwithme": {
|
||||||
|
"pageTitle": "与我共享",
|
||||||
|
"pageDescription": "其他用户与您共享的文件和文件夹",
|
||||||
|
"emptyStateTitle": "暂无内容与您共享",
|
||||||
|
"emptyStateDesc": "其他用户与您共享的项目将显示在此处",
|
||||||
|
"loadMore": "加载更多",
|
||||||
|
"sharedBy": "共享者",
|
||||||
|
"colName": "名称",
|
||||||
|
"colType": "类型",
|
||||||
|
"colSharedBy": "共享者",
|
||||||
|
"colDate": "共享日期",
|
||||||
|
"colPermissions": "权限"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user