1
0
Fork 0
mirror of synced 2024-06-15 01:04:51 +12:00

Collection UI updates

This commit is contained in:
Jake Barnby 2022-08-10 22:23:53 +12:00
parent 25e893f712
commit 531247deb4
6 changed files with 107 additions and 33 deletions

View file

@ -486,8 +486,8 @@ $logs = $this->getParam('logs', null);
<div class="box margin-bottom-small">
<div class="margin-start-negative-small margin-end-negative-small margin-top-negative-small margin-bottom-negative-small">
<div class="chart background-image-no border-no margin-bottom-no">
<input
type="hidden"
<input
type="hidden"
data-ls-bind="{{usage}}"
data-forms-chart="Created=documentsCreate,Read=documentsRead,Updated=documentsUpdate,Deleted=documentsDelete"
data-show-y-axis="true"
@ -540,34 +540,88 @@ $logs = $this->getParam('logs', null);
<label class="margin-bottom-small">Permissions</label>
<p class="text-fade text-size-small">Choose the permissions model for this collection.</p>
<p class="text-fade text-size-small">Configure the permissions matrix for this collection.</p>
<hr class="margin-top-small" />
<div class="row">
<div class="col span-1"><input name="permission" value="collection" type="radio" class="margin-top-tiny" data-ls-bind="{{project-collection.permission}}" /></div>
<div class="col span-11">
<b>Collection Level</b>
<p class="text-fade margin-top-tiny">With Collection Level permissions, you assign permissions only once in the collection.</p>
<p class="text-fade margin-top-tiny">In this permission level, permissions assigned to collection takes the precedence and documents permissions are ignored.</p>
<div data-ls-if="{{project-collection.permission}} === 'collection'">
<label for="collection-read">Read Access <span class="text-size-small">(<a data-ls-attrs="href={{env.HOME}}/docs/permissions" target="_blank" rel="noopener">Learn more</a>)</span></label>
<input type="hidden" id="collection-read" name="read" data-forms-tags data-cast-to="json" data-ls-bind="{{project-collection.$read}}" placeholder="User ID, Team ID or Role" />
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">Add 'any' for wildcard access</div>
<label for="collection-write">Write Access <span class="text-size-small">(<a data-ls-attrs="href={{env.HOME}}/docs/permissions" target="_blank" rel="noopener">Learn more</a>)</label>
<input type="hidden" id="collection-write" name="write" data-forms-tags data-cast-to="json" data-ls-bind="{{project-collection.$write}}" placeholder="User ID, Team ID or Role" />
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">Add 'any' for wildcard access</div>
</div>
</div>
<div
class="permissions-matrix margin-bottom-large"
data-ls-attrs="x-init=console.log({{project-collection}})"
x-data="{permissions: []}">
<table>
<thead>
<tr>
<th style="width: 100px;">Role</th>
<th style="text-align: center; width: 30px">Read</th>
<th style="text-align: center; width: 30px">Create</th>
<th style="text-align: center; width: 30px">Update</th>
<th style="text-align: center; width: 30px">Delete</th>
<th style="width: 10px"></th>
</tr>
</thead>
<tbody>
<template x-for="permission in permissions">
<tr>
<td>
<label></label>
</td>
<td>
<input type="checkbox" name="read" id="read" value="1"/>
</td>
<td>
<input type="checkbox" name="create" id="create" value="1"/>
</td>
<td>
<input type="checkbox" name="update" id="update" value="1"/>
</td>
<td>
<input type="checkbox" name="delete" id="delete" value="1"/>
</td>
<td>
<button type="button" @click="deleteRow(index)"></button>
</td>
</tr>
</template>
<tr>
<td style="vertical-align: middle">
<input type="text" name="permission" id="permission" />
</td>
<td style="text-align: center">
<input type="checkbox" name="read" id="read" value="1"/>
</td>
<td style="text-align: center">
<input type="checkbox" name="create" id="create" value="1"/>
</td>
<td style="text-align: center">
<input type="checkbox" name="update" id="update" value="1"/>
</td>
<td style="text-align: center">
<input type="checkbox" name="delete" id="delete" value="1"/>
</td>
<td>
<button type="button" class="icon-trash"></button>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>
<button type="button" class="btn btn-primary" @click="addRow()">Add</button>
</td>
</tr>
</tfoot>
</table>
</div>
<hr class="margin-top-no" />
<label class="margin-bottom-small">Document Security</label>
<div class="row">
<div class="col span-1"><input name="permission" value="document" type="radio" class="margin-top-no" data-ls-bind="{{project-collection.permission}}" /></div>
<div class="col span-1"><input name="documentSecurity" value="false" type="checkbox" class="margin-top-no" data-ls-bind="{{project-collection.documentSecurity}}" /></div>
<div class="col span-11">
<b>Document Level</b>
<p class="text-fade margin-top-tiny">With Document Level permissions, you have granular access control over every document. Users will only be able to access documents for which they have explicit permissions.</p>
<p class="text-fade margin-top-tiny">In this permission level, document permissions take precedence and collection permissions are ignored.</p>
<b>Enabled</b>
<p class="text-fade margin-top-tiny">With Document Security enabled, users will be able to access documents for which they have <i>either</i> Document or Collection permissions.</p>
</div>
</div>
@ -584,9 +638,9 @@ $logs = $this->getParam('logs', null);
</div>
<ul class="margin-bottom-large text-fade text-size-small">
<li class="margin-bottom-small"><i class="icon-angle-circled-right margin-start-tiny margin-end-tiny"></i>
<button data-ls-ui-trigger="open-json"
class="link text-size-small"
<li class="margin-bottom-small"><i class="icon-angle-circled-right margin-start-tiny margin-end-tiny"></i>
<button data-ls-ui-trigger="open-json"
class="link text-size-small"
data-analytics
data-analytics-event="click"
data-analytics-category="console"

