editing and setting works now

mount-manager
Moe 2024-11-01 17:13:44 -07:00
parent 81383f15a4
commit e2479c0332
6 changed files with 176 additions and 82 deletions

View File

@ -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

View File

@ -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",

View File

@ -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)

View File

@ -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)
})

View File

@ -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>

View File

@ -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')