mirror of
https://github.com/RetroShare/RSNewWebUI.git
synced 2026-09-14 11:05:47 +05:00
Merge pull request #82 from zelfroster/download-chunks
feat: view actual download chunks and fixed download actions
This commit is contained in:
commit
fac0e3ccc0
@ -723,7 +723,7 @@ const PostView = () => {
|
||||
post.mFiles.map((file) =>
|
||||
m('tr', [
|
||||
m('td', file.mName),
|
||||
m('td', util.formatbytes(file.mSize.xint64)),
|
||||
m('td', rs.formatBytes(file.mSize.xint64)),
|
||||
m(
|
||||
'button',
|
||||
{
|
||||
|
||||
@ -180,19 +180,8 @@ const FilesTable = () => {
|
||||
};
|
||||
};
|
||||
|
||||
function formatbytes(bytes, decimals = 2) {
|
||||
// takes in size returns a string (size)(kb/gb/tb)
|
||||
if (bytes === 0) return '0 Bytes';
|
||||
const k = 1024;
|
||||
const dm = decimals < 0 ? 0 : decimals;
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
const ChannelTable = () => {
|
||||
return {
|
||||
oninit: (v) => {},
|
||||
view: (v) => m('table.channels', [m('tr', [m('th', 'Channel Name')]), v.children]),
|
||||
};
|
||||
};
|
||||
@ -239,7 +228,6 @@ module.exports = {
|
||||
Data,
|
||||
SearchBar,
|
||||
ChannelSummary,
|
||||
formatbytes,
|
||||
DisplayChannelsFromList,
|
||||
updatedisplaychannels,
|
||||
ChannelTable,
|
||||
|
||||
@ -7,6 +7,7 @@ const Downloads = {
|
||||
strategies: {},
|
||||
statusMap: {},
|
||||
hashes: [],
|
||||
chunksMap: {},
|
||||
|
||||
loadStrategy() {
|
||||
rs.rsJsonApiRequest('/rsFiles/FileDownloads', {}, (d) =>
|
||||
@ -19,22 +20,29 @@ const Downloads = {
|
||||
},
|
||||
|
||||
async loadHashes() {
|
||||
await rs.rsJsonApiRequest('/rsFiles/FileDownloads', {}, (d) => (Downloads.hashes = d.hashs));
|
||||
await rs
|
||||
.rsJsonApiRequest('/rsFiles/FileDownloads', {}, (d) => (Downloads.hashes = d.hashs))
|
||||
.then(() => {
|
||||
Downloads.hashes.forEach((hash) => {
|
||||
rs.rsJsonApiRequest('/rsFiles/FileDownloadChunksDetails', {
|
||||
hash,
|
||||
}).then((res) => (this.chunksMap[hash] = res.body.info));
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
async loadStatus() {
|
||||
await Downloads.loadHashes();
|
||||
const fileKeys = Object.keys(Downloads.statusMap);
|
||||
if (Downloads.hashes !== undefined && Downloads.hashes.length !== fileKeys.length) {
|
||||
// New file added
|
||||
if (Downloads.hashes.length > fileKeys.length) {
|
||||
// New file added
|
||||
const newHashes = util.compareArrays(Downloads.hashes, fileKeys);
|
||||
for (const hash of newHashes) {
|
||||
Downloads.updateFileDetail(hash, true);
|
||||
}
|
||||
}
|
||||
// Existing file removed
|
||||
else {
|
||||
} else {
|
||||
// Existing file removed
|
||||
const oldHashes = util.compareArrays(fileKeys, Downloads.hashes);
|
||||
for (const hash of oldHashes) {
|
||||
delete Downloads.statusMap[hash];
|
||||
@ -125,13 +133,7 @@ const NewFileDialog = () => {
|
||||
m('input[type=text][name=fileurl]', {
|
||||
onchange: (e) => (url = e.target.value),
|
||||
}),
|
||||
m(
|
||||
'button',
|
||||
{
|
||||
onclick: () => addFile(url),
|
||||
},
|
||||
'Add'
|
||||
),
|
||||
m('button', { onclick: () => addFile(url) }, 'Add'),
|
||||
],
|
||||
};
|
||||
};
|
||||
@ -140,27 +142,17 @@ const Component = () => {
|
||||
return {
|
||||
oninit: () => {
|
||||
Downloads.loadStrategy();
|
||||
rs.setBackgroundTask(Downloads.loadStatus, 1000, () => {
|
||||
return m.route.get() === '/files/files';
|
||||
});
|
||||
rs.setBackgroundTask(Downloads.loadStatus, 1000, () => m.route.get() === '/files/files');
|
||||
Downloads.resetSearch();
|
||||
},
|
||||
view: () => [
|
||||
m('.widget__body-heading', [
|
||||
m('h3', 'Downloads (' + (Downloads.hashes && Downloads.hashes.length) + ' files)'),
|
||||
m('h3', `Downloads (${Downloads.hashes ? Downloads.hashes.length : 0} files)`),
|
||||
m('.action', [
|
||||
m('button', { onclick: () => widget.popupMessage(m(NewFileDialog)) }, 'Add new file'),
|
||||
m(
|
||||
'button',
|
||||
{
|
||||
onclick: () => widget.popupMessage(m(NewFileDialog)),
|
||||
},
|
||||
'Add new file'
|
||||
),
|
||||
m(
|
||||
'button',
|
||||
{
|
||||
onclick: () => rs.rsJsonApiRequest('/rsFiles/FileClearCompleted'),
|
||||
},
|
||||
{ onclick: () => rs.rsJsonApiRequest('/rsFiles/FileClearCompleted') },
|
||||
'Clear completed'
|
||||
),
|
||||
]),
|
||||
@ -173,7 +165,7 @@ const Component = () => {
|
||||
strategy: Downloads.strategies[hash],
|
||||
direction: 'down',
|
||||
transferred: Downloads.statusMap[hash].transfered.xint64,
|
||||
parts: [],
|
||||
chunksInfo: Downloads.chunksMap[hash],
|
||||
})
|
||||
),
|
||||
]),
|
||||
|
||||
24
webui-src/app/files/files_proxy.js
Normal file
24
webui-src/app/files/files_proxy.js
Normal file
@ -0,0 +1,24 @@
|
||||
const m = require('mithril');
|
||||
const rs = require('rswebui');
|
||||
const futil = require('files/files_util');
|
||||
|
||||
const fileProxyObj = futil.createProxy({}, () => {
|
||||
m.redraw();
|
||||
});
|
||||
|
||||
rs.events[rs.RsEventsType.FILE_TRANSFER] = {
|
||||
handler: (event) => {
|
||||
console.log('search results : ', event);
|
||||
|
||||
// if request item doesn't already exists in Object then create new item
|
||||
if (!Object.prototype.hasOwnProperty.call(fileProxyObj, event.mRequestId)) {
|
||||
fileProxyObj[event.mRequestId] = [];
|
||||
}
|
||||
|
||||
fileProxyObj[event.mRequestId].push(...event.mResults);
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
fileProxyObj,
|
||||
};
|
||||
@ -1,6 +1,7 @@
|
||||
const m = require('mithril');
|
||||
const rs = require('rswebui');
|
||||
const futil = require('files/files_util');
|
||||
const fproxy = require('files/files_proxy');
|
||||
const widget = require('widgets');
|
||||
|
||||
let matchString = '';
|
||||
@ -66,7 +67,7 @@ const Layout = () => {
|
||||
),
|
||||
]),
|
||||
m('div.file-search-container__results', [
|
||||
Object.keys(futil.proxyObj).length === 0
|
||||
Object.keys(fproxy.fileProxyObj).length === 0
|
||||
? m('h5.bold', 'Results')
|
||||
: m('table.results-container', [
|
||||
m(
|
||||
@ -80,13 +81,13 @@ const Layout = () => {
|
||||
),
|
||||
m(
|
||||
'tbody.results',
|
||||
futil.proxyObj[currentItem.slice(1)] === undefined &&
|
||||
futil.proxyObj[currentItem.slice(1)].length === 0
|
||||
fproxy.fileProxyObj[currentItem.slice(1)] === undefined &&
|
||||
fproxy.fileProxyObj[currentItem.slice(1)].length === 0
|
||||
? 'Fetching Results...'
|
||||
: futil.proxyObj[currentItem.slice(1)].map((item) =>
|
||||
: fproxy.fileProxyObj[currentItem.slice(1)].map((item) =>
|
||||
m('tr', [
|
||||
m('td.results__name', [m('i.fas.fa-file'), m('span', item.fName)]),
|
||||
m('td.results__size', futil.makeFriendlyUnit(item.fSize.xint64)),
|
||||
m('td.results__size', rs.formatBytes(item.fSize.xint64)),
|
||||
m('td.results__hash', item.fHash),
|
||||
m(
|
||||
'td.results__download',
|
||||
|
||||
@ -51,22 +51,6 @@ const createProxy = (obj, onChange) => {
|
||||
});
|
||||
};
|
||||
|
||||
const proxyObj = createProxy({}, () => {
|
||||
m.redraw();
|
||||
});
|
||||
|
||||
function makeFriendlyUnit(bytes) {
|
||||
let cnt = bytes;
|
||||
for (const s of ['', 'k', 'M', 'G']) {
|
||||
if (cnt < 1000) {
|
||||
return cnt.toFixed(1) + ' ' + s + 'B';
|
||||
} else {
|
||||
cnt = cnt / 1024;
|
||||
}
|
||||
}
|
||||
return cnt.toFixed(1) + 'TB';
|
||||
}
|
||||
|
||||
function calcRemainingTime(bytes, rate) {
|
||||
if (rate <= 0 || bytes < 1) {
|
||||
return '--';
|
||||
@ -91,29 +75,21 @@ function calcRemainingTime(bytes, rate) {
|
||||
}
|
||||
}
|
||||
|
||||
async function fileAction(hash, action) {
|
||||
let actionHeader = '';
|
||||
function fileAction(hash, action) {
|
||||
const jsonParams = {
|
||||
hash,
|
||||
flags: 0,
|
||||
};
|
||||
switch (action) {
|
||||
case 'cancel':
|
||||
actionHeader = '/rsFiles/FileCancel';
|
||||
break;
|
||||
|
||||
case 'pause':
|
||||
actionHeader = '/rsFiles/FileControl';
|
||||
jsonParams.flags = RS_FILE_CTRL_PAUSE;
|
||||
break;
|
||||
|
||||
case 'resume':
|
||||
actionHeader = '/rsFiles/FileControl';
|
||||
jsonParams.flags = RS_FILE_CTRL_START;
|
||||
break;
|
||||
|
||||
case 'force_check':
|
||||
actionHeader = '/rsFiles/FileControl';
|
||||
jsonParams.flags = RS_FILE_CTRL_FORCE_CHECK;
|
||||
break;
|
||||
|
||||
@ -121,182 +97,115 @@ async function fileAction(hash, action) {
|
||||
console.error('Unknown action in Downloads.control()');
|
||||
return;
|
||||
}
|
||||
const res = await rs.rsJsonApiRequest(actionHeader, jsonParams, () => {});
|
||||
return res.body.retval;
|
||||
}
|
||||
|
||||
function actionButton(file, action) {
|
||||
switch (action) {
|
||||
case 'resume':
|
||||
return m(
|
||||
'button',
|
||||
{
|
||||
title: 'resume',
|
||||
|
||||
onclick() {
|
||||
fileAction(file.hash, 'resume');
|
||||
},
|
||||
},
|
||||
m('i.fas.fa-play')
|
||||
);
|
||||
|
||||
case 'pause':
|
||||
return m(
|
||||
'button',
|
||||
{
|
||||
title: 'pause',
|
||||
|
||||
onclick() {
|
||||
fileAction(file.hash, 'pause');
|
||||
},
|
||||
},
|
||||
m('i.fas.fa-pause')
|
||||
);
|
||||
|
||||
case 'cancel':
|
||||
return m(
|
||||
'button.red',
|
||||
{
|
||||
title: 'cancel',
|
||||
|
||||
onclick() {
|
||||
widget.popupMessage(
|
||||
m('Cancelpop', [
|
||||
m('p', 'Are you sure you want to cancel download?'),
|
||||
m(
|
||||
'button',
|
||||
{
|
||||
onclick: async () => {
|
||||
const res = await fileAction(file.hash, 'cancel');
|
||||
if (res) {
|
||||
widget.popupMessage(m('p', 'Download Cancelled Successfully'));
|
||||
} else {
|
||||
widget.popupMessage(m('p', 'Download Cancel Failed'));
|
||||
}
|
||||
|
||||
m.redraw();
|
||||
},
|
||||
},
|
||||
'Cancel'
|
||||
),
|
||||
])
|
||||
);
|
||||
// fileAction(file.hash, 'cancel');
|
||||
},
|
||||
},
|
||||
m('i.fas.fa-times')
|
||||
);
|
||||
}
|
||||
rs.rsJsonApiRequest('/rsFiles/FileControl', jsonParams);
|
||||
}
|
||||
|
||||
const ProgressBar = () => {
|
||||
return {
|
||||
view: (v) =>
|
||||
m('.progressbar', [
|
||||
m('span.progressbar-status', {
|
||||
style: {
|
||||
width: v.attrs.rate + '%',
|
||||
},
|
||||
}),
|
||||
m('span.progressbar-percent', v.attrs.rate.toPrecision(3) + '%'),
|
||||
m('.progress-bar-chunks', [
|
||||
v.attrs.chunksInfo.chunks.map((item) => m(`span.chunk[data-chunkVal=${item}]`)),
|
||||
m('span.progress-bar-chunks__percent', v.attrs.rate.toPrecision(3) + '%'),
|
||||
]),
|
||||
};
|
||||
};
|
||||
|
||||
const chunkStrats = {
|
||||
0: 'Streaming', // CHUNK_STRATEGY_STREAMING
|
||||
1: 'Random', // CHUNK_STRATEGY_RANDOM
|
||||
2: 'Progressive', // CHUNK_STRATEGY_PROGRESSIVE
|
||||
};
|
||||
// rstypes.h :: 366
|
||||
|
||||
const File = () => {
|
||||
let chunkStrat;
|
||||
const chunkStrats = {
|
||||
// rstypes.h :: 366
|
||||
0: 'Streaming', // CHUNK_STRATEGY_STREAMING
|
||||
1: 'Random', // CHUNK_STRATEGY_RANDOM
|
||||
2: 'Progressive', // CHUNK_STRATEGY_PROGRESSIVE
|
||||
};
|
||||
function fileCancel(hash) {
|
||||
rs.rsJsonApiRequest('/rsFiles/FileCancel', { hash }).then((res) =>
|
||||
widget.popupMessage(m('p', `Download Cancel ${res ? 'Successful' : 'Failed'}`))
|
||||
);
|
||||
}
|
||||
function cancelFileDownload(hash) {
|
||||
widget.popupMessage([
|
||||
m('p', 'Are you sure you want to cancel download?'),
|
||||
m('button', { onclick: () => fileCancel(hash) }, 'Cancel'),
|
||||
]);
|
||||
}
|
||||
function actionButton(file, action) {
|
||||
return m(
|
||||
'button',
|
||||
{ title: action, onclick: () => fileAction(file.hash, action) },
|
||||
m(`i.fas.fa-${action === 'resume' ? 'play' : action}`)
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
oninit: async (v) => {
|
||||
chunkStrat = await v.attrs.strategy;
|
||||
},
|
||||
view: (v) => {
|
||||
chunkStrat = v.attrs && v.attrs.strategy;
|
||||
return m(
|
||||
'.file-view',
|
||||
{
|
||||
key: v.attrs.info.hash,
|
||||
style: {
|
||||
display: v.attrs.info.isSearched ? 'block' : 'none',
|
||||
},
|
||||
},
|
||||
[
|
||||
m('.file-view__heading', [
|
||||
m('h6', v.attrs.info.fname),
|
||||
!(v.attrs.direction === 'up') && [
|
||||
const { info, direction, transferred, chunksInfo } = v.attrs;
|
||||
function changeChunkStrategy(e) {
|
||||
chunkStrat = e.target.selectedIndex;
|
||||
rs.rsJsonApiRequest('/rsFiles/setChunkStrategy', {
|
||||
hash: info.hash,
|
||||
newStrategy: chunkStrat,
|
||||
});
|
||||
}
|
||||
return m('.file-view', { style: { display: info.isSearched ? 'block' : 'none' } }, [
|
||||
m('.file-view__heading', [
|
||||
m('h6', info.fname),
|
||||
chunkStrat !== undefined &&
|
||||
direction === 'down' && [
|
||||
m('.file-view__heading-chunk', [
|
||||
m('label[for=chunkTag]', 'Set Chunk Strategy: '),
|
||||
m(
|
||||
'select[id=chunkTag]',
|
||||
{
|
||||
value: chunkStrat,
|
||||
onchange: (e) => {
|
||||
chunkStrat = e.target.selectedIndex;
|
||||
rs.rsJsonApiRequest('/rsFiles/setChunkStrategy', {
|
||||
hash: v.attrs.info.hash,
|
||||
newStrategy: chunkStrat,
|
||||
});
|
||||
},
|
||||
},
|
||||
[
|
||||
Object.keys(chunkStrats).map((opt) =>
|
||||
m('option', { value: opt }, chunkStrats[opt])
|
||||
),
|
||||
]
|
||||
),
|
||||
m('select[id=chunkTag]', { value: chunkStrat, onchange: changeChunkStrategy }, [
|
||||
Object.keys(chunkStrats).map((strat) =>
|
||||
m('option', { value: strat }, chunkStrats[strat])
|
||||
),
|
||||
]),
|
||||
]),
|
||||
],
|
||||
]),
|
||||
m('.file-view__body', [
|
||||
m(
|
||||
'.file-view__body-progress',
|
||||
!(v.attrs.direction === 'up') &&
|
||||
m(ProgressBar, {
|
||||
rate: (v.attrs.transferred / v.attrs.info.size.xint64) * 100,
|
||||
})
|
||||
),
|
||||
m('.file-view__body-details', [
|
||||
m('.file-view__body-details-stat', [
|
||||
m('span', m('i.fas.fa-download'), makeFriendlyUnit(v.attrs.transferred)),
|
||||
|
||||
m('span', m('i.fas.fa-file'), makeFriendlyUnit(v.attrs.info.size.xint64)),
|
||||
m(
|
||||
'span',
|
||||
m('i.fas.fa-arrow-circle-' + v.attrs.direction),
|
||||
makeFriendlyUnit(v.attrs.info.tfRate * 1024) + '/s'
|
||||
),
|
||||
!(v.attrs.direction === 'up') &&
|
||||
m('span', { title: 'time remaining' }, [
|
||||
m('i.fas.fa-clock'),
|
||||
calcRemainingTime(
|
||||
v.attrs.info.size.xint64 - v.attrs.transferred,
|
||||
v.attrs.info.tfRate
|
||||
),
|
||||
]),
|
||||
m(
|
||||
'span',
|
||||
{ title: 'peers' },
|
||||
[m('i.fas.fa-users'), v.attrs.info.peers.length],
|
||||
v.attrs.parts.reduce((a, e) => [...a, ' - ' + makeFriendlyUnit(e)], [])
|
||||
),
|
||||
]),
|
||||
m('.file-view__body', [
|
||||
m(
|
||||
'.file-view__body-progress',
|
||||
direction === 'down' &&
|
||||
m(ProgressBar, { rate: (transferred / info.size.xint64) * 100, chunksInfo })
|
||||
),
|
||||
m('.file-view__body-details', [
|
||||
m('.file-view__body-details-stat', [
|
||||
m('span', { title: 'downloaded size' }, [
|
||||
m('i.fas.fa-download'),
|
||||
rs.formatBytes(transferred),
|
||||
]),
|
||||
m(
|
||||
'.file-view__body-details-action',
|
||||
!(v.attrs.info.downloadStatus === FT_STATE_COMPLETE) && [
|
||||
actionButton(
|
||||
v.attrs.info,
|
||||
v.attrs.info.downloadStatus === FT_STATE_PAUSED ? 'resume' : 'pause'
|
||||
),
|
||||
actionButton(v.attrs.info, 'cancel'),
|
||||
]
|
||||
),
|
||||
m('span', { title: 'total size' }, [
|
||||
m('i.fas.fa-file'),
|
||||
rs.formatBytes(info.size.xint64),
|
||||
]),
|
||||
m('span', { title: 'speed' }, [
|
||||
m(`i.fas.fa-arrow-circle-${direction}`),
|
||||
`${rs.formatBytes(info.tfRate * 1024)}/s`,
|
||||
]),
|
||||
direction === 'down' &&
|
||||
m('span', { title: 'time remaining' }, [
|
||||
m('i.fas.fa-clock'),
|
||||
calcRemainingTime(info.size.xint64 - transferred, info.tfRate),
|
||||
]),
|
||||
m('span', { title: 'peers' }, [m('i.fas.fa-users'), info.peers.length]),
|
||||
]),
|
||||
m(
|
||||
'.file-view__body-details-action',
|
||||
info.downloadStatus !== FT_STATE_COMPLETE && [
|
||||
actionButton(info, info.downloadStatus === FT_STATE_PAUSED ? 'resume' : 'pause'),
|
||||
m(
|
||||
'button.red',
|
||||
{ title: 'cancel', onclick: () => cancelFileDownload(info.hash) },
|
||||
m('i.fas.fa-times')
|
||||
),
|
||||
]
|
||||
),
|
||||
]),
|
||||
]
|
||||
);
|
||||
]),
|
||||
]);
|
||||
},
|
||||
};
|
||||
};
|
||||
@ -310,11 +219,8 @@ const SearchBar = () => {
|
||||
oninput: (e) => {
|
||||
searchString = e.target.value.toLowerCase();
|
||||
for (const hash in v.attrs.list) {
|
||||
if (v.attrs.list[hash].fname.toLowerCase().indexOf(searchString) > -1) {
|
||||
v.attrs.list[hash].isSearched = true;
|
||||
} else {
|
||||
v.attrs.list[hash].isSearched = false;
|
||||
}
|
||||
v.attrs.list[hash].isSearched =
|
||||
v.attrs.list[hash].fname.toLowerCase().indexOf(searchString) > -1;
|
||||
}
|
||||
},
|
||||
}),
|
||||
@ -352,14 +258,6 @@ const FriendsFilesTable = () => {
|
||||
]),
|
||||
};
|
||||
};
|
||||
function formatbytes(bytes, decimals = 2) {
|
||||
if (bytes === 0) return '0 Bytes';
|
||||
const k = 1024;
|
||||
const dm = decimals < 0 ? 0 : decimals;
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
RS_FILE_CTRL_PAUSE,
|
||||
@ -376,12 +274,10 @@ module.exports = {
|
||||
RS_FILE_REQ_ANONYMOUS_ROUTING,
|
||||
RS_FILE_HINTS_REMOTE,
|
||||
RS_FILE_HINTS_LOCAL,
|
||||
makeFriendlyUnit,
|
||||
File,
|
||||
SearchBar,
|
||||
compareArrays,
|
||||
MyFilesTable,
|
||||
FriendsFilesTable,
|
||||
formatbytes,
|
||||
proxyObj,
|
||||
createProxy,
|
||||
};
|
||||
|
||||
@ -73,7 +73,7 @@ function displayfiles() {
|
||||
? nameOfId + ' (' + parStruct.details.name.slice(0, 8) + '...)'
|
||||
: parStruct.details.name
|
||||
),
|
||||
m('td', util.formatbytes(parStruct.details.size.xint64)),
|
||||
m('td', rs.formatBytes(parStruct.details.size.xint64)),
|
||||
isFile &&
|
||||
m(
|
||||
'td',
|
||||
|
||||
@ -48,7 +48,7 @@ function displayfiles() {
|
||||
},
|
||||
parStruct.details.name
|
||||
),
|
||||
m('td', util.formatbytes(parStruct.details.size.xint64)),
|
||||
m('td', rs.formatBytes(parStruct.details.size.xint64)),
|
||||
]),
|
||||
parStruct.showChild &&
|
||||
childrenList.map((child) =>
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
const m = require('mithril');
|
||||
const futil = require('files/files_util');
|
||||
|
||||
const RsEventsType = {
|
||||
NONE: 0, // Used internally to detect invalid event type passed
|
||||
@ -170,18 +169,6 @@ function deeperIfExist(map, key, action) {
|
||||
|
||||
const eventQueue = {
|
||||
events: {
|
||||
[RsEventsType.FILE_TRANSFER]: {
|
||||
handler: (event) => {
|
||||
console.log('search results : ', event);
|
||||
|
||||
// if request item doesn't already exists in Object then create new item
|
||||
if (!Object.prototype.hasOwnProperty.call(futil.proxyObj, event.mRequestId)) {
|
||||
futil.proxyObj[event.mRequestId] = [];
|
||||
}
|
||||
|
||||
futil.proxyObj[event.mRequestId].push(...event.mResults);
|
||||
},
|
||||
},
|
||||
[RsEventsType.CHAT_MESSAGE]: {
|
||||
// Chat-Messages
|
||||
types: {
|
||||
@ -336,12 +323,23 @@ function logon(loginHeader, displayAuthError, displayErrorMessage, successful) {
|
||||
});
|
||||
}
|
||||
|
||||
function formatBytes(bytes, decimals = 2) {
|
||||
if (bytes === 0) return '0 Bytes';
|
||||
const k = 1024;
|
||||
const dm = decimals < 0 ? 0 : decimals;
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
rsJsonApiRequest,
|
||||
setKeys,
|
||||
setBackgroundTask,
|
||||
logon,
|
||||
events: eventQueue.events,
|
||||
RsEventsType,
|
||||
userList,
|
||||
loginKey,
|
||||
formatBytes,
|
||||
};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
@use '../abstracts/colors' as *;
|
||||
|
||||
.progressbar {
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 2rem;
|
||||
position: relative;
|
||||
@ -8,7 +8,7 @@
|
||||
background-color: $light-color;
|
||||
border-radius: 20px;
|
||||
overflow: hidden;
|
||||
&-status {
|
||||
&__status {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
@ -16,11 +16,43 @@
|
||||
color: $dark-color;
|
||||
background-color: $primary-color;
|
||||
}
|
||||
&-percent {
|
||||
&__percent {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
margin: auto;
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
}
|
||||
&-chunks {
|
||||
position: relative;
|
||||
margin-top: 0.5rem;
|
||||
width: 100%;
|
||||
height: 2rem;
|
||||
display: flex;
|
||||
border-radius: 0.25rem;
|
||||
overflow: hidden;
|
||||
background-color: $light-color;
|
||||
& .chunk {
|
||||
width: 100%;
|
||||
&[data-chunkVal='0'] {
|
||||
background-color: transparentize($primary-light-color, 0.8);
|
||||
}
|
||||
&[data-chunkVal='1'] {
|
||||
background-color: $red-color;
|
||||
}
|
||||
&[data-chunkVal='2'] {
|
||||
background-color: $primary-color;
|
||||
}
|
||||
&[data-chunkVal='3'] {
|
||||
background-color: $golden-yellow-color;
|
||||
}
|
||||
}
|
||||
&__percent {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
margin: auto;
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user