View file

@ -131,9 +131,8 @@
<label for="collection-name">Name</label>
<input type="text" class="full-width" id="collection-name" name="name" required autocomplete="off" maxlength="128" />
<input type="hidden" id="collection-permission" name="permission" required value="collection" />
<input type="hidden" id="collection-read" name="read" required data-cast-to="json" value="<?php echo htmlentities(json_encode([])); ?>" />
<input type="hidden" id="collection-write" name="write" required data-cast-to="json" value="<?php echo htmlentities(json_encode([])); ?>" />
<input type="hidden" id="collection-permissions" name="permissions" required data-cast-to="json" value="<?php echo htmlentities(json_encode([])); ?>" />
<input type="hidden" id="collection-documentSecurity" name="documentSecurity" required data-cast-to="boolean" value="false" />
<hr />

View file

@ -4048,7 +4048,7 @@ return url;}}else{if(typeof value!=="undefined"&&value!==null){var separator=url
return url;}else{return url;}}};keys=keys.split(",").map(element=>element.trim());return function(serviceForm,router,window){let url=window.location.href;keys.map(node=>{node=node.split("=");let key=node[0]||"";let name=node[1]||key;let value=getValue(key,"param",serviceForm);url=updateQueryString(name,value?value:null,url);});if(url!==window.location.href){window.history.pushState({},"",url);router.reset();}};},trigger:function(events){return function(document){events=events.trim().split(",");for(let i=0;i<events.length;i++){if(""===events[i]){continue;}
document.dispatchEvent(new CustomEvent(events[i]));}};},setId:function name(params){},default:function(){let collection=container.get('project-collection');let document=container.get('project-document');if(collection&&document&&collection.$id===document.$id){for(const[key,value]of Object.entries(document)){delete document[key];}
if(collection.rules){for(let index=0;index<collection.rules.length;index++){const element=collection.rules[index];switch(element.type){case'text':case'email':case'url':case'ip':document[element.key]=element.default||'';break;case'numeric':document[element.key]=element.default||'0';break;case'boolean':document[element.key]=element.default||false;break;case'document':document[element.key]=element.default||{'$id':'','$collection':'','$permissions':{}};break;default:document[element.key]=null;break;}
if(element.array){document[element.key]=[];}}}}}};let getParams=function getParams(func){const REGEX_COMMENTS=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;const REGEX_FUNCTION_PARAMS=/(?:\s*(?:function\s*[^(]*)?\s*)((?:[^'"]|(?:(?:(['"])(?:(?:.*?[^\\]\2)|\2))))*?)\s*(?=(?:=>)|{)/m;const REGEX_PARAMETERS_VALUES=/\s*([\w\\$]+)\s*(?:=\s*((?:(?:(['"])(?:\3|(?:.*?[^\\]\3)))((\s*\+\s*)(?:(?:(['"])(?:\6|(?:.*?[^\\]\6)))|(?:[\w$]*)))*)|.*?))?\s*(?:,|$)/gm;let functionAsString=func.toString();let params=[];let match;console.log(functionAsString);let indexOfArguments=functionAsString.indexOf('(');if(indexOfArguments!==-1){functionAsString=functionAsString.slice(indexOfArguments,-1);}
if(element.array){document[element.key]=[];}}}}}};let getParams=function getParams(func){const REGEX_COMMENTS=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;const REGEX_FUNCTION_PARAMS=/(?:\s*(?:function\s*[^(]*)?\s*)((?:[^'"]|(?:(?:(['"])(?:(?:.*?[^\\]\2)|\2))))*?)\s*(?=(?:=>)|{)/m;const REGEX_PARAMETERS_VALUES=/\s*([\w\\$]+)\s*(?:=\s*((?:(?:(['"])(?:\3|(?:.*?[^\\]\3)))((\s*\+\s*)(?:(?:(['"])(?:\6|(?:.*?[^\\]\6)))|(?:[\w$]*)))*)|.*?))?\s*(?:,|$)/gm;let functionAsString=func.toString();let params=[];let match;let indexOfArguments=functionAsString.indexOf('(');if(indexOfArguments!==-1){functionAsString=functionAsString.slice(indexOfArguments,-1);}
functionAsString=functionAsString.replaceAll('={}',"");functionAsString=functionAsString.replaceAll('=[]',"");functionAsString=functionAsString.replace(REGEX_COMMENTS,"");functionAsString=functionAsString.match(REGEX_FUNCTION_PARAMS)[1];if(functionAsString.charAt(0)==="("){functionAsString=functionAsString.slice(1,-1);}
while((match=REGEX_PARAMETERS_VALUES.exec(functionAsString))){params.push(match[1]);}
return params;};let getValue=function(key,prefix,data){let result=null;if(!key){return null;}
@ -4063,7 +4063,7 @@ running=true;element.style.backgroud='red';if(confirm){if(window.confirm(confirm
if(loading){loaderId=alerts.add({text:loading,class:""},0);}
let method=container.path(scope+"."+parsedAction);if(!method){throw new Error('Method "'+scope+"."+parsedAction+'" not found');}
let formData="FORM"===element.tagName?form.toJson(element):{};let result=resolve(method,"param",formData);if(!result){return;}
if(Promise.resolve(result)!==result){result=new Promise((resolve,reject)=>{resolve(result);});}
if(Promise.resolve(result)!=result){result=new Promise((resolve,reject)=>{resolve(result);});}
result.then(function(data){if(loaderId!==null){alerts.remove(loaderId);}
if(!element){return;}
running=false;element.style.backgroud='transparent';element.classList.add("load-service-end");if(service){container.set(service.replace(".","-"),data,true,true);}

View file

@ -713,7 +713,7 @@ return url;}}else{if(typeof value!=="undefined"&&value!==null){var separator=url
return url;}else{return url;}}};keys=keys.split(",").map(element=>element.trim());return function(serviceForm,router,window){let url=window.location.href;keys.map(node=>{node=node.split("=");let key=node[0]||"";let name=node[1]||key;let value=getValue(key,"param",serviceForm);url=updateQueryString(name,value?value:null,url);});if(url!==window.location.href){window.history.pushState({},"",url);router.reset();}};},trigger:function(events){return function(document){events=events.trim().split(",");for(let i=0;i<events.length;i++){if(""===events[i]){continue;}
document.dispatchEvent(new CustomEvent(events[i]));}};},setId:function name(params){},default:function(){let collection=container.get('project-collection');let document=container.get('project-document');if(collection&&document&&collection.$id===document.$id){for(const[key,value]of Object.entries(document)){delete document[key];}
if(collection.rules){for(let index=0;index<collection.rules.length;index++){const element=collection.rules[index];switch(element.type){case'text':case'email':case'url':case'ip':document[element.key]=element.default||'';break;case'numeric':document[element.key]=element.default||'0';break;case'boolean':document[element.key]=element.default||false;break;case'document':document[element.key]=element.default||{'$id':'','$collection':'','$permissions':{}};break;default:document[element.key]=null;break;}
if(element.array){document[element.key]=[];}}}}}};let getParams=function getParams(func){const REGEX_COMMENTS=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;const REGEX_FUNCTION_PARAMS=/(?:\s*(?:function\s*[^(]*)?\s*)((?:[^'"]|(?:(?:(['"])(?:(?:.*?[^\\]\2)|\2))))*?)\s*(?=(?:=>)|{)/m;const REGEX_PARAMETERS_VALUES=/\s*([\w\\$]+)\s*(?:=\s*((?:(?:(['"])(?:\3|(?:.*?[^\\]\3)))((\s*\+\s*)(?:(?:(['"])(?:\6|(?:.*?[^\\]\6)))|(?:[\w$]*)))*)|.*?))?\s*(?:,|$)/gm;let functionAsString=func.toString();let params=[];let match;console.log(functionAsString);let indexOfArguments=functionAsString.indexOf('(');if(indexOfArguments!==-1){functionAsString=functionAsString.slice(indexOfArguments,-1);}
if(element.array){document[element.key]=[];}}}}}};let getParams=function getParams(func){const REGEX_COMMENTS=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;const REGEX_FUNCTION_PARAMS=/(?:\s*(?:function\s*[^(]*)?\s*)((?:[^'"]|(?:(?:(['"])(?:(?:.*?[^\\]\2)|\2))))*?)\s*(?=(?:=>)|{)/m;const REGEX_PARAMETERS_VALUES=/\s*([\w\\$]+)\s*(?:=\s*((?:(?:(['"])(?:\3|(?:.*?[^\\]\3)))((\s*\+\s*)(?:(?:(['"])(?:\6|(?:.*?[^\\]\6)))|(?:[\w$]*)))*)|.*?))?\s*(?:,|$)/gm;let functionAsString=func.toString();let params=[];let match;let indexOfArguments=functionAsString.indexOf('(');if(indexOfArguments!==-1){functionAsString=functionAsString.slice(indexOfArguments,-1);}
functionAsString=functionAsString.replaceAll('={}',"");functionAsString=functionAsString.replaceAll('=[]',"");functionAsString=functionAsString.replace(REGEX_COMMENTS,"");functionAsString=functionAsString.match(REGEX_FUNCTION_PARAMS)[1];if(functionAsString.charAt(0)==="("){functionAsString=functionAsString.slice(1,-1);}
while((match=REGEX_PARAMETERS_VALUES.exec(functionAsString))){params.push(match[1]);}
return params;};let getValue=function(key,prefix,data){let result=null;if(!key){return null;}
@ -728,7 +728,7 @@ running=true;element.style.backgroud='red';if(confirm){if(window.confirm(confirm
if(loading){loaderId=alerts.add({text:loading,class:""},0);}
let method=container.path(scope+"."+parsedAction);if(!method){throw new Error('Method "'+scope+"."+parsedAction+'" not found');}
let formData="FORM"===element.tagName?form.toJson(element):{};let result=resolve(method,"param",formData);if(!result){return;}
if(Promise.resolve(result)!==result){result=new Promise((resolve,reject)=>{resolve(result);});}
if(Promise.resolve(result)!=result){result=new Promise((resolve,reject)=>{resolve(result);});}
result.then(function(data){if(loaderId!==null){alerts.remove(loaderId);}
if(!element){return;}
running=false;element.style.backgroud='transparent';element.classList.add("load-service-end");if(service){container.set(service.replace(".","-"),data,true,true);}

View file

@ -0,0 +1,16 @@
(function(window){
document.addEventListener('alpine:init', () => {
Alpine.store('permissions', {
_permissions: [],
permissions() {
return (this._permissions ?? []);
},
addRow() {
},
deleteRow(index) {
}
});
});
})(window);

View file

@ -0,0 +1,5 @@
.permissions-matrix {
tr {
vertical-align: center;
}
}