first new commit

This commit is contained in:
2023-01-22 10:53:09 +01:00
commit 869f192031
280 changed files with 101529 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
pwa = pwa || {};
pwa.main = pwa.main || {};
pwa.main.tpldata = pwa.main.tpldata || {};
pwa.main.tpl = pwa.main.tpl || {};
//menu
pwa.main.tpldata.sidebarAdminapixtribe = `static/components/adminapixtribe/sidebaradminapixtribe`;
// Custom data in user lang
//tremplate to store
pwa.main.tpl.adminapixtribe = 'static/components/adminapixtribe/adminapixtribe.mustache';
pwa.main.tpl.adminapixtribesysinfo = 'static/components/adminapixtribe/adminapixtribesysinfo.mustache';
pwa.main.tpl.adminapixtribeactivity = 'static/components/adminapixtribe/adminapixtribeactivity.mustache';
pwa.adminapixtribe = {};
pwa.adminapixtribe.init = () => {
// Run back stuff to update data
}
pwa.adminapixtribe.sysinfoview = () => {
const datasysinfo = {}; //request to get info and push them in template
document.getElementById( 'maincontent' )
.innerHTML = Mustache.render( pwa.state.data.tpl.adminapixtribesysinfo, datasysinfo );
}
pwa.adminapixtribe.activityview = () => {
const dataactivity = {}; //request to get info and push them in template
document.getElementById( 'maincontent' )
.innerHTML = Mustache.render( pwa.state.data.tpl.adminapixtribeactivity, dataactivity );
}
pwa.adminapixtribe.tribeidview = () => {
const datatribeid = {}; //request to get info and push them in template
document.getElementById( 'maincontent' )
.innerHTML = Mustache.render( pwa.state.data.tpl.adminapixtribe, datatribeid );
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,234 @@
<div class="mb-3">
<h1 class="h3 d-inline align-middle">tribeids</h1><a class="badge bg-primary ms-2" href="" target="_blank">120 <i class="fas fa-fw fa-external-link-alt"></i></a>
</div>
<div class="row">
<div class="col-xl-8">
<div class="card">
<div class="card-header pb-0">
<div class="card-actions float-end">
<div class="dropdown position-relative">
<a href="#" data-bs-toggle="dropdown" data-bs-display="static" aria-expanded="false" class="">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-more-horizontal align-middle"><circle cx="12" cy="12" r="1"></circle><circle cx="19" cy="12" r="1"></circle><circle cx="5" cy="12" r="1"></circle></svg>
</a>
<div class="dropdown-menu dropdown-menu-end">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</div>
</div>
<h5 class="card-title mb-0">Tribes</h5>
</div>
<div class="card-body">
<table class="table table-striped" style="width:100%">
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Company</th>
<th>Email</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td><img src="img/avatars/avatar.jpg" width="32" height="32" class="rounded-circle my-n1" alt="Avatar"></td>
<td>Garrett Winters</td>
<td>Good Guys</td>
<td>garrett@winters.com</td>
<td><span class="badge bg-success">Active</span></td>
</tr>
<tr>
<td><img src="img/avatars/avatar.jpg" width="32" height="32" class="rounded-circle my-n1" alt="Avatar"></td>
<td>Ashton Cox</td>
<td>Levitz Furniture</td>
<td>ashton@cox.com</td>
<td><span class="badge bg-success">Active</span></td>
</tr>
<tr>
<td><img src="img/avatars/avatar.jpg" width="32" height="32" class="rounded-circle my-n1" alt="Avatar"></td>
<td>Sonya Frost</td>
<td>Child World</td>
<td>sonya@frost.com</td>
<td><span class="badge bg-danger">Deleted</span></td>
</tr>
<tr>
<td><img src="img/avatars/avatar.jpg" width="32" height="32" class="rounded-circle my-n1" alt="Avatar"></td>
<td>Jena Gaines</td>
<td>Helping Hand</td>
<td>jena@gaines.com</td>
<td><span class="badge bg-warning">Inactive</span></td>
</tr>
<tr>
<td><img src="img/avatars/avatar-2.jpg" width="32" height="32" class="rounded-circle my-n1" alt="Avatar"></td>
<td>Charde Marshall</td>
<td>Price Savers</td>
<td>charde@marshall.com</td>
<td><span class="badge bg-success">Active</span></td>
</tr>
<tr>
<td><img src="img/avatars/avatar-2.jpg" width="32" height="32" class="rounded-circle my-n1" alt="Avatar"></td>
<td>Haley Kennedy</td>
<td>Helping Hand</td>
<td>haley@kennedy.com</td>
<td><span class="badge bg-danger">Deleted</span></td>
</tr>
<tr>
<td><img src="img/avatars/avatar-2.jpg" width="32" height="32" class="rounded-circle my-n1" alt="Avatar"></td>
<td>Tatyana Fitzpatrick</td>
<td>Good Guys</td>
<td>tatyana@fitzpatrick.com</td>
<td><span class="badge bg-success">Active</span></td>
</tr>
<tr>
<td><img src="img/avatars/avatar-3.jpg" width="32" height="32" class="rounded-circle my-n1" alt="Avatar"></td>
<td>Michael Silva</td>
<td>Red Robin Stores</td>
<td>michael@silva.com</td>
<td><span class="badge bg-success">Active</span></td>
</tr>
<tr>
<td><img src="img/avatars/avatar-3.jpg" width="32" height="32" class="rounded-circle my-n1" alt="Avatar"></td>
<td>Angelica Ramos</td>
<td>The Wiz</td>
<td>angelica@ramos.com</td>
<td><span class="badge bg-success">Active</span></td>
</tr>
<tr>
<td><img src="img/avatars/avatar-4.jpg" width="32" height="32" class="rounded-circle my-n1" alt="Avatar"></td>
<td>Jennifer Chang</td>
<td>Helping Hand</td>
<td>jennifer@chang.com</td>
<td><span class="badge bg-warning">Inactive</span></td>
</tr>
<tr>
<td><img src="img/avatars/avatar-4.jpg" width="32" height="32" class="rounded-circle my-n1" alt="Avatar"></td>
<td>Brenden Wagner</td>
<td>The Wiz</td>
<td>brenden@wagner.com</td>
<td><span class="badge bg-warning">Inactive</span></td>
</tr>
<tr>
<td><img src="img/avatars/avatar-4.jpg" width="32" height="32" class="rounded-circle my-n1" alt="Avatar"></td>
<td>Fiona Green</td>
<td>The Sample</td>
<td>fiona@green.com</td>
<td><span class="badge bg-warning">Inactive</span></td>
</tr>
<tr>
<td><img src="img/avatars/avatar-5.jpg" width="32" height="32" class="rounded-circle my-n1" alt="Avatar"></td>
<td>Prescott Bartlett</td>
<td>The Sample</td>
<td>prescott@bartlett.com</td>
<td><span class="badge bg-success">Active</span></td>
</tr>
<tr>
<td><img src="img/avatars/avatar-5.jpg" width="32" height="32" class="rounded-circle my-n1" alt="Avatar"></td>
<td>Gavin Cortez</td>
<td>Red Robin Stores</td>
<td>gavin@cortez.com</td>
<td><span class="badge bg-success">Active</span></td>
</tr>
<tr>
<td><img src="img/avatars/avatar-5.jpg" width="32" height="32" class="rounded-circle my-n1" alt="Avatar"></td>
<td>Howard Hatfield</td>
<td>Price Savers</td>
<td>howard@hatfield.com</td>
<td><span class="badge bg-warning">Inactive</span></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="col-xl-4">
<div class="card">
<div class="card-header">
<div class="card-actions float-end">
<div class="dropdown position-relative">
<a href="#" data-bs-toggle="dropdown" data-bs-display="static">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-more-horizontal align-middle"><circle cx="12" cy="12" r="1"></circle><circle cx="19" cy="12" r="1"></circle><circle cx="5" cy="12" r="1"></circle></svg>
</a>
<div class="dropdown-menu dropdown-menu-end">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</div>
</div>
<h5 class="card-title mb-0">Angelica Ramos</h5>
</div>
<div class="card-body">
<div class="row g-0">
<div class="col-sm-3 col-xl-12 col-xxl-3 text-center">
<img src="img/avatars/avatar-3.jpg" width="64" height="64" class="rounded-circle mt-2" alt="Angelica Ramos">
</div>
<div class="col-sm-9 col-xl-12 col-xxl-9">
<strong>About me</strong>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua.</p>
</div>
</div>
<table class="table table-sm mt-2 mb-4">
<tbody>
<tr>
<th>Name</th>
<td>Angelica Ramos</td>
</tr>
<tr>
<th>Company</th>
<td>The Wiz</td>
</tr>
<tr>
<th>Email</th>
<td>angelica@ramos.com</td>
</tr>
<tr>
<th>Phone</th>
<td>+1234123123123</td>
</tr>
<tr>
<th>Status</th>
<td><span class="badge bg-success">Active</span></td>
</tr>
</tbody>
</table>
<strong>Activity</strong>
<ul class="timeline mt-2 mb-0">
<li class="timeline-item">
<strong>Signed out</strong>
<span class="float-end text-muted text-sm">30m ago</span>
<p>Nam pretium turpis et arcu. Duis arcu tortor, suscipit...</p>
</li>
<li class="timeline-item">
<strong>Created invoice #1204</strong>
<span class="float-end text-muted text-sm">2h ago</span>
<p>Sed aliquam ultrices mauris. Integer ante arcu...</p>
</li>
<li class="timeline-item">
<strong>Discarded invoice #1147</strong>
<span class="float-end text-muted text-sm">3h ago</span>
<p>Nam pretium turpis et arcu. Duis arcu tortor, suscipit...</p>
</li>
<li class="timeline-item">
<strong>Signed in</strong>
<span class="float-end text-muted text-sm">3h ago</span>
<p>Curabitur ligula sapien, tincidunt non, euismod vitae...</p>
</li>
<li class="timeline-item">
<strong>Signed up</strong>
<span class="float-end text-muted text-sm">2d ago</span>
<p>Sed aliquam ultrices mauris. Integer ante arcu...</p>
</li>
</ul>
</div>
</div>
</div>
</div>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,22 @@
{
"groupheader": "Admin apixtribe",
"sbssgroupmenu": [{
"name": "Activité",
"icon": "sliders",
"actionclick": "pwa.adminapixtribe.init()",
"iditemmenus": "adminxpress",
"itemmenus": [{
"name": "Info activités",
"actionclick": "pwa.adminapixtribe.activityview()"
},
{
"name": "Admin des tribeid",
"actionclick": "pwa.adminapixtribe.tribeidview()"
}
]
}, {
"name": "System Info",
"icon": "sliders",
"actionclick": "pwa.adminapixtribe.sysinfoview()"
}]
}

View File

@@ -0,0 +1,22 @@
{
"groupheader": "Admin apixtribe",
"sbssgroupmenu": [{
"name": "Tribes",
"icon": "sliders",
"actionclick": "pwa.tribeids.init()",
"iditemmenus": "admintribeid",
"itemmenus": [{
"name": "Suivi des tribeid",
"actionclick": "pwa.tribeids.tribeidactivity()"
},
{
"name": "Admin des tribeid",
"actionclick": "pwa.tribeids.settings()"
}
]
}, {
"name": "Suivi technique",
"icon": "sliders",
"actionclick": "pwa.tribeids.suivi()"
}]
}

View File

@@ -0,0 +1,145 @@
// app management sidebar and navbar
/*
Load into pwa.state.data.tpl[name] templates content
appsidebarmenu.mustache side menu sbgroupmenu:[list of submenu]
apptopbarmenu.mustache top menu menuprofil:[ list of submenu]
apptopbarnotification.mustache show a dropdown list if withnotification is true
apptopbarmessage.mustache show a dropdown list if withmessage is true
Load list of public data into pwa.state.data.menu
sidebar
topbar
Then add specific menu in based on login list into
pwa.state.data.login.user.ACCESSRIGHTS.app[tribeid:website]
each name starting by sidebar is added into sidebar.subgroupmenu
each name starting by topbar is added into topbar.menuprofil
*/
var pwa = pwa || {};
pwa.app = {};
pwa.app.init = async () => {
//Load template in pwa.state.data.tpl
console.log( 'app.init()' );
const tpllist = {};
[ 'appsidebarmenu', 'apptopbarmenu', 'apptopbarnotification', 'apptopbarmessage' ].forEach( c => {
tpllist[ c ] = `static/components/appmesa/${c}.mustache`
} );
// add other generic public template, carefull name have to be unique
tpllist[ 'notiflist' ] = `static/components/notification/notiflist.mustache`;
// tpllist[ 'msglist' ] = `static/components/messagerie/msglist.mustache`;
tpllist[ 'verticaltab' ] = `static/components/verticaltab/verticaltab.mustache`;
await pwa.state.loadfile( tpllist, "tpl" );
await pwa.app.getcontent();
//get menu depending of user profile: tribeid:app
};
pwa.app.getcontent = async () => {
const menubase = {};
let menu = [ 'sidebar', 'topbar' ];
//check if authentify and add specific menu
if( pwa.state.data.login && pwa.state.data.login.isAuthenticated ) {
//Get personnal menu user.ACCESSRIGHTS={app:{ "tribeid:website":{sidebar,top}
const appname = `${pwa.state.data.ctx.tribeid}:${pwa.state.data.ctx.website}`
//console.log( 'with ', appname )
menu = menu.concat( pwa.state.data.login.user.ACCESSRIGHTS.app[ appname ] )
}
//console.log( 'update pwa.state.data.menu with ', menu )
menu.forEach( c => { menubase[ c ] = `static/data/${c}_${pwa.state.data.ctx.lang}.json` } );
await pwa.state.loadfile( menubase, 'menu' );
pwa.app.loadsidebarmenu( menu.filter( m => m.includes( 'sidebar' ) ) )
pwa.app.loadtopmenu( menu.filter( m => m.includes( 'topbar' ) ) );
//active les icones svg de feather
feather.replace();
//active scroll presentation + sidebar animation
pwa.app.simplebar();
pwa.app.clickactive();
}
pwa.app.loadsidebarmenu = ( list ) => {
//console.log( 'list de menu sidebar', list )
const data = pwa.state.data.menu.sidebar
for( let m of list ) {
if( m != 'sidebar' ) {
console.log( m )
data.sbgroupmenu = data.sbgroupmenu.concat( pwa.state.data.menu[ m ] )
}
}
//console.log( data )
document.querySelector( "#sidebar" )
.innerHTML = Mustache.render( pwa.state.data.tpl.appsidebarmenu, data )
}
pwa.app.loadtopmenu = ( list ) => {
const data = pwa.state.data.menu.topbar
for( let m of list ) {
if( m != 'topbar' ) {
data.menuprofil = data.menuprofil.concat( pwa.state.data.menu[ m ] )
}
}
//update date from login if authenticated
if( pwa.state.data.login.isAuthenticated ) {
//remove the login item from menuprofil
data.menuprofil.shift();
data.name = pwa.state.data.login.user.NAME;
data.avatarimg = pwa.state.data.login.user.AVATARIMG;
// get notification / message if exist
//const notifsrc= `${pwa.urlbackauth}/Tribes/logs/`;
if( pwa.state.data.menu.topbar.withnotification ) {
pwa.notification.update();
}
if( pwa.state.data.menu.topbar.withmessage ) {
//pwa.message.update( );
}
}
//console.log( 'topbar data', data.menuprofil );
document.querySelector( "#navbar" )
.innerHTML = Mustache.render( pwa.state.data.tpl.apptopbarmenu, data )
}
pwa.app.simplebar = () => {
const simpleBarElement = document.getElementsByClassName( "js-simplebar" )[ 0 ];
if( simpleBarElement ) {
/* Initialize simplebar */
new SimpleBar( document.getElementsByClassName( "js-simplebar" )[ 0 ] )
const sidebarElement = document.getElementsByClassName( "sidebar" )[ 0 ];
const sidebarToggleElement = document.getElementsByClassName( "sidebar-toggle" )[ 0 ];
sidebarToggleElement.addEventListener( "click", () => {
sidebarElement.classList.toggle( "collapsed" );
sidebarElement.addEventListener( "transitionend", () => {
window.dispatchEvent( new Event( "resize" ) );
} );
} );
}
}
pwa.app.clickactive = () => {
const cleanactive = () => {
const el = document.querySelectorAll( '.sidebar-item' )
for( var i = 0; i < el.length; i++ ) {
//console.log( 'clean', el[ i ].classList )
el[ i ].classList.remove( 'active' );
}
}
document.addEventListener( "click", ( e ) => {
console.log( 'click', e );
if( e.target.classList.contains( 'sidebar-link' ) ) {
cleanactive();
e.target.closest( '.sidebar-item' )
.classList.add( 'active' );
// remonte au menu au dessus si existe
e.target.closest( '.sidebar-item' )
.closest( '.sidebar-item' )
.classList.add( 'active' );
}
} );
// If enter run the research
document.getElementById( 'globalsearch' )
.addEventListener( 'keypress', ( e ) => {
if( e.keyCode == 13 ) {
pwa.search.req( 'globalsearch' );
e.preventDefault();
}
} )
};

View File

@@ -0,0 +1,5 @@
<!-- div id="maincontent" class="container-fluid p-0" -->
<p>Content when js is desactivated</p>
<!--/div-->

View File

@@ -0,0 +1,29 @@
<!-- div class="wrapper" -->
<nav id="sidebar" class="sidebar"></nav>
<div class="main">
<nav id ="navbar" class="navbar {{navbarclass}}"></nav>
<main class="content">
<importhtml></importhtml>
</main>
<footer class="footer">
<div class="container-fluid">
<div class="row text-muted">
<div class="col-6 text-start">
<p class="mb-0">
<a href="{{{urlapixtribe}}}" class="text-muted"><strong>{{claim}}</strong></a> &copy;
</p>
</div>
<div class="col-6 text-end">
<ul class="list-inline">
{{#links}}
<li class="list-inline-item">
<a class="text-muted" href="{{{url}}}">{{{desc}}}</a>
</li>
{{/links}}
</ul>
</div>
</div>
</div>
</footer>
</div>
<!-- /div -->

View File

@@ -0,0 +1,33 @@
<div class="sidebar-content js-simplebar">
<a class="sidebar-brand" href="{{sbbrandlink}}">
<span class="align-middle">{{{sbtitle}}}</span>
</a>
{{#sbgroupmenu}}
<ul class="sidebar-nav">
<li class="sidebar-header">
{{{groupheader}}}
</li>
{{#sbssgroupmenu}}
<li class="sidebar-item ">
{{^iditemmenus}}
<a class="sidebar-link" onclick="{{actionclick}}">
<i class="align-middle" data-feather="{{icon}}"></i>
<span class="align-middle">{{name}}</span>
</a>
{{/iditemmenus}}
{{#iditemmenus}}
<a data-bs-target="#{{iditemmenus}}" data-bs-toggle="collapse" class="sidebar-link collapsed">
<i class="align-middle" data-feather="{{icon}}"></i>
<span class="align-middle">{{name}}</span>
</a>
<ul id="{{iditemmenus}}" class="sidebar-dropdown list-unstyled collapse " data-bs-parent="#sidebar">
{{#itemmenus}}
<li class="sidebar-item"><a class="sidebar-link" onclick="{{actionclick}}">{{name}}</a></li>
{{/itemmenus}}
</ul>
{{/iditemmenus}}
</li>
{{/sbssgroupmenu}}
</ul>
{{/sbgroupmenu}}
</div>

View File

@@ -0,0 +1,61 @@
<a class="sidebar-toggle d-flex">
<i class="hamburger align-self-center"></i>
</a>
{{#withsearch}}
<form class="d-none d-sm-inline-block">
<div class="input-group input-group-navbar">
<input type="text" id="globalsearch" class="form-control" placeholder="{{{searchtxt}}}" aria-label="Search">
<button class="btn" type="button" onclick="pwa.search.req('globalsearch');return false;" cancelhref="?action=search.req&idsearchtxt=globalsearch">
<i class="align-middle" data-feather="search"></i>
</button>
</div>
</form>
{{/withsearch}}
<div class="navbar-collapse collapse">
<ul id="topbarmenuright" class="navbar-nav navbar-align">
{{#withnotif}}
<li id="notiflist" class="nav-item dropdown">
</li>
{{/withnotif}}
{{#withmessage}}
<li class="nav-item dropdown">
<a class="nav-icon dropdown-toggle" href="#" id="messagesDropdown" data-bs-toggle="dropdown">
<div class="position-relative">
<i class="align-middle" data-feather="message-square"></i>
<span class="indicator">0</span>
</div>
</a>
<div class="dropdown-menu dropdown-menu-lg dropdown-menu-end py-0" aria-labelledby="messagesDropdown">
<div class="dropdown-menu-header">
<div class="position-relative">
{{{messageheader}}}
</div>
</div>
<div id="topmenumessages" class="list-group">
</div>
<div class="dropdown-menu-footer">
<a href="#" class="text-muted">{{{messagefooter}}}</a>
</div>
</div>
</li>
{{/withmessage}}
<li class="nav-item dropdown">
<a class="nav-icon dropdown-toggle d-inline-block d-sm-none" href="#" data-bs-toggle="dropdown">
<i class="align-middle" data-feather="settings"></i>
</a>
<a class="nav-link dropdown-toggle d-none d-sm-inline-block" href="#" data-bs-toggle="dropdown">
<img src="{{avatarimg}}" class="avatar img-fluid rounded me-1" alt="avatar" /> <span class="text-dark">{{name}}</span>
</a>
<div class="dropdown-menu dropdown-menu-end">
{{#menuprofil}}
<a class="dropdown-item" href="{{{href}}}">
<i class="align-middle me-1" data-feather="{{{icon}}}"></i> {{{desc}}}
</a>
{{#menubreaker}}
<div class="dropdown-divider"></div>
{{/menubreaker}}
{{/menuprofil}}
</div>
</li>
</ul>
</div>

View File

@@ -0,0 +1,16 @@
<div class="list-group">
{{#messages}}
<a href="#" class="list-group-item">
<div class="row g-0 align-items-center">
<div class="col-2">
<img src="{{{imgsrc}}}" class="avatar img-fluid rounded-circle" alt="Vanessa Tucker">
</div>
<div class="col-10">
<div class="text-dark">{{{name}}}</div>
<div class="text-muted small mt-1">{{{subject}}}.</div>
<div class="text-muted small mt-1">{{{elapse}}}</div>
</div>
</div>
</a>
{{/messages}}
</div>

View File

@@ -0,0 +1,16 @@
<div class="list-group">
{{#notifications}}
<a href="#" class="list-group-item">
<div class="row g-0 align-items-center">
<div class="col-2">
<i class="{{{classicon}}}" data-feather="{{{icon}}}"></i>
</div>
<div class="col-10">
<div class="text-dark">{{{titre}}}</div>
<div class="text-muted small mt-1">{{{description}}}.</div>
<div class="text-muted small mt-1">{{{elapse}}}</div>
</div>
</div>
</a>
{{/notifications}}
</div>

View File

@@ -0,0 +1,14 @@
{
"navbarclass": "navbar-expand navbar-light navbar-bg",
"footer": {
"urlapixtribe": "https://apixtribe.org",
"claim": "apixtribe made with love for freedom",
"links": [{
"url": "#",
"desc": "Support"
}, {
"url": "#",
"desc": "Privacy"
}]
}
}

View File

@@ -0,0 +1,47 @@
{
"groupheader": "Mon espace client",
"sbssgroupmenu": [{
"name": "Espace web",
"icon": "sliders",
"actionclick": "pwa.spaceweb.init()",
"iditemmenus": "clentidspace",
"itemmenus": [{
"name": "Mon espace web",
"actionclick": "pwa.spaceweb.myfile()"
},
{
"name": "Mes utilisateurs",
"actionclick": "pwa.spaceweb.users()"
},
{
"name": "Mes contenus",
"actionclick": "pwa.spaceweb.content()"
},
{
"name": "Mes plugins",
"actionclick": "pwa.spaceweb.plugins()"
}
]
}, {
"name": "Referentiels",
"icon": "sliders",
"iditemmenus": "adminreferentiel",
"itemmenus": [{
"name": "Force update",
"actionclick": "pwa.referential.forceupdate()"
},
{
"name": "data",
"actionclick": "pwa.referential.setting('data')"
},
{
"name": "json",
"actionclick": "pwa.referential.setting('json')"
},
{
"name": "Objects",
"actionclick": "pwa.referential.setting('object')"
}
]
}]
}

View File

@@ -0,0 +1,23 @@
{
"sbbrandlink": "app_index_fr.html",
"sbtitle": "Need-Data",
"sbgroupmenu": [{
"groupheader": "apixtribe",
"sbssgroupmenu": [{
"name": "Les news",
"icon": "sliders",
"actionclick": "pwa.news.init()"
},
{
"name": "Reporting",
"icon": "sliders",
"actionclick": "pwa.reporting.init()",
"iditemmenus": "reportingapixtribe",
"itemmenus": [{
"name": "",
"actionclick": "pwa.reporting.init()"
}]
}
]
}]
}

View File

@@ -0,0 +1,14 @@
{
"withsearch": true,
"searchtxt": "Recherche...",
"withnotification": true,
"notificationheader": "Vos notifications",
"notificationfooter": "Voir toutes les notifications",
"href": "?action=notification.view",
"withmessage": true,
"messageheader": "Vos messages non lus",
"messagefooter": "Voir tous les messages",
"avatarimg": "static/img/avataranonymous.png",
"name": "Login",
"menuprofil": []
}

View File

@@ -0,0 +1,28 @@
"use strict";
var pwa = pwa || {};
/*
Manage message
____________________
*/
//--##
pwa.message = {};
pwa.message.update = ( urlmsg ) => {
console.log( 'get message update' );
axios.get( urlmsg, { headers: pwa.state.data.headers } )
.then( rep => {
const tpl = document.getElementById( "app_menutopmessage" );
document.getElementById( "topmenumessages" )
.innerHTML = Mustache.render( tpl.innerHTML, { messagess: rep.data } );
} )
.catch( err => {
console.log( `Err pwa.notification.update data from ${urlmsg}`, err );
} );
};
/*pwa
.state
.ready( pwa.notification.update( 'static/data/staticContentwebsite/notification.json' ) );
*/

View File

@@ -0,0 +1,271 @@
"use strict";
var pwa = pwa || {};
/*
Manage referentials for a tribeid
*/
//--##
pwa.referential = {};
pwa.referential.content = `
<div class="row gap-20 masonry pos-r">
<div class="blocA masonry-item col-md-6">
<div class="bgc-white p-20 bd">
<h6 class="c-grey-900">Affiche json</h6>
<div id="jsoneditor" class="jsoneditor">
</div>
</div>
</div>
<div class="blocB masonry-item col-md-6">
<div class="bgc-white p-20 bd">
<h6 class="c-grey-900">Changer son mot de passe</h6>
<div class="formdata">
</div>
</div>
</div>
</div>
`;
pwa.referential.set = async ( sourceref ) => {
/*
@sourceref app (recupere le referentiel de l'application)
workon (recupere le referentiel du client id sur lequel on travail state.data.headers[X-workOn])
On alimente le referentiel ds localStorage
state.app.referentials = {menu:}
*/
console.groupCollapsed( 'Load pwa.referential.set with ', sourceref )
//let reftoload;
let savexworkon;
if( sourceref == "app" ) {
//reftoload = pwa.state.data.app.referentials
// affecte le menu en fonction du profil
console.assert( pwa.state.data.app.profil && pwa.state.data.app.profil[ pwa.state.data.userlogin.ACCESSRIGHTS.app[ `${pwa.tribeid}:${pwa.PROJET}` ] ], `profil de l app ${pwa.tribeid}:${pwa.PROJET} n'existe pas pour le user dans userlogin.ACCESSRIGHTS.app , verifier qu'on a bien pour cette app un menu correspondant` );
const menuapp = pwa.state.data.app.profil[ pwa.state.data.userlogin.ACCESSRIGHTS.app[ `${pwa.tribeid}:${pwa.PROJET}` ] ].menu;
if( !pwa.state.data.app.referentials.json[ menuapp ] ) {
//on ajoute ce menu avec une version à O pour forcer sa mise à jour
pwa.state.data.app.referentials.json[ menuapp ] = { version: 0 }
}
//set xworkon on tribeid where app is stored
savexworkon = pwa.state.data.headers[ 'X-WorkOn' ];
pwa.state.data.headers[ 'X-WorkOn' ] = pwa.tribeid
}
/* else if(sourceref == "xworkon") {
// on recupere le referentiel utile pour clientcon.json du xworkon pour le projet
reftoload = pwa.state.data.xworkon.referentials
}*/
// recupere les versions du clientconf.json
const clientconfref = await axios.get( `${pwa.urlbackauth}/referentials/clientconf/referentials`, { headers: pwa.state.data.headers } );
console.debug( 'clientconfref', clientconfref );
for( const o of [ 'object', 'json', 'data' ] ) {
console.debug( o )
//update by adding or upgraded version if in dev or in prod and pwa.state.data[sourceref].referentials[type=object|json|data][nomref].version is upper than the local one
// Take care app is load first with previous referential then need to refresh app to use the new version.
if( !clientconfref.data.referentials[ o ] ) {
clientconfref.data.referentials[ o ] = {};
}
//Warning do not use foreach in async cause foreach is not sync
for( const r of Object.keys( clientconfref.data.referentials[ o ] ) ) {
console.debug( r )
if( !pwa.state.data.app.referentials[ o ][ r ] ) {
// New referential added need to reload app to refresh app
pwa.state.data.app.referentials[ o ][ r ] = { version: -1 };
}
if( pwa.MODE_ENV == "dev" || !( pwa.state.data.app.referentials[ o ][ r ].version == clientconfref[ o ][ r ].version ) ) {
// alors nouvelle version à mettre à jour en dev on le fait systematiquement
console.log( `${pwa.urlbackauth}/referentials/content/${o}/${r}`, pwa.state.data.headers );
const dataref = await axios.get( `${pwa.urlbackauth}/referentials/content/${o}/${r}`, { headers: pwa.state.data.headers } )
if( dataref.status == 200 ) {
console.log( `${o} - ${r}`, dataref.data )
pwa.state.data[ sourceref ].referentials[ o ][ r ] = dataref.data;
pwa.state.save()
} else {
console.log( `ERREUR de recuperation de referentiel ${o} ${r}` )
}
}
}
// we remove from local if nomref disapear of app clientconfref.data.referential
Object.keys( pwa.state.data[ sourceref ].referentials[ o ] )
.forEach( r => {
if( !clientconfref.data.referentials[ o ] ) {
delete pwa.state.data[ sourceref ].referentials[ o ];
pwa.state.save();
}
} )
};
if( sourceref == "app" ) {
// on remet le xworkon en cours
pwa.state.data.headers[ 'X-WorkOn' ] = savexworkon;
}
console.groupEnd();
};
pwa.referential.forceupdate = () => {
axios.get( `${pwa.urlbackauth}/referentials/updatefull`, {
headers: pwa.state.data.headers
} )
.then( data => {
alert( data.status )
} )
}
// GUI to manage referential
pwa.referential.setting = async ( objecttype ) => {
// Convert location.search to get objecttype
const urlpar = new URLSearchParams( objecttype );
objecttype = ( urlpar.get( 'objecttype' ) ) ? urlpar.get( 'objecttype' ) : objecttype;
const tpleditor = `
<div class="input-group mb-3" data-idref="{{id}}">
<button class="btn btn-outline-primary actionobject save" >
{{{btnsave}}}
</button>
<button class="btn btn-outline-primary actionobject delete" >
{{{btndelete}}}
</button>
<button class=" btn btn-outline-primary actionobject copy" >
{{{btncopy}}}
</button>
<input type="text" class="form-control nameas" placeholder="{{{copyplaceholder}}}" >
</div>
</div>
<div class="jsoneditor mb-3"></div>
`;
console.groupCollapsed( `load referentials setting for ${objecttype}` );
//reinit submenuitems
pwa.state.data.app.referentials.json.referentialsetting.submenuitems = [];
//Requested directly the back warranty to get always the last updated referential
const data = await axios.get( `${pwa.urlbackauth}/referentials/contentlist/${objecttype}`, {
headers: pwa.state.data.headers
} );
console.log( "Liste des referentiels ", data.data )
let reqref = []
let ref = []
//init a temporary (opposite od state that is save) data to work on referential (each time referentials/object is load this variable is refresh)
pwa.tmp = {};
data.data.forEach( o => {
reqref.push( axios.get( `${pwa.urlbackauth}/referentials/contentfull/${objecttype}/${o}`, {
headers: pwa.state.data.headers
} ) )
ref.push( o );
} );
axios.all( reqref )
.then( axios.spread( ( ...rep ) => {
console.log( rep )
rep.forEach( ( d, i ) => {
pwa.tmp[ ref[ i ] ] = d.data
const submenuit = {
active: "",
groupinfo: ref[ i ],
id: `referential${ref[i]}`,
optionjsoneditor: {},
onclick: `pwa.referential.save(event,'referential${ref[i]}')`,
btnsave: pwa.state.data.app.referentials.json.referentialsetting.btnsave,
btndelete: pwa.state.data.app.referentials.json.referentialsetting.btndelete,
btncopy: pwa.state.data.app.referentials.json.referentialsetting.btncopy,
copyplaceholder: pwa.state.data.app.referentials.json.referentialsetting.copyplaceholder,
objecttype: objecttype
};
pwa.state.data.app.referentials.json.referentialsetting.submenuitems.push( submenuit )
} );
document.getElementById( 'maincontent' )
.innerHTML = Mustache.render( document.getElementById( 'referential' )
.innerHTML, pwa.state.data.app.referentials.json.referentialsetting );
pwa.state.data.app.referentials.json.referentialsetting.submenuitems.forEach( tab => {
document.getElementById( tab.id )
.innerHTML = Mustache.render( tpleditor, tab );
//console.log( tab.id, tab )
// Convert each div with formfieldtype to a form field set with value if exist and listen button to run callback
pwa.referential.init( tab );
} );
} ) )
.catch( err => {
console.log( "eeeee", err );
const submenuit = {
active: "",
groupinfo: objecttype,
id: `referential${objecttype}`,
optionjsoneditor: {},
onclick: `pwa.referential.save(event,'referential${objecttype}')`,
data: { erreur: err }
};
pwa.state.data.app.referentials.json.referentialsetting.submenuitems.push( submenuit )
} );
console.groupEnd();
}
pwa.referential.init = ( tab ) => {
const doctab = document.querySelector( `#${tab.id}` );
const editor = new JSONEditor( doctab.querySelector( `.jsoneditor` ), tab.optionjsoneditor );
console.table( tab )
console.log( tab.objecttype, tab.groupinfo )
editor.set( pwa.tmp[ tab.groupinfo ] );
editor.expandAll();
// ajoute un listener sur btn pour faire axios post with editor.get()
Array.from( doctab.querySelectorAll( '.save, .delete, .copy' ) )
.forEach( act => {
act.addEventListener( 'click', e => {
e.preventDefault();
console.log( 'cliiiiiiiiiiiiiiiiiiiick', tab.id )
if( e.target.classList.contains( 'save' ) ) {
/*
axios.put( `${pwa.urlbackauth}/referentials/content/${tab.objecttype}/${tab.groupinfo}`, editor.get(), {
headers: pwa.state.data.headers
} )
.then( data => {
console.log( "affiche message done" );
} )
.catch( err => {
console.log( "affiche message err ", err )
} );
*/
console.log( 'editor', editor.get() );
}
if( e.target.classList.contains( 'delete' ) ) {
//axios.get( @tTODO la mise à jour du nouveau referentiel avec la version)
}
if( e.target.classList.contains( 'copy' ) ) {
//@TODO create a new referential file localy from an existing one
}
/*console.log( e.target.closest( '[data-idref]' )
.getAttribute( 'data-idref' ) )
console.log( editor.get() );
envoyer à axios et modifier pwa.state. en cours
*/
} );
} );
}
///////////////////////////////////////////////////////
pwa.referential.initold = async ( object ) => {
$( '#mainContent' )
.html( pwa.referential.content );
// charge ul#menuleft
// create the editor
const container = document.getElementById( "jsoneditor" )
const options = {}
const editor = new JSONEditor( container, options )
axios.get( `${pwa.urlbackauth}/referentials/content/object/${object}`, {
headers: pwa.state.data.headers
} )
.then(
( ref ) => { editor.set( ref.data ) },
( error ) => {
window.location.pathname == "/"
} )
// set json
/*const initialJson = {
"Array": [1, 2, 3],
"Boolean": true,
"Null": null,
"Number": 123,
"Object": { "a": "b", "c": "d" },
"String": "Hello World"
}
editor.set(initialJson)
*/
// get json
const updatedJson = editor.get()
console.log( 'updatedJson', updatedJson )
}

View File

@@ -0,0 +1,48 @@
<h1 class="h3 mb-3">{{titre}}</h1>
<div class="row">
<div class="col-12">
<div class='card'>
<div class='card-body'>
<p>La gestion d'un referentiel est multilangue, la sauvegarde remplace l'ancien et génére chaque referentiel par langue.</p>
</div>
</div>
</div>
</div>
<div class="row">
<div class='col-sm-12 col-xl-4'>
<div class='card h-100'>
<div class='card-body'>{{{datadef}}}</div>
</div>
</div>
<div class='col-sm-12 col-xl-4'>
<div class='card h-100'>
<div class='card-body'>{{{jsondef}}}</div>
</div>
</div>
<div class='col-sm-12 col-xl-4'>
<div class='card h-100'>
<div class='card-body'>{{{objectdef}}}</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-3 col-xl-2">
<div class="card">
<div class="card-header bg-grey">
<h5 class="card-title mb-0">{{{submenutitre}}}</h5>
</div>
<div class="list-group list-group-flush" role="tablist">
{{#submenuitems}}
<a class="list-group-item list-group-item-action {{active}}" data-bs-toggle="list" href="#{{id}}" role="tab">{{{groupinfo}}}
</a>
{{/submenuitems}}
</div>
</div>
</div>
<div class="col-md-9 col-xl-10">
<div class="tab-content">
<div class="tab-pane fade show active" role="tabpanel">
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,12 @@
"use strict";
var pwa = pwa || {};
/*
Reporting js managing sceen
*/
//--##
pwa.reporting = pwa.reporting || {};
pwa.reporting.init = () => {
console.log('charge reporting');
}

View File

@@ -0,0 +1,68 @@
// app management for search request
/*
@todo create a search/index content for an apixtribe instance
//store request to analyse kind of looking for
*/
var pwa = pwa || {};
pwa.search = {};
pwa.search.tpl = `
<div class="container-fluid p-0">
<h1 class="h3 mb-3">Recherche pour: {{searchtxt}}</h1>
<div class="row">
{{#results}}
<div class="col-12">
<div class="card">
<div class="card-header">
<p><a href="{{url}}" target="_blank">{{url}}</a> - {{format}}</p>
<h5 class="card-title mb-0">{{{title}}}</h5>
</div>
<div class="card-body">
{{{desc}}}
</div>
<div class="card-footer">
{{#relatedtag}}
<button type="button" class="btn btn-dark" >{{.}}</button>
{{/relatedtag}}
</div>
</div>
</div>
{{/results}}
</div>
</div>
`;
pwa.search.dataexample = {
searchtxt: "search string to looking for",
results: [ {
url: "https://apixtribe.org",
format: "pdf",
title: "Search finding title of the page",
desc: "sentence contexte of the searchtxt",
relatedtag: [ "keyword1", "keyword2" ]
} ]
}
pwa.search.req = ( info ) => {
if( info[ 1 ] == "?" ) {
const urlparse = new URLSearchParams( info );
//Then set param with urlpar.get('variable name')
info = {
idsearch: urlparse.get( 'idsearchtxt' )
}
}
const searchtxt = document.getElementById( info )
.value;
console.log( info, searchtxt );
const req = { searchtxt };
req.results = [ {
url: "",
format: "",
title: "Nous n'avons rien à vous proposer sur ce sujet",
desc: `<p>To find more click on <a href='https://google.com/search?q=${searchtxt.replace(/ /g,'+')}' target="_blanck"> google search </a></p> `,
relatedtag: [ 'tag1', "tag2", "tag3" ]
} ];
document.getElementsByTagName( 'main' )[ 0 ]
.innerHTML = Mustache.render( pwa.search.tpl, req );
}

View File

@@ -0,0 +1,94 @@
"use strict";
var pwa = pwa || {};
// Affiche pour tous les tuso et manage des tutos en fonction des droits
// ces tuto sont stocké dans items avec les tag TUTO MAILDIGIT
// Un searchindex/TUTOMAILDIGIT.json list les id
//--##
pwa.tuto = {};
$(document)
.ready(function() {
//simule un ensemble de click pour faciliter le dev sans avoir à recliquer
// à commenter avant de passer en production
//pwa.tuto.init();
})
pwa.tuto.masonryview = () => {
const blocmasonry = {
classnamebloc: "searchtuto",
classmasonryitem: "col-md-12",
titlemasonry: "Liste des tutos",
masonrycontent: "",
actionmasonry: [{
classbtn: "btn-primary",
actionclick: "pwa.tuto.createTuto();",
title: "Ajouter un tuto",
icone: "fas fa-plus"
}]
}
//on recupere la data
const data = {}
// recupere liste des tag et comptage pour afficher les tag présent
//
// axios.get( items/tuto, company, card (objet)/tuto retourne un json avec liste de cards )
//
/*blocmasonry.masonrycontent = Mustache.render($('#sectionFilterlist')
.html(), data)*/
return blocmasonry
}
pwa.tuto.gestion = () => {
alert('gere')
}
pwa.tuto.menutop = () => {
//liste des options possibles pour le contexte
$('#tplmenutop > .nav-left li')
.removeClass('d-none')
.addClass('d-none');
const listmenutop = ['burger']; //['burger', 'filemanager', 'statistique', 'manageobjet'];
listmenutop.forEach(m => {
$('#tplmenutop > .nav-left li.' + m)
.removeClass('d-none');
});
//Ajout eventuel d'icone d'action on enleve celels d'avant
$('li.objectspecifique')
.remove();
const addmenutop = {
listmenu: [{
"liclass": "manageobjet",
"title": "Gestion des objets",
"actionclick": "pwa.tuto.gestion();",
"icone": "fas fa-cubes"
}]
}
const tplmenutop = `
{{#listmenu}}
<li class="{{liclass}} objectspecifique">
<a class='menutop' title="{{title}}" onclick="{{actionclick}}">
<i class="{{icone}}"></i>
</a>
</li>
{{/listmenu}}`;
$('#tplmenutop ul.nav-left')
.append(Mustache.render(tplmenutop, addmenutop))
}
pwa.tuto.init = async (object) => {
console.log('Lance tuto')
pwa.tuto.menutop();
// Reinit et ajoute des bloc
$('#mainContent > .row')
.html('<div class="masonry-sizer col-md-12"></div>');
$('#mainContent > .row')
.append(Mustache.render($('#app_masonryitemaction')
.html(), pwa.tuto.masonryview()));
new Masonry(".masonry", {
itemSelector: ".masonry-item",
columnWidth: ".masonry-sizer",
percentPosition: true
});
};

View File

@@ -0,0 +1,74 @@
"use strict";
var pwa = pwa || {};
//--##
pwa.userManager = pwa.userManager || {};
pwa.userManager.init = function() {
$("#espaceMasonry")
.html("");
pwa.userProfile.ficheUser("0", "ADMIN");
};
pwa.userManager.userList = async function() {
//check ADMIN
if(pwa.MODE_ENV) {
return [
{ uuid: "pcolzy", desc: "pcolzy" },
{ uuid: "user2", desc: "User2" }
];
} else {
const datauser = await axios.get(pwa.urlbackauth + "/login", {
headers: pwa.state.data.headers
});
const lst = datauser.data.items.map(u => {
return { uuid: u.uuid, desc: u.name };
});
return lst;
}
};
pwa.userManager.ficheUser = function(iduser) {
// Génere un form de user pre-rempli avec iduser
let userForm = {
includein: "#espaceMasonry",
template: "#mainContentMasonry",
idmasonry: "UserForm",
destinationclass: "formUser",
header: "Information du compte",
formclass: "formUserProfil",
nombreColonne: 6,
commentaire: "",
footer: ""
};
let datauser = pwa.state.data.user;
if(iduser) {
//On recupere les informations iduser
// faire un get (iduser) datauser =
userForm.button = [{
action: "update",
label: "Sauvegarder",
msgok: "Votre sauvegarde a bien été effectuée en local",
msgko: "Votre sauvegarde n'a pas pu être réalisée ",
actionclick: "pwa.userManager.update()",
idObject: pwa.state.data.user.uuid,
objectSelected: "user"
}];
} else {
userForm.button = [{
action: "create",
label: "Créer",
msgok: "Utilisateur créer en local",
msgko: "La création d'un utilisateur n'est pas possible ",
actionclick: "pwa.userManager.create()",
idObject: "0",
objectSelected: "user"
}];
}
userForm.main = pwa.forms.genereForm(pwa.state.app.ref.users, datauser);
console.log("button envoye", userForm.button);
userForm.buttonup = Mustache.render($("#actionButton")
.html(), {
button: userForm.button
});
pwa.masonry.append(userForm, pwa.forms.actionForm);
};

View File

@@ -0,0 +1,88 @@
<h1 class="h3 mb-3">Chart.js</h1>
<div class="row">
<div class="col-12 col-lg-6">
<div class="card flex-fill w-100">
<div class="card-header">
<h5 class="card-title">Line Chart</h5>
<h6 class="card-subtitle text-muted">A line chart is a way of plotting data points on a line.</h6>
</div>
<div class="card-body">
<div class="chart">
<canvas id="chartjs-line"></canvas>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<div class="card">
<div class="card-header">
<h5 class="card-title">Bar Chart</h5>
<h6 class="card-subtitle text-muted">A bar chart provides a way of showing data values represented as vertical bars.</h6>
</div>
<div class="card-body">
<div class="chart">
<canvas id="chartjs-bar"></canvas>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<div class="card">
<div class="card-header">
<h5 class="card-title">Doughnut Chart</h5>
<h6 class="card-subtitle text-muted">Doughnut charts are excellent at showing the relational proportions between data.</h6>
</div>
<div class="card-body">
<div class="chart chart-sm">
<canvas id="chartjs-doughnut"></canvas>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<div class="card">
<div class="card-header">
<h5 class="card-title">Pie Chart</h5>
<h6 class="card-subtitle text-muted">Pie charts are excellent at showing the relational proportions between data.</h6>
</div>
<div class="card-body">
<div class="chart chart-sm">
<canvas id="chartjs-pie"></canvas>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<div class="card">
<div class="card-header">
<h5 class="card-title">Radar Chart</h5>
<h6 class="card-subtitle text-muted">A radar chart is a way of showing multiple data points and the variation between them.</h6>
</div>
<div class="card-body">
<div class="chart">
<canvas id="chartjs-radar"></canvas>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<div class="card">
<div class="card-header">
<h5 class="card-title">Polar Area Chart</h5>
<h6 class="card-subtitle text-muted">Polar area charts are similar to pie charts, but each segment has the same angle.</h6>
</div>
<div class="card-body">
<div class="chart">
<canvas id="chartjs-polar-area"></canvas>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,170 @@
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">{{{publicinfo}}}</h5>
</div>
<div class="card-body">
<form id="userpublicinfo" somethingchange="false">
<div class="row">
<div class="col-md-8">
<div class="mb-3" {{{meta.users.PSEUDO.tag}}}
newvalue="">
{{{meta.users.PSEUDO.html}}}
</div>
<div class="mb-3" {{{meta.users.BIOGRAPHY.tag}}}
newvalue="">
{{{meta.users.BIOGRAPHY.html}}}
</div>
<div class="mb-3" {{{meta.users.PUBLICKEY.tag}}}
newvalue="">
{{{meta.users.PUBLICKEY.html}}}
</div>
</div>
<div class="col-md-4">
<div class="text-center" {{{meta.users.IMGAVATAR.tag}}}
newvalue="">
{{{meta.users.IMGAVATAR.html}}}
</div>
</div>
</div>
<button type="submit" class="btn btn-primary" onclick="{{{onclickpub}}}">
{{{btnsavepub}}}
</button>
<div class="msgsubmit"></div>
</form>
</div>
</div>
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">{{{privateinfo}}}</h5>
</div>
<div class="card-body">
<form id="userprivateinfo" somethingchange="false" >
<div class="row">
{{{infoprivate}}}
</div>
<div class="row">
<div class="mb-3 col-md-6" {{{meta.users.NICKNAME.tag}}}>
{{{meta.users.NICKNAME.html}}}
</div>
<div class="mb-3 col-md-6" {{{meta.users.NAME.tag}}}>
{{{meta.users.NAME.html}}}
</div>
</div>
<div class="mb-3" {{{meta.users.EMAIL.tag}}}>
{{{meta.users.EMAIL.html}}}
</div>
<div class="mb-3" {{{meta.users.ADDRESS1.tag}}}>
{{{meta.users.ADDRESS1.html}}}
</div>
<div class="mb-3" {{{meta.users.ADDRESS2.tag}}}>
{{{meta.users.ADDRESS2.html}}}
</div>
<div class="row">
<div class="mb-3 col-md-6" {{{meta.users.CITY.tag}}}>
{{{meta.users.CITY.html}}}
</div>
<div class="mb-3 col-md-4" {{{meta.users.ZIP.tag}}}>
{{{meta.users.ZIP.html}}}
</div>
<div class="mb-3 col-md-2" {{{meta.users.COUNTRY.tag}}}>
{{{meta.users.COUNTRY.html}}}
</div>
</div>
<button type="submit" class="btn btn-primary" onclick="{{{onclickprivate}}}">
{{{btnsaveprivate}}}
</button>
</form>
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">{{{publicinfo}}}</h5>
</div>
<div class="card-body">
<form id="userpublicinfo" somethingchange="false">
<div class="row">
<div class="col-md-8">
<div class="mb-3" {{{meta.users.PSEUDO.tag}}} tpl="{{{users.PSEUDO.type}}}" object="users" fieldname="PSEUDO" placeholder="{{{users.PSEUDO.placeholder}}}" desc="{{{users.PSEUDO.desc}}}"
checkdata="{{{users.PSEUDO.check}}}"
newvalue="">
{{{meta.users.PSEUDO.html}}}
</div>
<div class="mb-3" formfieldtype="{{users.BIOGRAPHY.type}}" object="users" fieldname="BIOGRAPHY" placeholder="{{users.BIOGRAPHY.placeholder}}" rows="{{{users.BIOGRAPHY.rows}}}" desc="{{{users.BIOGRAPHY.desc}}}" checkdata="{{{users.BIOGRAPHY.check}}}" info="{{{users.BIOGRAPHY.info}}}"
newvalue="">
</div>
<div class="mb-3" formfieldtype="{{users.PUBLICKEY.type}}" object="users" fieldname="PUBLICKEY" placeholder="{{}}" rows="2" desc="{{{users.PUBLICKEY.desc}}}" info="{{{users.PUBLICKEY.info}}}"
newvalue="">
</div>
</div>
<div class="col-md-4">
<div class="text-center" formfieldtype="{{users.IMGAVATAR.type}}" object="users" fieldname="IMGAVATAR" altimg="{{users.PSEUDO.desc}}" classimg="rounded-circle img-responsive mt-2" width="{{users.IMGAVATAR.width}}" height="{{users.IMGAVATAR.height}}" classdivupload="mt-2" classbtn="btn btn-primary" desc="{{{users.IMGAVATAR.desc}}}"
info="{{{users.IMGAVATAR.info}}}"
newvalue="">
</div>
</div>
</div>
<button type="submit" class="btn btn-primary" onclick="{{{onclickpub}}}">
{{{btnsavepub}}}
</button>
<div class="msgsubmit"></div>
</form>
</div>
</div>
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">{{{privateinfo}}}</h5>
</div>
<div class="card-body">
<form id="userprivateinfo" somethingchange="false" >
<div class="row">
{{{infoprivate}}}
</div>
<div class="row">
<div class="mb-3 col-md-6" formfieldtype="{{{users.NICKNAME.type}}}" object="users" fieldname="NICKNAME" placeholder="{{{users.NICKNAME.placeholder}}}" desc="{{{users.NICKNAME.desc}}}"
checkdata="{{{users.NICKNAME.check}}}"
newvalue="">
<div class="mb-3 col-md-6" formfieldtype="{{{users.NAME.type}}}" object="users" fieldname="NAME" placeholder="{{{users.NAME.placeholder}}}" desc="{{{users.NAME.desc}}}"
checkdata="{{{users.NAME.check}}}"
newvalue="">
</div>
</div>
<div class="mb-3" formfieldtype="{{{users.EMAIL.type}}}" object="users" fieldname="EMAIL" placeholder="{{{users.EMAIL.placeholder}}}" desc="{{{users.EMAIL.desc}}}"
checkdata="{{{users.EMAIL.check}}}"
newvalue="">
</div>
<div class="mb-3" formfieldtype="{{{users.ADDRESS1.type}}}" object="users" fieldname="ADDRESS1" placeholder="{{{users.ADDRESS1.placeholder}}}" desc="{{{users.ADDRESS1.desc}}}"
checkdata="{{{users.ADDRESS1.check}}}"
newvalue="">
</div>
<div class="mb-3" formfieldtype="{{{users.ADDRESS2.type}}}" object="users" fieldname="ADDRESS2" placeholder="{{{users.ADDRESS2.placeholder}}}" desc="{{{users.ADDRESS2.desc}}}"
checkdata="{{{users.ADDRESS2.check}}}"
newvalue="">
</div>
<div class="row">
<div class="mb-3 col-md-6" formfieldtype="{{{users.CITY.type}}}" object="users" fieldname="CITY" placeholder="{{{users.CITY.placeholder}}}" desc="{{{users.CITY.desc}}}"
checkdata="{{{users.CITY.check}}}"
newvalue="">
</div>
<div class="mb-3 col-md-4" formfieldtype="{{{users.ZIP.type}}}" object="users" fieldname="ZIP" placeholder="{{{users.ZIP.placeholder}}}" desc="{{{users.ZIP.desc}}}"
checkdata="{{{users.ZIP.check}}}"
newvalue="">
</div>
<div class="mb-3 col-md-2" formfieldtype="{{{users.COUNTRY.type}}}" object="users" fieldname="COUNTRY" placeholder="{{{users.COUNTRY.placeholder}}}" desc="{{{users.COUNTRY.desc}}}"
checkdata="{{{users.COUNTRY.check}}}"
newvalue="">
</div>
</div>
<button type="submit" class="btn btn-primary" onclick="{{{onclickprivate}}}">
{{{btnsaveprivate}}}
</button>
</form>
</div>
</div>
</div>

View File

@@ -0,0 +1,23 @@
<div class="card">
<div class="card-body">
<h5 class="card-title">Password</h5>
<form>
<div class="mb-3">
<label class="form-label" for="inputPasswordCurrent">Current password</label>
<input type="password" class="form-control" id="inputPasswordCurrent">
<small><a href="#">Forgot your password?</a></small>
</div>
<div class="mb-3">
<label class="form-label" for="inputPasswordNew">New password</label>
<input type="password" class="form-control" id="inputPasswordNew">
</div>
<div class="mb-3">
<label class="form-label" for="inputPasswordNew2">Verify password</label>
<input type="password" class="form-control" id="inputPasswordNew2">
</div>
<button type="submit" class="btn btn-primary">Save changes</button>
</form>
</div>
</div>

View File

@@ -0,0 +1,19 @@
{
"title": "Profile",
"desc": "<p>Vos informations</p>",
"submenutitle": "Blabla",
"submenuitems": [{
"submenudesc": "group1",
"active": "active",
"id": "gr1",
"content": "blabla group1"
}, {
"submenudesc": "group2",
"id": "gr2",
"content": "blabla group2"
}, {
"submenudesc": "group3",
"id": "gr3",
"content": "blabla group 3"
}]
}

View File

@@ -0,0 +1,20 @@
$( 'a.contenu' )
.on( 'click', function () {
// $( this )
// .preventDefault();
// hide all
$( '.face.back >div' )
.addClass( 'd-none' );
const dest = $( this )
.attr( 'data-dest' )
$( '.face.back >.' + dest )
.removeClass( 'd-none' );
$( '.flip >.card' )
.toggleClass( 'flipped' );
} )
$( '.face.back >> a.retour' )
.on( 'click', function () {
$( '.flip >.card' )
.toggleClass( 'flipped' );
} )

View File

@@ -0,0 +1,37 @@
<div class="container">
<div class="row">
<div class="col-sm-12">
<div class="flip">
<div class="card">
<div class="face front">
<div class="inner">
<h3>Blabla</h3>
<p><a class="contenu" data-dest="contenuA">ContenuA</a></p>
<p><a class="contenu" data-dest="contenuB">ContenuB</a></p>
<p><a class="contenu" data-dest="contenuC">ContenuC</a></p>
</div>
</div>
<div class="face back">
<div class="inner text-center contenuA">
<a class="retour"> back </a>
<h3>A Improved efficiency through automation</h3>
</div>
<div class="inner text-center contenuB">
<a class="retour"> back </a>
<h3>B Improved efficiency through automation</h3>
</div>
<div class="inner text-center contenuC">
<a class="retour"> back </a>
<h3>C Improved efficiency through automation</h3>
</div>
<button type="button" class="btn btn-default">Know More</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,53 @@
.flipbox {
.flip {
-webkit-perspective: 800;
perspective: 800;
position: relative;
text-align: center;
}
.flip .card.flipped {
-webkit-transform: rotatey(-180deg);
transform: rotatey(-180deg);
}
.flip .card {
width: 270px;
height: 178px;
-webkit-transform-style: preserve-3d;
-webkit-transition: 0.5s;
transform-style: preserve-3d;
transition: 0.5s;
background-color: #fff;
}
.flip .card .face {
-webkit-backface-visibility: hidden ;
backface-visibility: hidden ;
z-index: 2;
}
.flip .card .front {
position: absolute;
width: 270px;
z-index: 1;
}
.flip .card .front img{
width: 100%;
height: 100%;
}
.flip .card .img {
position: relaitve;
width: 270px;
height: 178px;
z-index: 1;
border: 2px solid #000;
}
.flip .card .back {
padding-top: 10%;
-webkit-transform: rotatey(-180deg);
transform: rotatey(-180deg);
position: absolute;
}
.inner{
margin:0px !important;
width: 270px;
}
}

View File

@@ -0,0 +1,9 @@
<!-- main class="d-flex w-100 h-100" -->
<div class="container d-flex flex-column">
<div class="row vh-100">
<div class="col-sm-10 col-md-8 col-lg-6 mx-auto d-table h-100">
<importhtml></importhtml>
</div>
</div>
</div>
<!-- /main -->

View File

@@ -0,0 +1,33 @@
{
"iconnotif": "bell",
"number": 0,
"notifheader": "Vos notifications",
"notiffooter": "Voir toutes les notifications",
"actionnotifmanager": "",
"href": "?action=notification.view",
"notifs": [{
"urldetail": "#",
"classicon": "text-danger",
"icon": "alert",
"title": "Intusion de 192.168.1.3",
"desc": "Check your log",
"elapse": "il y a 13mn"
},
{
"urldetail": "#",
"classicon": "text-success",
"icon": "star",
"title": "Successfull backup",
"desc": "",
"elapse": "il y a 2 jours"
},
{
"urldetail": "#",
"classicon": "text-warning",
"icon": "bell",
"title": "Commande en attente",
"desc": "Vous avez des commandes en attente de traitement",
"elapse": "il y a 6 heures"
}
]
}

View File

@@ -0,0 +1,28 @@
"use strict";
var pwa = pwa || {};
/*
Manage notification
Get notification after tomenu was load
from /components/notification
____________________
*/
//--##
pwa.notification = {};
pwa.notification.update = () => {
console.log( 'get notification update for a user' );
axios.get( `https://${pwa.state.data.ctx.urlbackoffice}/notifications/user`, { headers: pwa.state.data.headers } )
.then( rep => {
console.log( "list des notifs", rep.data.payload.data )
rep.data.payload.data.number = rep.data.payload.data.notifs.length;
document.getElementById( "topbarmenuright" )
.innerHTML = Mustache.render( pwa.state.data.tpl.notiflist, rep.data.payload.data ) + document.getElementById( "topbarmenuright" )
.innerHTML;
} )
.catch( err => {
console.log( `Err pwa.notification.update data for user into header ${pwa.state.data.headers}`, err );
} );
};

View File

@@ -0,0 +1,32 @@
<li class="nav-item dropdown">
<a class="nav-icon dropdown-toggle" href="#" id="alertsDropdown" data-bs-toggle="dropdown">
<div class="position-relative">
<i class="align-middle" data-feather="{{iconnotif}}"></i>
<span class="indicator">{{number}}</span>
</div>
</a>
<div class="dropdown-menu dropdown-menu-lg dropdown-menu-end py-0" aria-labelledby="alertsDropdown">
<div class="dropdown-menu-header">
{{{notificationheader}}}
</div>
<div class="list-group">
{{#notifs}}
<a href="{{urldetail}}" class="list-group-item">
<div class="row g-0 align-items-center">
<div class="col-2">
<i class="{{{classicon}}}" data-feather="{{{icon}}}"></i>
</div>
<div class="col-10">
<div class="text-dark">{{{title}}}</div>
<div class="text-muted small mt-1">{{{desc}}}</div>
<div class="text-muted small mt-1">{{{elapse}}}</div>
</div>
</div>
</a>
{{/notifs}}
</div>
<div class="dropdown-menu-footer">
<a href="#" class="text-muted">{{{notificationfooter}}}</a>
</div>
</div>
</li>

View File

@@ -0,0 +1,6 @@
{
"icon": "settings",
"desc": "Log out",
"href": "?action=auth.logout",
"menubreaker": false
}

View File

@@ -0,0 +1,6 @@
{
"icon": "user",
"desc": "Mes Activités",
"href": "?action=userprofile.settings",
"menubreaker": false
}

View File

@@ -0,0 +1,6 @@
{
"icon": "pie-chart",
"desc": "Mon profile",
"href": "?action=userprofile.settings",
"menubreaker": false
}

View File

@@ -0,0 +1,88 @@
<h1 class="h3 mb-3">Chart.js</h1>
<div class="row">
<div class="col-12 col-lg-6">
<div class="card flex-fill w-100">
<div class="card-header">
<h5 class="card-title">Line Chart</h5>
<h6 class="card-subtitle text-muted">A line chart is a way of plotting data points on a line.</h6>
</div>
<div class="card-body">
<div class="chart">
<canvas id="chartjs-line"></canvas>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<div class="card">
<div class="card-header">
<h5 class="card-title">Bar Chart</h5>
<h6 class="card-subtitle text-muted">A bar chart provides a way of showing data values represented as vertical bars.</h6>
</div>
<div class="card-body">
<div class="chart">
<canvas id="chartjs-bar"></canvas>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<div class="card">
<div class="card-header">
<h5 class="card-title">Doughnut Chart</h5>
<h6 class="card-subtitle text-muted">Doughnut charts are excellent at showing the relational proportions between data.</h6>
</div>
<div class="card-body">
<div class="chart chart-sm">
<canvas id="chartjs-doughnut"></canvas>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<div class="card">
<div class="card-header">
<h5 class="card-title">Pie Chart</h5>
<h6 class="card-subtitle text-muted">Pie charts are excellent at showing the relational proportions between data.</h6>
</div>
<div class="card-body">
<div class="chart chart-sm">
<canvas id="chartjs-pie"></canvas>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<div class="card">
<div class="card-header">
<h5 class="card-title">Radar Chart</h5>
<h6 class="card-subtitle text-muted">A radar chart is a way of showing multiple data points and the variation between them.</h6>
</div>
<div class="card-body">
<div class="chart">
<canvas id="chartjs-radar"></canvas>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<div class="card">
<div class="card-header">
<h5 class="card-title">Polar Area Chart</h5>
<h6 class="card-subtitle text-muted">Polar area charts are similar to pie charts, but each segment has the same angle.</h6>
</div>
<div class="card-body">
<div class="chart">
<canvas id="chartjs-polar-area"></canvas>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,66 @@
var pwa = pwa || {};
/*
Manage user data for current login user
From user data = pwa.state.data.userlogin
*/
//--##
pwa.main = pwa.main || {};
pwa.main.tpldata = pwa.main.tpldata || {};
pwa.main.tpl = pwa.main.tpl || {};
pwa.main.ref = pwa.main.ref || {};
//Add template here to make it available after authentification
// in pwa.state.data.tpl[name]
// pwa.state.data.tpldata[name] in the user's language by adding at the end of value _{pwa.state.data.ctx.lang}.json
pwa.main.tpl.usersettingaccount = `static/components/userprofile/usersettingaccount.mustache`;
pwa.main.tpldata.topbaruserprofile = `static/components/userprofile/topbaruserprofile`;
pwa.main.tpldata.topbaruseractivity = `static/components/userprofile/topbaruseractivity`;
pwa.main.tpldata.topbaruserLogout = `static/components/userprofile/topbaruserLogout`;
pwa.main.referential.users = 'url ... obeject/users.json';
//header check if user is allow to get this
pwa.userprofile = pwa.userprofile || {};
pwa.userprofile.settings = ( e ) => {
console.groupCollapsed( 'load user settings' );
console.log( Object.keys( pwa ) )
//data form init from pwa.state or axios.get( data from user )
const data = pwa.state.data.userlogin;
// add meta data object to create forms
const meta = { "users": {} };
pwa.state.data.app.referentials.object.users.forEach( f => {
// genere tag
const test = Object.keys( f )
f.tag = " object='users' " + test.reduce( ( ac, k ) => {
return ac + k + '="' + f[ k ] + '" ';
} );
// genere html field care do html after tag if not
f.html = pwa.form.tpl[ f.tpl ].html( f )
meta.users[ f.idfield ] = f
//console.log( f.idfield )
//console.log( f )
} );
pwa.state.data.app.referentials.json.usersetting.submenuitems[ 0 ].meta = meta;
console.log( "meta", pwa.state.data.app.referentials.json.usersetting )
// tpl in #usersetting data in referentials json usersetting
document.getElementById( 'maincontent' )
.innerHTML = Mustache.render( document.getElementById( 'setting' )
.innerHTML, pwa.state.data.app.referentials.json.usersetting );
// load each content of tab then init form with data merged with tab info
pwa.state.data.app.referentials.json.usersetting.submenuitems.forEach( tab => {
document.getElementById( tab.id )
.innerHTML = Mustache.render( document.getElementById( `${tab.id}tpl` )
.innerHTML, tab );
console.log( tab.id, tab )
// Convert each div with formfieldtype to a form field set with value if exist and listen button to run callback
pwa.form.init( tab.id, { ...tab, ...data }, pwa.userprofile.save )
} )
console.groupEnd();
}
pwa.userprofile.save = ( data ) => {
console.log( "data to save", data )
}
pwa.userprofile.activities = () => {
console.group( 'load user activity' );
}

View File

@@ -0,0 +1,170 @@
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">{{{publicinfo}}}</h5>
</div>
<div class="card-body">
<form id="userpublicinfo" somethingchange="false">
<div class="row">
<div class="col-md-8">
<div class="mb-3" {{{meta.users.PSEUDO.tag}}}
newvalue="">
{{{meta.users.PSEUDO.html}}}
</div>
<div class="mb-3" {{{meta.users.BIOGRAPHY.tag}}}
newvalue="">
{{{meta.users.BIOGRAPHY.html}}}
</div>
<div class="mb-3" {{{meta.users.PUBLICKEY.tag}}}
newvalue="">
{{{meta.users.PUBLICKEY.html}}}
</div>
</div>
<div class="col-md-4">
<div class="text-center" {{{meta.users.IMGAVATAR.tag}}}
newvalue="">
{{{meta.users.IMGAVATAR.html}}}
</div>
</div>
</div>
<button type="submit" class="btn btn-primary" onclick="{{{onclickpub}}}">
{{{btnsavepub}}}
</button>
<div class="msgsubmit"></div>
</form>
</div>
</div>
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">{{{privateinfo}}}</h5>
</div>
<div class="card-body">
<form id="userprivateinfo" somethingchange="false" >
<div class="row">
{{{infoprivate}}}
</div>
<div class="row">
<div class="mb-3 col-md-6" {{{meta.users.NICKNAME.tag}}}>
{{{meta.users.NICKNAME.html}}}
</div>
<div class="mb-3 col-md-6" {{{meta.users.NAME.tag}}}>
{{{meta.users.NAME.html}}}
</div>
</div>
<div class="mb-3" {{{meta.users.EMAIL.tag}}}>
{{{meta.users.EMAIL.html}}}
</div>
<div class="mb-3" {{{meta.users.ADDRESS1.tag}}}>
{{{meta.users.ADDRESS1.html}}}
</div>
<div class="mb-3" {{{meta.users.ADDRESS2.tag}}}>
{{{meta.users.ADDRESS2.html}}}
</div>
<div class="row">
<div class="mb-3 col-md-6" {{{meta.users.CITY.tag}}}>
{{{meta.users.CITY.html}}}
</div>
<div class="mb-3 col-md-4" {{{meta.users.ZIP.tag}}}>
{{{meta.users.ZIP.html}}}
</div>
<div class="mb-3 col-md-2" {{{meta.users.COUNTRY.tag}}}>
{{{meta.users.COUNTRY.html}}}
</div>
</div>
<button type="submit" class="btn btn-primary" onclick="{{{onclickprivate}}}">
{{{btnsaveprivate}}}
</button>
</form>
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">{{{publicinfo}}}</h5>
</div>
<div class="card-body">
<form id="userpublicinfo" somethingchange="false">
<div class="row">
<div class="col-md-8">
<div class="mb-3" {{{meta.users.PSEUDO.tag}}} tpl="{{{users.PSEUDO.type}}}" object="users" fieldname="PSEUDO" placeholder="{{{users.PSEUDO.placeholder}}}" desc="{{{users.PSEUDO.desc}}}"
checkdata="{{{users.PSEUDO.check}}}"
newvalue="">
{{{meta.users.PSEUDO.html}}}
</div>
<div class="mb-3" formfieldtype="{{users.BIOGRAPHY.type}}" object="users" fieldname="BIOGRAPHY" placeholder="{{users.BIOGRAPHY.placeholder}}" rows="{{{users.BIOGRAPHY.rows}}}" desc="{{{users.BIOGRAPHY.desc}}}" checkdata="{{{users.BIOGRAPHY.check}}}" info="{{{users.BIOGRAPHY.info}}}"
newvalue="">
</div>
<div class="mb-3" formfieldtype="{{users.PUBLICKEY.type}}" object="users" fieldname="PUBLICKEY" placeholder="{{}}" rows="2" desc="{{{users.PUBLICKEY.desc}}}" info="{{{users.PUBLICKEY.info}}}"
newvalue="">
</div>
</div>
<div class="col-md-4">
<div class="text-center" formfieldtype="{{users.IMGAVATAR.type}}" object="users" fieldname="IMGAVATAR" altimg="{{users.PSEUDO.desc}}" classimg="rounded-circle img-responsive mt-2" width="{{users.IMGAVATAR.width}}" height="{{users.IMGAVATAR.height}}" classdivupload="mt-2" classbtn="btn btn-primary" desc="{{{users.IMGAVATAR.desc}}}"
info="{{{users.IMGAVATAR.info}}}"
newvalue="">
</div>
</div>
</div>
<button type="submit" class="btn btn-primary" onclick="{{{onclickpub}}}">
{{{btnsavepub}}}
</button>
<div class="msgsubmit"></div>
</form>
</div>
</div>
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">{{{privateinfo}}}</h5>
</div>
<div class="card-body">
<form id="userprivateinfo" somethingchange="false" >
<div class="row">
{{{infoprivate}}}
</div>
<div class="row">
<div class="mb-3 col-md-6" formfieldtype="{{{users.NICKNAME.type}}}" object="users" fieldname="NICKNAME" placeholder="{{{users.NICKNAME.placeholder}}}" desc="{{{users.NICKNAME.desc}}}"
checkdata="{{{users.NICKNAME.check}}}"
newvalue="">
<div class="mb-3 col-md-6" formfieldtype="{{{users.NAME.type}}}" object="users" fieldname="NAME" placeholder="{{{users.NAME.placeholder}}}" desc="{{{users.NAME.desc}}}"
checkdata="{{{users.NAME.check}}}"
newvalue="">
</div>
</div>
<div class="mb-3" formfieldtype="{{{users.EMAIL.type}}}" object="users" fieldname="EMAIL" placeholder="{{{users.EMAIL.placeholder}}}" desc="{{{users.EMAIL.desc}}}"
checkdata="{{{users.EMAIL.check}}}"
newvalue="">
</div>
<div class="mb-3" formfieldtype="{{{users.ADDRESS1.type}}}" object="users" fieldname="ADDRESS1" placeholder="{{{users.ADDRESS1.placeholder}}}" desc="{{{users.ADDRESS1.desc}}}"
checkdata="{{{users.ADDRESS1.check}}}"
newvalue="">
</div>
<div class="mb-3" formfieldtype="{{{users.ADDRESS2.type}}}" object="users" fieldname="ADDRESS2" placeholder="{{{users.ADDRESS2.placeholder}}}" desc="{{{users.ADDRESS2.desc}}}"
checkdata="{{{users.ADDRESS2.check}}}"
newvalue="">
</div>
<div class="row">
<div class="mb-3 col-md-6" formfieldtype="{{{users.CITY.type}}}" object="users" fieldname="CITY" placeholder="{{{users.CITY.placeholder}}}" desc="{{{users.CITY.desc}}}"
checkdata="{{{users.CITY.check}}}"
newvalue="">
</div>
<div class="mb-3 col-md-4" formfieldtype="{{{users.ZIP.type}}}" object="users" fieldname="ZIP" placeholder="{{{users.ZIP.placeholder}}}" desc="{{{users.ZIP.desc}}}"
checkdata="{{{users.ZIP.check}}}"
newvalue="">
</div>
<div class="mb-3 col-md-2" formfieldtype="{{{users.COUNTRY.type}}}" object="users" fieldname="COUNTRY" placeholder="{{{users.COUNTRY.placeholder}}}" desc="{{{users.COUNTRY.desc}}}"
checkdata="{{{users.COUNTRY.check}}}"
newvalue="">
</div>
</div>
<button type="submit" class="btn btn-primary" onclick="{{{onclickprivate}}}">
{{{btnsaveprivate}}}
</button>
</form>
</div>
</div>
</div>

View File

@@ -0,0 +1,22 @@
<div class="card">
<div class="card-body">
<h5 class="card-title">Password</h5>
<form>
<div class="mb-3">
<label class="form-label" for="inputPasswordCurrent">Current password</label>
<input type="password" class="form-control" id="inputPasswordCurrent">
<small><a href="#">Forgot your password?</a></small>
</div>
<div class="mb-3">
<label class="form-label" for="inputPasswordNew">New password</label>
<input type="password" class="form-control" id="inputPasswordNew">
</div>
<div class="mb-3">
<label class="form-label" for="inputPasswordNew2">Verify password</label>
<input type="password" class="form-control" id="inputPasswordNew2">
</div>
<button type="submit" class="btn btn-primary">Save changes</button>
</form>
</div>
</div>

View File

@@ -0,0 +1,19 @@
{
"title": "Profile",
"desc": "<p>Vos informations</p>",
"submenutitle": "Blabla",
"submenuitems": [{
"submenudesc": "group1",
"active": "active",
"id": "gr1",
"content": "blabla group1"
}, {
"submenudesc": "group2",
"id": "gr2",
"content": "blabla group2"
}, {
"submenudesc": "group3",
"id": "gr3",
"content": "blabla group 3"
}]
}

View File

@@ -0,0 +1,26 @@
<h1 class="h3 mb-3">{{title}}</h1>
{{{desc}}}
<div class="row">
<div class="col-md-3 col-xl-2">
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">{{{submenutitle}}}</h5>
</div>
<div class="list-group list-group-flush" role="tablist">
{{#submenuitems}}
<a class="list-group-item list-group-item-action {{active}}" data-bs-toggle="list" href="#{{id}}" role="tab">{{{submenudesc}}}
</a>
{{/submenuitems}}
</div>
</div>
</div>
<div class="col-md-9 col-xl-10">
<div class="tab-content">
{{#submenuitems}}
<div class="tab-pane fade show {{active}}" id="{{id}}" role="tabpanel">
{{{content}}}
</div>
{{/submenuitems}}
</div>
</div>
</div>

View File

@@ -0,0 +1,14 @@
{
"navbarclass": "navbar-expand navbar-light navbar-bg",
"footer": {
"urlapixtribe": "https://apixtribe.org",
"claim": "apixtribe made with love for freedom",
"links": [{
"url": "#",
"desc": "Support"
}, {
"url": "#",
"desc": "Privacy"
}]
}
}

View File

@@ -0,0 +1,7 @@
{
"title": "Need-Data manager",
"js": [],
"icons": ["static/img/icons/iconX74x74.png"],
"manifest": "manifest.json",
"css": ["static/fonts/icofont/icofont.min.css", "css/app/styles.css"]
}

View File

@@ -0,0 +1,53 @@
{
"signin": {
"claimh1": "Need-Data",
"claimp": "Votre hébergement apixtribe en toute confidentialité.",
"logo": "static/img/logo/ndda.png",
"classlogo": "img-fluid",
"login": "Identifiant",
"loginph": "Votre identifiant (login ou clé public)",
"password": "Mot de passe",
"passwordph": "Mot de passe ou hash sur clé public",
"forget": "Mot de passe oublié?",
"forgetonclick": "pwa.auth.route('#resetpsw');return false;",
"rememberme": "Se souvenir de moi sur ce navigateur",
"submit": "S'authentifier",
"onclick": "pwa.auth.login();return false;",
"registerrequest": "Rejoindre un espace",
"registeronclick": "pwa.auth.route('#register');return false;",
"ifAuthenticatedRouteto": "app_index_fr.html",
"msgok": "Bienvenu dans votre espace.",
"msgko": "Désolé, vos identifiants ne sont pas valides! Au bout de 3 echecs, vous devrez attendre 1 minute entre chaque tentative."
},
"resetpsw": {
"claimh1": "Mot de passe oublié",
"claimp": "Indiquez votre email. Si vous n'avez pas indiqué d'email, vos données sont definitivement perdues, c'est le prix de votre anonymat.",
"emailph": "indiquez votre email",
"submit": "Recevoir un lien temporaire",
"onclick": "pwa.auth.forget();return false;",
"msgok": "Une email vous a été envoyé",
"msgko": "Lien impossible à envoyer "
},
"register": {
"claimh1": "S'inscrire à votre communauté",
"claimp": "Vous devez disposez du nom de la communauté qui vous invite à ouvrir un compte chez elle.<br> Pour créer une communauté, sur cet hébergement: <a href='mailto:contact@need-data.com'>contact@need-data.com</a>.<br> En savoir plus sur <a href='https://apixtribe.org/anonymat_avec_apixppress.html'>Anomymat & apixtribe</a>.",
"logoapixtribe": "static/img/logo/apixtribe.png",
"logoowner": "static/img/logo/ndda.png",
"login": "Votre identifiant",
"loginph": "login ou clé public",
"community": "Nom de communauté",
"communityph": "Nom communiqué par la personne qui vous invite.",
"email": "Email (optionel)",
"emailph": "Sans email impossible de ré-initialiser son compte",
"password": "Mot de passe",
"passwordph": "Mot de passe ou hash sur clé public",
"autologin": "Génerer une paire<br> de clé public/privée",
"submit": "S'enregistrer",
"autologinonclick": "pwa.auth.autologin();return false;",
"onclick": "pwa.auth.register();return false;",
"msgok": "Votre compte a bien été créé",
"msgko": "Désolé impossible de créer le compte",
"signinonclick": "pwa.auth.route('#signin');return false;",
"signinrequest": "S'authentifier"
}
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1,5 @@
{
"title": "apixtribe",
"js": [],
"css": ["static/fonts/icofont/icofont.min.css", "css/fullscreen/styles.css"]
}

View File

@@ -0,0 +1,33 @@
{
"iconnotif": "bell",
"number": 0,
"notifheader": "Vos notifications",
"notiffooter": "Voir toutes les notifications",
"actionnotifmanager": "",
"href": "?action=notification.view",
"notifs": [{
"urldetail": "#",
"classicon": "text-danger",
"icon": "alert",
"title": "Intusion de 192.168.1.3",
"desc": "Check your log",
"elapse": "il y a 13mn"
},
{
"urldetail": "#",
"classicon": "text-success",
"icon": "star",
"title": "Successfull backup",
"desc": "",
"elapse": "il y a 2 jours"
},
{
"urldetail": "#",
"classicon": "text-warning",
"icon": "bell",
"title": "Commande en attente",
"desc": "Vous avez des commandes en attente de traitement",
"elapse": "il y a 6 heures"
}
]
}

View File

@@ -0,0 +1,22 @@
[{
"groupheader": "Admin apixtribe",
"sbssgroupmenu": [{
"name": "Tribes",
"icon": "sliders",
"actionclick": "pwa.tribeids.init()",
"iditemmenus": "admintribeid",
"itemmenus": [{
"name": "Suivi des tribeid",
"actionclick": "pwa.tribeids.tribeidactivity()"
},
{
"name": "Admin des tribeid",
"actionclick": "pwa.tribeids.settings()"
}
]
}, {
"name": "Suivi technique",
"icon": "sliders",
"actionclick": "pwa.tribeids.suivi()"
}]
}]

View File

@@ -0,0 +1,47 @@
[{
"groupheader": "Mon espace client",
"sbssgroupmenu": [{
"name": "Espace web",
"icon": "sliders",
"actionclick": "pwa.spaceweb.init()",
"iditemmenus": "clentidspace",
"itemmenus": [{
"name": "Mon espace web",
"actionclick": "pwa.spaceweb.myfile()"
},
{
"name": "Mes utilisateurs",
"actionclick": "pwa.spaceweb.users()"
},
{
"name": "Mes contenus",
"actionclick": "pwa.spaceweb.content()"
},
{
"name": "Mes plugins",
"actionclick": "pwa.spaceweb.plugins()"
}
]
}, {
"name": "Referentiels",
"icon": "sliders",
"iditemmenus": "adminreferentiel",
"itemmenus": [{
"name": "Force update",
"actionclick": "pwa.referential.forceupdate()"
},
{
"name": "data",
"actionclick": "pwa.referential.setting('data')"
},
{
"name": "json",
"actionclick": "pwa.referential.setting('json')"
},
{
"name": "Objects",
"actionclick": "pwa.referential.setting('object')"
}
]
}]
}]

View File

@@ -0,0 +1,23 @@
{
"sbbrandlink": "app_index_fr.html",
"sbtitle": "Need-Data",
"sbgroupmenu": [{
"groupheader": "apixtribe",
"sbssgroupmenu": [{
"name": "Les news",
"icon": "sliders",
"actionclick": "pwa.news.init()"
},
{
"name": "Reporting",
"icon": "sliders",
"actionclick": "pwa.reporting.init()",
"iditemmenus": "reportingapixtribe",
"itemmenus": [{
"name": "",
"actionclick": "pwa.reporting.init()"
}]
}
]
}]
}

View File

@@ -0,0 +1,19 @@
[{
"icon": "user",
"desc": "Mon profile",
"href": "?action=user.settings",
"menubreaker": false
},
{
"icon": "pie-chart",
"desc": "Activity",
"href": "?action=user.activity",
"menubreaker": true
},
{
"icon": "settings",
"desc": "Log out",
"href": "?action=auth.logout",
"menubreaker": false
}
]

View File

@@ -0,0 +1,16 @@
{
"withsearch": true,
"searchtxt": "Recherche...",
"withnotification": true,
"withmessage": true,
"messageheader": "Vos messages non lus",
"messagefooter": "Voir tous les messages",
"avatarimg": "static/img/avataranonymous2.png",
"name": "Anonymous",
"menuprofil": [{
"icon": "user",
"desc": "S'identifier",
"href": "fullscreen_auth_fr.html",
"menubreaker": false
}]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 2.3 MiB

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.0 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@@ -0,0 +1 @@
{"time":1640518264618}

View File

@@ -0,0 +1 @@
{"time":1640518264044}