globular-mvc
Version:
Generic template to create web-application that made use of globular as backend and materialize as css (wrap in web-component's)
1,303 lines (1,067 loc) • 84.2 kB
JavaScript
import "@polymer/iron-icons/social-icons";
import { GetResourcePermissionsRqst, GetSharedResourceRqst, Permission, Permissions, RemoveSubjectFromShareRqst, SetResourcePermissionsRqst, SubjectType } from "globular-web-client/rbac/rbac_pb";
import { CreateNotificationRqst, Notification, NotificationType } from "globular-web-client/resource/resource_pb";
import * as getUuidByString from "uuid-by-string";
import { Account } from "../Account";
import { Application } from "../Application";
import { ApplicationView } from "../ApplicationView";
import { Group } from "../Group";
import { generatePeerToken, Model } from "../Model";
import { Menu } from './Menu';
import { fireResize, formatBoolean, randomUUID } from "./utility";
import { Wizard } from "./Wizard";
import { Link } from "./Link"
import { File } from "../File"
import { Notification as Notification_ } from '../Notification';
/**
* Login/Register functionality.
*/
export class ShareMenu extends Menu {
// Create the application view.
constructor() {
super("share", "social:share", "Share")
// The panel to manage shared content.
this.sharePanel = null;
this.onclick = () => {
let icon = this.getIconDiv().querySelector("iron-icon")
icon.style.removeProperty("--iron-icon-fill-color")
if (this.sharePanel.parentNode == undefined) {
Model.eventHub.publish("_display_workspace_content_event_", this.sharePanel, true)
}
}
}
// Initialyse the share panel.
init(account) {
if (this.sharePanel == null) {
this.account = account;
// init once...
this.sharePanel = new SharePanel(account);
}
}
}
customElements.define('globular-share-menu', ShareMenu)
/**
* Sample empty component
*/
export class SharePanel extends HTMLElement {
// attributes.
// Create the applicaiton view.
constructor(account) {
super()
// keep local account in memory...
this.account = account;
// Set the shadow dom.
this.attachShadow({ mode: 'open' });
// Innitialisation of the layout.
this.shadowRoot.innerHTML = `
<style>
paper-card {
background-color: var(--palette-background-paper);
margin-top: 10px;
height: calc(100vh - 85px);
font-size: 1.65rem;
}
#share_div{
display: flex;
padding-left: 10px;
height: calc(100% - 100px);
flex-grow: 1;
}
#share_content_div{
min-width: 728px;
max-width: 728px;
width: 728px;
}
#title_div{
display: flex;
flex-wrap: wrap;
}
h1{
margin: 0px;
margin-left: 10px;
}
h2{
margin-bottom: 4px;
margin-left: 10px;
border-bottom: 1px solid var(--palette-divider);
width: 80%;
}
::slotted(globular-shared-resources){
flex-grow: 1;
}
paper-card h1 {
font-size: 1.65rem;
}
globular-subjects-view{
border-right: 1px solid var(--palette-divider);
}
.card-content{
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
padding: 0px;
padding-bottom: 10px;
font-size: 1rem;
}
@media (max-width: 500px) {
.card-content{
width: calc(100vw - 10px);
}
#share_div{
padding: 0px;
flex-direction: column;
flex-grow: 1;
}
#share_content_div{
min-width: auto;
width: 100%;
height: 100%;
}
globular-subjects-view{
border-right: none;
}
}
</style>
<paper-card id="container">
<div class="card-content">
<div style="display: flex; justify-content: center;">
<h1 style="flex-grow: 1;">Shared Resources...</h1>
<paper-icon-button id="close-btn" icon="icons:close"></paper-icon-button>
</div>
<div id="share_div">
<globular-subjects-view></globular-subjects-view>
<div id="share_content_div">
<slot></slot>
</div>
</div>
</div>
</paper-card>
`
this.onclose = null
// simply close the watching content...
this.shadowRoot.querySelector("#close-btn").onclick = () => {
this.parentNode.removeChild(this)
if (this.onclose != null) {
this.onclose()
}
}
let subjectsView = this.shadowRoot.querySelector("globular-subjects-view")
// Append account
subjectsView.on_account_click = (accountDiv, account) => {
accountDiv.account = account;
this.displaySharedResources(account)
}
// Append group
subjectsView.on_group_click = (groupDiv, group) => {
groupDiv.group = group;
this.displaySharedResources(group)
}
}
// Display resource shared with a given subject.
displaySharedResources(subject) {
this.innerHTML = "" // clear the slot...
this.appendChild(new SharedResources(subject))
}
}
customElements.define('globular-share-panel', SharePanel)
/**
* That panel display resource share with a given subject (account, group, organization etc.)
*/
export class SharedResources extends HTMLElement {
// attributes.
// Create the applicaiton view.
constructor(subject) {
super()
// Set the shadow dom.
this.attachShadow({ mode: 'open' });
// Innitialisation of the layout.
this.shadowRoot.innerHTML = `
<style>
::-webkit-scrollbar {
width: 5px;
height: 5px;
}
::-webkit-scrollbar-track {
background: var(--palette-background-default);
}
::-webkit-scrollbar-thumb {
background: var(--palette-divider);
}
#container{
display: flex;
flex-direction: column;
height: 100%;
}
.resource-share-div{
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
position: relative;
}
#you-share-with-div{
display: flex;
flex-wrap: wrap;
margin-top: 10px;
}
#share-with-you-div{
display: flex;
flex-wrap: wrap;
margin-top: 10px;
}
globular-link{
margin-left: 15px;
}
/* Need to position the badge to look like a text superscript */
paper-tab {
padding-right: 25px;
}
paper-tabs{
/* custom CSS property */
--paper-tabs-selection-bar-color: var(--palette-primary-main);
color: var(--palette-text-primary);
--paper-tab-ink: var(--palette-action-disabled);
}
paper-tab paper-badge {
--paper-badge-background: var(--palette-warning-main);
--paper-badge-width: 16px;
--paper-badge-height: 16px;
--paper-badge-margin-left: 10px;
}
@media(max-width: 500px){
#container{
width: 100vw - 10px);
margin: 0px;
}
.resource-share-div {
margin: 0px;
width: calc(100vw - 10px);
}
}
</style>
<div id="container">
<paper-tabs selected="0">
<paper-tab id="share-with-you"">
Share with you
</paper-tab>
<paper-tab id="you-share-with">
You share with
</paper-tab>
</paper-tabs>
<div class="resource-share-div">
<div id="scroll-container" style="position: absolute; overflow-y: auto; top:0px; left:0px; right: 0px; bottom: 0px;">
<div id="share-with-you-div"></div>
<div id="you-share-with-div" style="display: none;"></div>
</div>
</div>
</div>
`
// give the focus to the input.
let scrollContainer = this.shadowRoot.querySelector("#scroll-container")
scrollContainer.onscroll = () => {
if (scrollContainer.scrollTop == 0) {
scrollContainer.style.boxShadow = ""
scrollContainer.style.borderTop = ""
} else {
scrollContainer.style.boxShadow = "inset 0px 5px 6px -3px rgb(0 0 0 / 40%)"
scrollContainer.style.borderTop = "1px solid var(--palette-divider)"
}
}
// get resources share with a given account...
let youShareWithDiv = this.shadowRoot.querySelector("#you-share-with-div")
let shareWithYouDiv = this.shadowRoot.querySelector("#share-with-you-div")
this.shadowRoot.querySelector("#share-with-you").onclick = () => {
youShareWithDiv.style.display = "none"
shareWithYouDiv.style.display = "flex"
}
this.shadowRoot.querySelector("#you-share-with").onclick = () => {
youShareWithDiv.style.display = "flex"
shareWithYouDiv.style.display = "none"
}
// The logged user... ( 'you' in the context of a session)
ApplicationView.wait(`<div style="display: flex; flex-direction: column; justify-content: center;"><span>Retreive</span><span>shared resources with</span><span>` + subject.id + `</span><span>...</span>` )
this.getSharedResources(Application.account, subject, resources => {
this.displaySharedResources(youShareWithDiv, resources, subject, true)
this.getSharedResources(subject, Application.account, resources => {
this.displaySharedResources(shareWithYouDiv, resources, subject, false)
ApplicationView.resume()
})
})
}
displaySharedResources(div, resources, subject, deleteable) {
let range = document.createRange()
let displayLink = () => {
let r = resources.pop()
let globule = Model.getGlobule(r.getDomain())
File.getFile(globule, r.getPath(), 100, 64, file => {
let id = "_" + getUuidByString(file.path)
// so here I will determine if I display the deleteable icon...
let deleteable_ = deleteable
if(deleteable){
// Here I will make sure that the delete button has an effect on the share.
// for exemple is the permission is at group level i will not display delete
// button at accout level even if the resource appear in the list. To remove the
// resource the user must remove group permission on it.
if (subject.constructor.name == "Account_Account") {
deleteable_ = r.getAccountsList().indexOf(subject.id + "@" + subject.domain) != -1
} else if (subject.constructor.name == "Group_Group") {
deleteable_ = r.getGroupsList().indexOf(subject.id + "@" + subject.domain) != -1
} else if (subject.constructor.name == "Application_Application") {
deleteable_ = r.getApplicationList().indexOf(subject.id + "@" + subject.domain) != -1
} else if (subject.constructor.name == "Organization_Organization") {
deleteable_ = r.getOrganizationList().indexOf(subject.id + "@" + subject.domain) != -1
}
}
let alias = ""
if(file.videos){
alias = file.videos[0].getDescription()
}else if (file.titles){
alias = file.titles[0].getName()
}else if (file.audios){
alias = file.audio[0].getTitle()
}
let html = `<globular-link alias="${alias}" mime="${file.mime}" id="${id}" ${deleteable_ ? "deleteable" : ""} path="${file.path}" thumbnail="${file.thumbnail}" domain="${file.domain}"></globular-link>`
div.appendChild(range.createContextualFragment(html))
if (resources.length > 0) {
displayLink();
}
let lnk = div.querySelector(`#${id}`)
lnk.ondelete = () => {
// so now I will remove share resource.
let rqst = new RemoveSubjectFromShareRqst
rqst.setDomain(file.domain)
rqst.setPath(file.path)
let globule = Model.getGlobule(file.domain)
if (subject.constructor.name == "Account_Account") {
rqst.setType(SubjectType.ACCOUNT)
} else if (subject.constructor.name == "Group_Group") {
rqst.setType(SubjectType.GROUP)
} else if (subject.constructor.name == "Application_Application") {
rqst.setType(SubjectType.APPLICATION)
} else if (subject.constructor.name == "Organization_Organization") {
rqst.setType(SubjectType.ORGANIZATION)
}
// set the subject domain.
rqst.setSubject(subject.id + "@" + subject.domain)
generatePeerToken(globule, token => {
globule.rbacService.removeSubjectFromShare(rqst, { domain: Model.domain, address: Model.address, application: Model.application, token: token })
.then(
// Display message...
ApplicationView.displayMessage("Subject " + subject.id + " was removed from shared of " + file.path, 3000)
).catch(err => ApplicationView.displayMessage(err))
})
}
}, err => {
console.log(err);
if (resources.length > 0) {
displayLink()
}
})
}
if (resources.length > 0) {
displayLink()
}
}
// Return the list of resource for a given subject.
getSharedResources(share_by, share_with, callback) {
let globules = Model.getGlobules()
let resources = [];
let getSharedResource_ = () => {
let globule = globules.pop()
let rqst = new GetSharedResourceRqst
if (share_with.constructor.name == "Account_Account") {
rqst.setType(SubjectType.ACCOUNT)
rqst.setSubject(share_with.id + "@" + share_with.domain)
rqst.setOwner(share_by.id + "@" + share_by.domain)
} else if (share_with.constructor.name == "Group_Group") {
rqst.setType(SubjectType.GROUP)
rqst.setSubject(share_with.id + "@" + share_with.domain)
rqst.setOwner(share_by.id + "@" + share_by.domain)
}
// Get file shared by account.
globule.rbacService.getSharedResource(rqst, { application: Application.application, domain: globule.domain, token: localStorage.getItem("user_token") })
.then(rsp => {
resources = resources.concat(rsp.getSharedresourceList())
if (globules.length == 0) {
callback(resources)
} else {
getSharedResource_()
}
}).catch(err => {
if (globules.length == 0) {
callback(resources)
} else {
getSharedResource_()
}
})
}
if (globules.length > 0)
getSharedResource_()
}
}
customElements.define('globular-shared-resources', SharedResources)
/**
* create a new permission for a given resource.
*/
export class ShareResourceMenu extends HTMLElement {
// attributes.
// Create the applicaiton view.
constructor() {
super()
// Set the shadow dom.
this.attachShadow({ mode: 'open' });
this.files = [];
// Innitialisation of the layout.
this.shadowRoot.innerHTML = `
<style>
#container{
}
#share-resource-btn {
height: 18px;
}
#share-resource-btn:hover{
cursor: pointer;
}
</style>
<div id="container">
<iron-icon id="share-resource-btn" icon="social:share">
</iron-icon>
</div>
`
// give the focus to the input.
this.shadowRoot.querySelector("#share-resource-btn").onclick = (evt) => {
evt.stopPropagation();
this.share()
}
}
setFiles(files) {
this.files = files;
}
share() {
let shareResourceWizard = new ShareResourceWizard(this.files)
shareResourceWizard.show()
}
}
customElements.define('globular-share-resource-menu', ShareResourceMenu)
/**
* Sample empty component
*/
export class ShareResourceWizard extends HTMLElement {
// attributes.
// Create the applicaiton view.
constructor(files) {
super()
this.files = files;
// Set the shadow dom.
this.attachShadow({ mode: 'open' });
// Innitialisation of the layout.
this.shadowRoot.innerHTML = `
<style>
paper-card{
display: flex;
flex-direction: column;
border-left: 1px solid var(--palette-divider);
border-right: 1px solid var(--palette-divider);
background-color: var(--palette-background-paper);
}
.header {
display: flex;
color: var(--palette-text-accent);
background-color: var(--palette-primary-accent);
align-items: center;
}
.header paper-icon-button {
min-width: 40px;
}
.title-span {
flex-grow: 1;
}
</style>
<paper-card>
<div class="header">
<iron-icon icon="social:share" style="padding-left: 10px;"></iron-icon>
<span class="title-span"> </span>
<paper-icon-button icon="icons:close"></paper-icon-button>
</div>
<slot> </slot>
</paper-card>
`
// give the focus to the input.
let wizard = new Wizard(800)
// Here I will set the wizard pages...
let range = document.createRange()
let files_page = `
<div class="globular-wizard-page" style="display: flex; flex-wrap: wrap; height: 500px; overflow-y: auto;">
`
// The welcome pages...
files.forEach(file => {
let title = null
let name = file.name;
if (file.titles) {
title = file.titles[0]
name = title.getName()
if (title.getEpisode() > 0) {
name += " S" + title.getSeason() + "-E" + title.getEpisode()
}
} else if (file.videos) {
title = file.videos[0]
name = title.getDescription()
} else if (file.audios) {
title = file.audios[0]
name = title.getTitle()
}
let uuid = "_" + getUuidByString(file.path)
let file_page = `
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px; height: fit-content; ">
<div style="display: flex; flex-direction: column; border: 1px solid var(--palette-divider); padding: 5px; border-radius: 2.5px;">
<div style="display: flex; align-items: center; width: 100%;">
<paper-checkbox checked id="${uuid + "_checkbox"}"></paper-checkbox>
<span class="title-span" style="flex-grow: 1;"></span>
<iron-icon class="wizard-file-infos-btn" id="${uuid + "_infos_btn"}" icon="icons:info"></iron-icon>
</div>
<img style="height: 64px; width: auto; margin-top: 4px;" src="${file.thumbnail}"></img>
</div>
<span style="font-size: .85rem; padding: 2px; display: block; max-width: 128px; word-break: break-all;" title=${file.path}> ${name}</span>
</div>
`
files_page += file_page;
})
files_page += "</div>"
wizard.appendPage(range.createContextualFragment(files_page).children[0])
// Now the user, group application and organization page...
let subjects_page = `
<style>
.globular-wizard-page-content{
display: flex;
height: 100%;
}
@media(max-width: 500px){
.globular-wizard-page-content{
flex-direction: column;
}
}
</style>
<div class="globular-wizard-page" style="height: 500px; overflow-y: auto;">
<div class="globular-wizard-page-content">
<globular-subjects-view style="height: 100%; min-width: 250px; border-right: 1px solid var(--palette-divider)"></globular-subjects-view>
<globular-subjects-selected style="height: 100%; margin-left: 20px; flex-grow: 1"></globular-subjects-selected>
</div>
</div>
`
wizard.appendPage(range.createContextualFragment(subjects_page).children[1])
let subjectsView = wizard.querySelector("globular-subjects-view")
let selectedSubjects = wizard.querySelector("globular-subjects-selected")
let shared_permissions_page = `
<div class="globular-wizard-page" style="height: 500px; overflow-y: auto;">
<globular-shared-subjects-permissions></globular-shared-subjects-permissions>
</div>
`
wizard.appendPage(range.createContextualFragment(shared_permissions_page).children[0])
let sharedSubjectsPermission = wizard.querySelector("globular-shared-subjects-permissions")
// Append account
subjectsView.on_account_click = (accountDiv, account) => {
accountDiv.account = account;
selectedSubjects.appendAccount(accountDiv)
}
// Append group
subjectsView.on_group_click = (groupDiv, group) => {
groupDiv.group = group;
selectedSubjects.appendGroup(groupDiv)
}
// if account are remove or append...
subjectsView.on_accounts_change = () => {
sharedSubjectsPermission.setAccounts(selectedSubjects.getAccounts())
}
subjectsView.on_groups_change = () => {
sharedSubjectsPermission.setGroups(selectedSubjects.getGroups())
}
let summary = `
<style>
.globular-wizard-page-content{
display: flex;
height: 100%;
}
#content{
display: flex;
flex-direction: column;
margin-left: 30px;
padding-left: 30px;
border-left: 1px solid var(--palette-divider)
}
@media(max-width: 500px){
.globular-wizard-page-content{
flex-direction: column;
}
#content{
border-bottom: 1px solid var(--palette-divider)
}
}
</style>
<div class="globular-wizard-page" style="max-height: 500px; overflow-y: auto;">
<div class="globular-wizard-page-content">
<div>
<iron-icon id="status-ico" style="height: 64px; width: 64px; fill: var(--palette-success-main);" icon="icons:check-circle"></iron-icon>
</div>
<div id="content" style="">
<p style="flex-grow: 1;">
Resources permissions was successfully created for
</p>
<div style="display: flex; flex-wrap: wrap;" id="resources"></div>
<p>
The following user's will be notified of their new access
</p>
<div style="display: flex; flex-wrap: wrap;" id="paticipants"></div>
</div>
</div>
</div>
`
wizard.setSummaryPage(range.createContextualFragment(summary).children[1])
wizard.ondone = (summary_page) => {
// Here I will get read element from the interface to get permissions infos...
let permissions = sharedSubjectsPermission.getPermissions()
this.setFilesPermissions(permissions, files, errors => {
let participants = selectedSubjects.getAccounts()
let groups = selectedSubjects.getGroups()
// display the list of resource...
let getMembers = (index) => {
let group = groups[index]
group.getMembers(members => {
// append members...
members.forEach(member => {
if (participants.filter(p => p.id + "@" + p.domain === member.id + "@" + member.domain).length == 0) {
participants.push(member)
}
})
index++
if (index < groups.length) {
getMembers(index)
} else {
displayParticipants()
}
})
}
let displayResources = () => {
let resourcesDiv = summary_page.querySelector("#resources")
let statusIco = summary_page.querySelector("#status-ico")
let nbTotal = files.length
let nbFail = 0
files.forEach(file => {
let title = null
let name = file.name;
if (file.titles) {
title = file.titles[0]
name = title.getName()
if (title.getEpisode() > 0) {
name += " S" + title.getSeason() + "-E" + title.getEpisode()
}
} else if (file.videos) {
title = file.videos[0]
name = title.getDescription()
} else if (file.audios) {
title = file.audios[0]
name = title.getTitle()
}
let uuid = "_" + getUuidByString(file.path)
let fileDiv = `
<div style="display: flex; flex-direction: column; align-items: center; width: fit-content; margin: 5px; height: fit-content; ">
<div style="display: flex; flex-direction: column; border: 1px solid var(--palette-divider); padding: 5px; border-radius: 2.5px;">
<div style="display: flex; align-items: center; width: 100%;">
<span class="title-span" style="flex-grow: 1;"></span>
<iron-icon style="fill: var(--palette-success-main);" id="${uuid + "_success"}" icon="icons:check-circle"></iron-icon>
<iron-icon style="fill: var(--palette-secondary-main);" id="${uuid + "_error"}" icon="icons:error"></iron-icon>
</div>
<img style="height: 64px; width: auto;" src="${file.thumbnail}"></img>
</div>
<span style="font-size: .85rem; padding: 2px; display: block; max-width: 128px; word-break: break-all;" title=${file.path}> ${name}</span>
</div>
`
resourcesDiv.appendChild(range.createContextualFragment(fileDiv))
// Here I will display error in the interface if ther some...
if (errors[file.path]) {
resourcesDiv.querySelector(`#${uuid + "_success"}`).style.display = "none"
resourcesDiv.querySelector(`#${uuid + "_error"}`).title = errors[file.path].message
nbFail++
if(nbFail < nbTotal){
statusIco.icon = "icons:warning"
statusIco.style.fill = "var(--palette-error-main)"
}else{
statusIco.icon = "icons:error"
statusIco.style.fill = "var(--palette-secondary-main)"
}
} else {
resourcesDiv.querySelector(`#${uuid + "_error"}`).style.display = "none"
participants.forEach(contact => {
// So here I will send a notification to the participant with the share information...
let rqst = new CreateNotificationRqst
let notification = new Notification
notification.setDate(parseInt(Date.now() / 1000)) // Set the unix time stamp...
notification.setId(randomUUID())
notification.setRecipient(contact.id + "@" + contact.domain)
notification.setSender(Application.account.id + "@" + Application.account.domain)
notification.setNotificationType(NotificationType.USER_NOTIFICATION)
notification.setMac(Model.getGlobule(contact.domain).config.Mac)
let alias = ""
if(file.videos){
alias = file.videos[0].getDescription()
}else if (file.titles){
alias = file.titles[0].getName()
}else if (file.audios){
alias = file.audio[0].getTitle()
}
let date = new Date()
let msg = `
<div style="display: flex; flex-direction: column; padding: 16px;">
<div>
${date.toLocaleString()}
</div>
<div>
<div style="display: flex; flex-direction: column;">
<p>
${Application.account.name} has share file with you,
</p>
<globular-link alias="${alias}" mime="${file.mime}" path="${file.path}" thumbnail="${file.thumbnail}" domain="${file.domain}"></globular-link>
</div>
</div>
</div>
`
notification.setMessage(msg)
rqst.setNotification(notification)
// Create the notification...
let globule = Model.getGlobule(contact.domain)
generatePeerToken(globule, token => {
globule.resourceService.createNotification(rqst, {
token: token,
application: Model.application,
domain: contact.domain,
address: Model.address
}).then((rsp) => {
/** nothing here... */
let notification_ = new Notification_
notification_.id = notification.getId()
notification_.date = date
notification_.sender = notification.getSender()
notification_.recipient = notification.getRecipient()
notification_.text = notification.getMessage()
notification_.type = 0
notification_.mac = Model.getGlobule(contact.domain).config.Mac
// Send notification...
Model.getGlobule(contact.domain).eventHub.publish(contact.id + "@" + contact.domain + "_notification_event", notification_.toString(), false)
}).catch(err => {
ApplicationView.displayMessage(err, 3000);
console.log(err)
})
})
})
}
})
}
let displayParticipants = () => {
let participantsDiv = summary_page.querySelector("#paticipants")
let range = document.createRange()
// set style...
participantsDiv.appendChild(range.createContextualFragment(`
<style>
.infos {
margin: 2px;
padding: 4px;
display: flex;
flex-direction: column;
border-radius: 4px;
align-items: center;
transition: background 0.2s ease,padding 0.8s linear;
background-color: var(--palette-background-paper);
color: var(--palette-text-primary);
}
.infos img{
max-height: 64px;
max-width: 64px;
border-radius: 32px;
}
.infos span{
font-size: 1rem;
}
</style>
`))
participants.forEach(a => {
let uuid = "_" + getUuidByString(a.id + "@" + a.domain)
let html = `
<div id="${uuid}" class="infos">
<img style="width: 32px; height: 32px; display: ${a.profilePicture.length == 0 ? "none" : "block"};" src="${a.profilePicture}"></img>
<iron-icon icon="account-circle" style="width: 32px; height: 32px; --iron-icon-fill-color:var(--palette-action-disabled); display: ${a.profilePicture.length > 0 ? "none" : "block"};"></iron-icon>
<span>${a.name}</span>
</div>
`
participantsDiv.appendChild(range.createContextualFragment(html))
})
// display resources...
displayResources()
}
if (groups.length == 0) {
displayParticipants()
} else {
getMembers(0)
}
})
}
this.appendChild(wizard)
// So he I will connect events...
files.forEach(file => {
let title = null
let video = null
let audio = null
if (file.titles) {
title = file.titles[0]
} else if (file.videos) {
video = file.videos[0]
} else if (file.audios) {
audio = file.audios[0]
}
let uuid = "_" + getUuidByString(file.path)
let infos_btn = this.querySelector(`#${uuid + "_infos_btn"}`)
if (title) {
infos_btn.onclick = () => {
this.showTitleInfo(title)
}
} else if (video) {
infos_btn.onclick = () => {
this.showVideoInfo(video)
}
} else {
infos_btn.style.display = "none"
}
infos_btn.onmouseover = () => {
infos_btn.style.cursor = "pointer"
}
infos_btn.onmouseleave = () => {
infos_btn.style.cursor = "default"
}
let checkbox = this.querySelector(`#${uuid + "_checkbox"}`)
file.selected = true;
checkbox.onclick = () => {
file.selected = checkbox.checked;
console.log(file.path, " is selected ", file.selected)
}
})
// make the wizard modal...
this.modal = document.createElement("div")
this.modal.style.position = "absolute"
this.modal.style.top = "0px"
this.modal.style.bottom = "0px"
this.modal.style.left = "0px"
this.modal.style.right = "0px"
this.modal.style.backgroundColor = "rgba(0,0,0,.45)"
// Close the wizard...
wizard.onclose = () => {
this.close()
}
// Cancel button...
this.shadowRoot.querySelector("paper-icon-button").onclick = () => {
this.close()
}
}
// save permission, it will return map of errors if some permissions can't be set
// for a given file.
setFilesPermissions(permissions_, files, callback) {
let errors = {}
// save permissions.
let saveFilePermissions = (f, permissions, callback, errorCallback) => {
/** todo write the code to save the permission. */
console.log("save permissions: ", permissions)
let rqst = new SetResourcePermissionsRqst
let globule = f.globule
rqst.setPath(f.path)
rqst.setResourcetype("file")
rqst.setPermissions(permissions)
generatePeerToken(globule, token => {
globule.rbacService.setResourcePermissions(rqst, { domain: Model.domain, address: Model.address, application: Model.application, token: token })
.then(() => { console.log("save permission successfully!"); callback(); })
.catch(err => {
errorCallback(err)
})
})
}
let setPermissions = (index) => {
if (index == files.length) {
callback(errors)
return
}
let f = files[index]
let permissions = new Permissions
permissions.setPath(f.path)
permissions.setResourceType("file")
let rqst = new GetResourcePermissionsRqst
rqst.setPath(f.path)
generatePeerToken(f.globule, token => {
f.globule.rbacService.getResourcePermissions(rqst, { domain: Model.domain, address: Model.address, application: Model.application, token: token }).then(
rsp => {
permissions = rsp.getPermissions()
console.log("permission find for file ", f.path, permissions)
// so here I will merge the value for permission_ (taken from the interface)
// and the existing permissions from the backend.
permissions_.allowed.forEach(p => {
// Get existing allowed permission accounts list.
let allowed = permissions.getAllowedList()
// The existing permission with the same name
let p_ = allowed.filter(p__ => p__.getName() == p.getName())[0]
if (p_) {
let accounts_lst = p.getAccountsList()
accounts_lst.forEach(a => {
let accounts_lst_ = p_.getAccountsList()
if (accounts_lst_.filter(a_ => a_ == a).length == 0) {
accounts_lst_.push(a)
}
p_.setAccountsList(accounts_lst_)
})
let groups_lst = p.getGroupsList()
groups_lst.forEach(g => {
let groups_lst_ = p_.getGroupsList()
if (groups_lst_.filter(g_ => g_ == g).length == 0) {
groups_lst_.push(g)
}
p_.setGroupsList(groups_lst_)
})
} else {
// no permission with that name exist so I will simply append the new one...
permissions.addAllowed(p)
}
})
// Now the denied permissions.
permissions_.denied.forEach(p => {
// Get existing allowed permission accounts list.
let denied = permissions.getDeniedList()
// The existing permission with the same name
let p_ = denied.filter(p__ => p__.getName() == p.getName())[0]
if (p_) {
let accounts_lst = p.getAccountsList()
accounts_lst.forEach(a => {
let accounts_lst_ = p_.getAccountsList()
if (accounts_lst_.filter(a_ => a_ == a).length == 0) {
accounts_lst_.push(a)
}
p_.setAccountsList(accounts_lst_)
})
let groups_lst = p.getGroupsList()
groups_lst.forEach(g => {
let groups_lst_ = p_.getGroupsList()
if (groups_lst_.filter(g_ => g_ == g).length == 0) {
groups_lst_.push(g)
}
p_.setGroupsList(groups_lst_)
})
} else {
// no permission with that name exist so I will simply append the new one...
permissions.addDenied(p)
}
})
// next file...
saveFilePermissions(f, permissions, () => {
setPermissions(++index)
}, err => { console.log("---------->", err); errors[f.path] = err; setPermissions(++index) })
}).catch(err => {
let msg = JSON.parse(err.message);
if (msg.ErrorMsg.startsWith("item not found")) {
permissions.setAllowedList(permissions_.allowed)
permissions.setDeniedList(permissions_.denied)
saveFilePermissions(f, permissions, () => {
setPermissions(++index)
}, err => { console.log("---------------> ", err); errors[f.path] = err; setPermissions(++index) })
}
})
})
}
// start setting permissions.
let index = 0;
if (files.length > 0) {
setPermissions(index)
}
}
showVideoInfo(video) {
let uuid = randomUUID()
let html = `
<paper-card id="video-info-box-dialog-${uuid}" style="background: var(--palette-background-default); border-top: 1px solid var(--palette-background-paper); border-left: 1px solid var(--palette-background-paper);">
<globular-informations-manager id="video-info-box"></globular-informations-manager>
</paper-card>
`
let videoInfoBox = document.getElementById("video-info-box")
if (videoInfoBox == undefined) {
let range = document.createRange()
document.body.appendChild(range.createContextualFragment(html))
videoInfoBox = document.getElementById("video-info-box")
let parent = document.getElementById("video-info-box-dialog-" + uuid)
parent.style.position = "fixed"
parent.style.top = "75px"
parent.style.left = "50%"
parent.style.transform = "translate(-50%)"
videoInfoBox.onclose = () => {
parent.parentNode.removeChild(parent)
}
}
videoInfoBox.setVideosInformation([video])
}
showTitleInfo(title) {
let uuid = randomUUID()
let html = `
<paper-card id="video-info-box-dialog-${uuid}" style="background: var(--palette-background-default); border-top: 1px solid var(--palette-background-paper); border-left: 1px solid var(--palette-background-paper);">
<globular-informations-manager id="title-info-box"></globular-informations-manager>
</paper-card>
`
let titleInfoBox = document.getElementById("title-info-box")
if (titleInfoBox == undefined) {
let range = document.createRange()
document.body.appendChild(range.createContextualFragment(html))
titleInfoBox = document.getElementById("title-info-box")
let parent = document.getElementById("video-info-box-dialog-" + uuid)
parent.style.position = "fixed"
parent.style.top = "75px"
parent.style.left = "50%"
parent.style.transform = "translate(-50%)"
titleInfoBox.onclose = () => {
parent.parentNode.removeChild(parent)
}
}
titleInfoBox.setTitlesInformation([title])
}
show() {
document.body.appendChild(this.modal);
document.body.appendChild(this);
}
close() {
document.body.removeChild(this.modal)
document.body.removeChild(this)
}
}
customElements.define('globular-share-resource-wizard', ShareResourceWizard)
/**
* Display suject (user's, group's, organization's, application's) in accordeon panel...
*/
export class GlobularSubjectsView extends HTMLElement {
// attributes.
// Create the applicaiton view.
constructor() {
super()
// Set the shadow dom.
this.attachShadow({ mode: 'open' });
// The event listener...
this.on_accounts_change = null
this.on_groups_change = null
this.on_account_click = null
this.on_group_click = null
this.on_application_click = null
this.on_organization_click = null
// set the account...
this.account = Application.account
// Innitialisation of the layout.
this.shadowRoot.innerHTML = `
<style>
#subjects-div{
display: flex;
flex-direction: column;
margin-right: 25px;
}
.vertical-tabs {
display: flex;
flex-direction: column;
height: 100%;
}
.vertical-tab {