editing and setting works now
parent
81383f15a4
commit
e2479c0332
|
@ -91,6 +91,8 @@ require('./libs/ffmpeg.js')(s,config,lang, async () => {
|
|||
require('./libs/auth/logins.js')(s,config,lang,app)
|
||||
//rally other Shinobi
|
||||
require('./libs/rally.js')(s,config,lang,app,io)
|
||||
//rally other Shinobi
|
||||
require('./libs/mountManager.js')(s,config,lang,app,io)
|
||||
//on-start actions, daemon(s) starter
|
||||
await require('./libs/startup.js')(s,config,lang)
|
||||
//p2p, commander
|
||||
|
|
|
@ -553,8 +553,14 @@
|
|||
"URL": "URL",
|
||||
"Operating Hours": "Operating Hours",
|
||||
"Autosave": "Autosave",
|
||||
"Source": "Source",
|
||||
"Delete Mount": "Delete Mount",
|
||||
"Mount Path": "Mount Path",
|
||||
"Mount Type": "Mount Type",
|
||||
"Save Directory": "Save Directory",
|
||||
"Path Inside": "Path Inside",
|
||||
"New Videos Directory Set": "New Videos Directory Set",
|
||||
"Use Default Videos Directory": "Use Default Videos Directory",
|
||||
"Set New Videos Directory": "Set New Videos Directory?",
|
||||
"CSS": "CSS <small>Style your dashboard.</small>",
|
||||
"Don't Stretch Monitors": "Don't Stretch Monitors",
|
||||
|
|
|
@ -6,14 +6,15 @@ module.exports = (s,config,lang,app,io) => {
|
|||
modifyConfiguration,
|
||||
} = require('./system/utils.js')(config)
|
||||
const {
|
||||
createMountPoint,
|
||||
mount,
|
||||
update,
|
||||
remove,
|
||||
list,
|
||||
remountAll,
|
||||
remount,
|
||||
unmount
|
||||
unmount,
|
||||
createMountPoint,
|
||||
checkDiskPathExists,
|
||||
} = require('node-fstab');
|
||||
/**
|
||||
* API : Remount All in fstab
|
||||
|
@ -30,16 +31,40 @@ module.exports = (s,config,lang,app,io) => {
|
|||
app.post(config.webPaths.superApiPrefix+':auth/mountManager/mount', function (req,res){
|
||||
s.superAuth(req.params, async (resp) => {
|
||||
const { sourceTarget, localPath, mountType, options } = req.body;
|
||||
try{
|
||||
await createMountPoint(localPath)
|
||||
}catch(err){
|
||||
console.error(err)
|
||||
}
|
||||
const response = await update(sourceTarget, localPath, mountType, options);
|
||||
try{
|
||||
await remount(localPath)
|
||||
}catch(err){
|
||||
console.error(err)
|
||||
const response = { ok: false }
|
||||
if(sourceTarget && localPath){
|
||||
try{
|
||||
const createDirResponse = await createMountPoint(localPath)
|
||||
response.createDirResponse = createDirResponse
|
||||
}catch(err){
|
||||
console.error(err)
|
||||
}
|
||||
try{
|
||||
const { exists } = await checkDiskPathExists(localPath)
|
||||
if(exists){
|
||||
const unmountResponse = await unmount(localPath)
|
||||
response.unmountResponse = unmountResponse
|
||||
}
|
||||
}catch(err){
|
||||
console.error(err)
|
||||
}
|
||||
const updateResponse = await update(sourceTarget, localPath, mountType, options);
|
||||
response.updateResponse = updateResponse
|
||||
response.ok = updateResponse.ok
|
||||
try{
|
||||
const remountResponse = await remount(localPath)
|
||||
response.remountResponse = remountResponse
|
||||
}catch(err){
|
||||
console.error(err)
|
||||
}
|
||||
response.mount = {
|
||||
device: sourceTarget,
|
||||
mountPoint: localPath,
|
||||
type: mountType,
|
||||
options,
|
||||
}
|
||||
}else{
|
||||
response.error = lang['Invalid Data']
|
||||
}
|
||||
s.closeJsonResponse(res, response);
|
||||
},res,req);
|
||||
|
@ -65,15 +90,19 @@ module.exports = (s,config,lang,app,io) => {
|
|||
app.post(config.webPaths.superApiPrefix+':auth/mountManager/setVideosDir', function (req,res){
|
||||
s.superAuth(req.params, async (resp) => {
|
||||
const { localPath, pathInside } = req.body;
|
||||
const isDefaultDir = localPath === '__DIR__/videos';
|
||||
const response = { ok: false }
|
||||
try{
|
||||
const { exists } = await checkDiskPathExists(localPath)
|
||||
const { exists } = isDefaultDir ? { exists: true } : await checkDiskPathExists(localPath)
|
||||
if(exists){
|
||||
const newVideosDirPath = pathInside ? path.join(localPath, pathInside) : localPath;
|
||||
const createDirResponse = isDefaultDir ? true : await createMountPoint(newVideosDirPath)
|
||||
const configError = await modifyConfiguration({
|
||||
videosDir: newVideosDirPath,
|
||||
}, true);
|
||||
response.ok = true;
|
||||
response.configError = configError;
|
||||
response.createDirResponse = createDirResponse;
|
||||
}
|
||||
}catch(err){
|
||||
console.error(err)
|
||||
|
|
|
@ -2,33 +2,37 @@ $(document).ready(function(){
|
|||
const loadedMounts = {}
|
||||
const theEnclosure = $('#superMountManager')
|
||||
const theSearch = $('#mountManagerListSearch')
|
||||
const theTable = $('#mountManagerListTable')
|
||||
const theTable = $('#mountManagerListTable tbody')
|
||||
const newMountForm = $('#mountManagerNewMount')
|
||||
function getMountId(theMount){
|
||||
return `${theMount.mountPoint.split('/').join('_')}`
|
||||
}
|
||||
function drawMountToTable(theMount){
|
||||
var html = `
|
||||
<tr row-mounted="${getMountId(theMount)}">
|
||||
<td class="align-middle">
|
||||
<div>${theMount.device}</div>
|
||||
<div><small>${theMount.mountPoint}</small></div>
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
${theMount.type}
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
${theMount.options}
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
<a class="btn btn-primary btn-sm cursor-pointer edit" title="${lang.Edit}"><i class="fa fa-pencil-square-o"></i></a>
|
||||
<a class="btn btn-success btn-sm cursor-pointer setVideosDir" title="${lang.videosDir}"><i class="fa fa-download"></i></a>
|
||||
<a class="btn btn-danger btn-sm cursor-pointer delete" title="${lang.Delete}"><i class="fa fa-trash-o"></i></a>
|
||||
</td>
|
||||
</tr>`
|
||||
theTable.append(html)
|
||||
}
|
||||
function drawMountsTable(data){
|
||||
var html = ''
|
||||
theTable.empty()
|
||||
$.each(data,function(n,theMount){
|
||||
html += `
|
||||
<tr row-mounted="${getMountId(theMount)}">
|
||||
<td class="align-middle">
|
||||
<div>${theMount.device}</div>
|
||||
<div><small>${theMount.mountPoint}</small></div>
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
${theMount.type}
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
${theMount.options}
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
<a class="btn btn-success btn-sm cursor-pointer setVideosDir" title="${lang.videosDir}"><i class="fa fa-download"></i></a>
|
||||
<a class="btn btn-danger btn-sm cursor-pointer delete" title="${lang.Delete}"><i class="fa fa-trash-o"></i></a>
|
||||
</td>
|
||||
</tr>`
|
||||
})
|
||||
downloadListElement.html(html)
|
||||
drawMountToTable(theMount)
|
||||
});
|
||||
}
|
||||
function filterMountsTable(theSearch = '') {
|
||||
var searchQuery = theSearch.trim().toLowerCase();
|
||||
|
@ -52,10 +56,10 @@ $(document).ready(function(){
|
|||
function loadMounts(callback) {
|
||||
return new Promise((resolve,reject) => {
|
||||
$.getJSON(superApiPrefix + $user.sessionKey + '/mountManager/list',function(data){
|
||||
$.each(data,function(n,theMount){
|
||||
$.each(data.mounts,function(n,theMount){
|
||||
loadedMounts[getMountId(theMount)] = theMount;
|
||||
})
|
||||
drawMountsTable(data)
|
||||
drawMountsTable(data.mounts)
|
||||
resolve(data)
|
||||
})
|
||||
})
|
||||
|
@ -79,7 +83,7 @@ $(document).ready(function(){
|
|||
}
|
||||
function setVideosDir(localPath, pathInside) {
|
||||
return new Promise((resolve,reject) => {
|
||||
$.post(superApiPrefix + $user.sessionKey + '/mountManager/removeMount',{
|
||||
$.post(superApiPrefix + $user.sessionKey + '/mountManager/setVideosDir',{
|
||||
localPath,
|
||||
pathInside
|
||||
},function(data){
|
||||
|
@ -87,46 +91,10 @@ $(document).ready(function(){
|
|||
})
|
||||
})
|
||||
}
|
||||
newMountForm.submit(async function(e){
|
||||
e.preventDefault();
|
||||
const form = newMountForm.serializeObject();
|
||||
const response = await addMount(form);
|
||||
const notify = {
|
||||
title: lang['Mount Added'],
|
||||
type: 'success'
|
||||
}
|
||||
if(!response.ok){
|
||||
notify.title = lang['Failed to Add Mount']
|
||||
notify.text = response.error
|
||||
notify.type = 'danger'
|
||||
}
|
||||
new PNotify(notify)
|
||||
return false;
|
||||
});
|
||||
theTable.on('click','.delete', async function(e){
|
||||
const el = $(this).parents('[row-mounted]')
|
||||
const mountId = el.attr('row-mounted');
|
||||
const theMount = loadedMounts[mountId]
|
||||
const localPath = theMount.mountPoint
|
||||
const response = await removeMount(localPath);
|
||||
if(response.ok){
|
||||
el.remove()
|
||||
}else{
|
||||
new PNotify({
|
||||
title: lang['Failed to Remove Mount'],
|
||||
text: lang['See System Logs'],
|
||||
type: 'danger'
|
||||
})
|
||||
}
|
||||
})
|
||||
theTable.on('click','.setVideosDir', function(e){
|
||||
const el = $(this).parents('[row-mounted]')
|
||||
const mountId = el.attr('row-mounted');
|
||||
const theMount = loadedMounts[mountId]
|
||||
const localPath = theMount.mountPoint
|
||||
function launchSetVideoDirConfirm(localPath){
|
||||
$.confirm.create({
|
||||
title: lang['Set New Videos Directory'],
|
||||
body: `${lang.restartRequired}<br><br><input class="form-control" id="newVideosDirInnerPath">? `,
|
||||
body: `<b>${lang.Path} : ${localPath}</b><br>${lang.restartRequired}<br><br><input placeholder="${lang['Path Inside']}" class="form-control" id="newVideosDirInnerPath">`,
|
||||
clickOptions: {
|
||||
class: 'btn-success',
|
||||
title: lang.Save,
|
||||
|
@ -149,6 +117,78 @@ $(document).ready(function(){
|
|||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
newMountForm.submit(async function(e){
|
||||
e.preventDefault();
|
||||
const form = newMountForm.serializeObject();
|
||||
$.each(form, function(key,val){form[key] = val.trim()});
|
||||
const response = await addMount(form);
|
||||
const notify = {
|
||||
title: lang['Mount Added'],
|
||||
type: 'success'
|
||||
}
|
||||
if(!response.ok){
|
||||
notify.title = lang['Failed to Add Mount']
|
||||
notify.text = response.error
|
||||
notify.type = 'danger'
|
||||
}else{
|
||||
const theMount = response.mount
|
||||
const mountId = getMountId(theMount);
|
||||
theTable.find(`[row-mounted="${mountId}"]`).remove()
|
||||
loadedMounts[mountId] = theMount;
|
||||
drawMountToTable(theMount);
|
||||
}
|
||||
new PNotify(notify)
|
||||
return false;
|
||||
});
|
||||
theTable.on('click','.delete', async function(e){
|
||||
const el = $(this).parents('[row-mounted]')
|
||||
const mountId = el.attr('row-mounted');
|
||||
const theMount = loadedMounts[mountId]
|
||||
const localPath = theMount.mountPoint
|
||||
$.confirm.create({
|
||||
title: lang['Delete Mount'],
|
||||
body: `<b>${localPath} (${theMount.type})</b>`,
|
||||
clickOptions: {
|
||||
class: 'btn-danger',
|
||||
title: lang.Delete,
|
||||
},
|
||||
clickCallback: async function(){
|
||||
const response = await removeMount(localPath);
|
||||
if(response.ok){
|
||||
el.remove()
|
||||
}else{
|
||||
new PNotify({
|
||||
title: lang['Failed to Remove Mount'],
|
||||
text: lang['See System Logs'],
|
||||
type: 'danger'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
loadMounts()
|
||||
theTable.on('click','.edit', async function(e){
|
||||
const el = $(this).parents('[row-mounted]')
|
||||
const mountId = el.attr('row-mounted');
|
||||
const theMount = loadedMounts[mountId]
|
||||
newMountForm.find('[name="sourceTarget"]').val(theMount.device)
|
||||
newMountForm.find('[name="localPath"]').val(theMount.mountPoint)
|
||||
newMountForm.find('[name="mountType"]').val(theMount.type)
|
||||
newMountForm.find('[name="options"]').val(theMount.options)
|
||||
})
|
||||
theTable.on('click','.setVideosDir', function(e){
|
||||
const el = $(this).parents('[row-mounted]')
|
||||
const mountId = el.attr('row-mounted');
|
||||
const theMount = loadedMounts[mountId]
|
||||
const localPath = theMount.mountPoint
|
||||
launchSetVideoDirConfirm(localPath)
|
||||
})
|
||||
theEnclosure.on('click','.setDefaultVideosDir', function(e){
|
||||
launchSetVideoDirConfirm('__DIR__/videos')
|
||||
})
|
||||
theSearch.keydown(function(){
|
||||
const value = $(this).val().trim()
|
||||
filterMountsTable(value)
|
||||
})
|
||||
onInitSuccess(loadMounts)
|
||||
})
|
||||
|
|
|
@ -3,27 +3,35 @@
|
|||
<form class="card bg-dark grey mt-1" id="mountManagerNewMount">
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<input type="text" placeholder="192.11.11.11:/samba/share" class="form-control" name="sourceTarget" />
|
||||
<label><%- lang.Source %></label>
|
||||
<input type="text" placeholder="//192.168.1.200/shared/folder" class="form-control" name="sourceTarget" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label><%- lang['Mount Path'] %></label>
|
||||
<input type="text" placeholder="/mnt/newmount" class="form-control" name="localPath" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label><%- lang['Mount Type'] %></label>
|
||||
<select type="text" class="form-control" name="mountType">
|
||||
<option value="nfs" selected>NFS</option>
|
||||
<option value="cifs" selected>CIFS</option>
|
||||
<option value="nfs">NFS</option>
|
||||
<option value="ext4">ext4</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="text" placeholder="rw,async 0 0" value="rw,async 0 0" class="form-control" name="options" />
|
||||
<label><%- lang.Options %></label>
|
||||
<input type="text" placeholder="username=username,password=password,rw,iocharset=utf8,file_mode=0777,dir_mode=0777 0 0" value="username=username,password=password,rw,iocharset=utf8,file_mode=0777,dir_mode=0777 0 0" class="form-control" name="options" />
|
||||
</div>
|
||||
<div><button type="submit" class="btn btn-round btn-block btn-default mb-0"><i class="fa fa-check"></i> <%- lang.Save %></button></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-content pt-4 pb-0 m-0">
|
||||
<div class="tab-pane" id="mountManagerList">
|
||||
<div class="pt-4 pb-0 m-0">
|
||||
<div id="mountManagerList">
|
||||
<div class="form-group">
|
||||
<a class="btn btn-block btn-info setDefaultVideosDir"><%- lang['Use Default Videos Directory'] %></a>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input id="mountManagerListSearch" type="text" placeholder="<%- lang.Search %>" class="form-control" />
|
||||
</div>
|
||||
|
|
|
@ -89,6 +89,9 @@
|
|||
<li class="nav-item">
|
||||
<a class="nav-link" data-bs-toggle="tab" data-bs-target="#superPluginManager" role="tab"><%-lang['Plugin Manager']%></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-bs-toggle="tab" data-bs-target="#superMountManager" role="tab"><%-lang['Mount Manager']%></a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="card-body text-white" style="background:#263343">
|
||||
<!-- Tab panes -->
|
||||
|
@ -223,7 +226,10 @@ switch($user.lang){
|
|||
$.ccio.ws = io(`${location.origin.split('/super')[0]}/`,{
|
||||
path : tool.checkCorrectPathEnding(location.pathname)+'socket.io'
|
||||
});
|
||||
|
||||
const onInitSuccessExtensions = [];
|
||||
function onInitSuccess(theAction){
|
||||
onInitSuccessExtensions.push(theAction)
|
||||
}
|
||||
$.ccio.cx=function(x){return $.ccio.ws.emit('super',x)}
|
||||
$.ccio.ws.on('connect',function(d){
|
||||
$.ccio.cx({f:'init',mail:$user.mail,pass:$user.pass,machineId: `<%- config.machineId %>`})
|
||||
|
@ -235,6 +241,9 @@ $.ccio.ws.on('f',function(d){
|
|||
drawUserList()
|
||||
drawSystemLogs()
|
||||
drawSystemInfo()
|
||||
onInitSuccessExtensions.forEach((theAction) => {
|
||||
theAction()
|
||||
})
|
||||
break;
|
||||
case'log':
|
||||
$.ccio.tm(4,d.log,'#logs-list')
|
||||
|
|
Loading…
Reference in New Issue