filter enhancements

This commit is contained in:
Gani Georgiev
2023-01-07 22:25:56 +02:00
parent d5775ff657
commit 9b880f5ab4
102 changed files with 3693 additions and 986 deletions
@@ -236,12 +236,23 @@
result.push(key);
if (field.type === "relation" && field.options.collectionId) {
// add relation fields
if (field.type === "relation" && field.options?.collectionId) {
const subKeys = getCollectionFieldKeys(field.options.collectionId, key + ".", level + 1);
if (subKeys.length) {
result = result.concat(subKeys);
}
}
// add ":each" field modifier
if (field.type === "select" && field.options?.maxSelect != 1) {
result.push(key + ":each");
}
// add ":length" field modifier to arrayble fields
if (field.options?.maxSelect != 1 && ["select", "file", "relation"].includes(field.type)) {
result.push(key + ":length");
}
}
return result;
@@ -259,7 +270,6 @@
result.push("@request.method");
result.push("@request.query.");
result.push("@request.data.");
result.push("@request.auth.");
result.push("@request.auth.id");
result.push("@request.auth.collectionId");
result.push("@request.auth.collectionName");
@@ -279,6 +289,27 @@
}
}
// load base collection fields into @request.data.*
const issetExcludeList = ["created", "updated"];
if (baseCollection?.id) {
const keys = getCollectionFieldKeys(baseCollection.name, "@request.data.");
for (const key of keys) {
result.push(key);
// add ":isset" modifier to non-base keys
const parts = key.split(".");
if (
parts.length === 3 &&
// doesn't contain another modifier
parts[2].indexOf(":") === -1 &&
// is not from the exclude list
!issetExcludeList.includes(parts[2])
) {
result.push(key + ":isset");
}
}
}
return result;
}
@@ -9,7 +9,7 @@
</script>
<div class="block m-b-base">
<div class="flex txt-sm m-b-5">
<div class="flex txt-sm txt-hint m-b-5">
<p>
All rules follow the
<a href={import.meta.env.PB_RULES_SYNTAX_DOCS} target="_blank" rel="noopener noreferrer">
@@ -108,6 +108,17 @@
return CommonHelper.slugify(name);
}
function requiredLabel(field) {
switch (field?.type) {
case "bool":
return "Nonfalsey";
case "number":
return "Nonzero";
default:
return "Nonempty";
}
}
onMount(() => {
// auto expand new fields
if (!field.id) {
@@ -150,7 +161,7 @@
<span class="label" class:label-warning={interactive && !field.toDelete}>New</span>
{/if}
{#if field.required}
<span class="label label-success">Nonempty</span>
<span class="label label-success">{requiredLabel(field)}</span>
{/if}
{#if field.unique}
<span class="label label-success">Unique</span>
@@ -270,13 +281,13 @@
<Field class="form-field form-field-toggle m-0" name="requried" let:uniqueId>
<input type="checkbox" id={uniqueId} bind:checked={field.required} />
<label for={uniqueId}>
<span class="txt">Nonempty</span>
<span class="txt">{requiredLabel(field)}</span>
<i
class="ri-information-line link-hint"
use:tooltip={{
text: `Requires the field value to be nonempty\n(aka. not ${CommonHelper.zeroDefaultStr(
text: `Requires the field value to be ${requiredLabel(
field
)}).`,
)}\n(aka. not ${CommonHelper.zeroDefaultStr(field)}).`,
position: "right",
}}
/>
+61 -71
View File
@@ -4,7 +4,6 @@
<script>
import { tick } from "svelte";
import tooltip from "@/actions/tooltip";
import Field from "@/components/base/Field.svelte";
export let collection = null;
@@ -20,6 +19,8 @@
$: isAdminOnly = rule === null;
loadEditorComponent();
async function loadEditorComponent() {
if (ruleInputComponent || isRuleComponentLoading) {
return; // already loaded or in the process
@@ -34,7 +35,16 @@
isRuleComponentLoading = false;
}
loadEditorComponent();
async function unlock() {
rule = tempValue || "";
await tick();
editorRef?.focus();
}
async function lock() {
tempValue = rule;
rule = null;
}
</script>
{#if isRuleComponentLoading}
@@ -42,80 +52,60 @@
<span class="loader" />
</div>
{:else}
<div class="rule-block">
{#if isAdminOnly}
<button
type="button"
class="rule-toggle-btn btn btn-circle btn-outline btn-success"
use:tooltip={{
text: "Unlock and set custom rule",
position: "left",
}}
on:click={async () => {
rule = tempValue || "";
await tick();
editorRef?.focus();
}}
>
<i class="ri-lock-unlock-line" />
</button>
{:else}
<button
type="button"
class="rule-toggle-btn btn btn-circle btn-outline"
use:tooltip={{
text: "Lock and set to Admins only",
position: "left",
}}
on:click={() => {
tempValue = rule;
rule = null;
}}
>
<i class="ri-lock-line" />
</button>
{/if}
<Field
class="form-field rule-field m-0 {required ? 'requied' : ''} {isAdminOnly ? 'disabled' : ''}"
name={formKey}
let:uniqueId
>
<label for={uniqueId}>
<Field
class="form-field rule-field m-0 {required ? 'requied' : ''} {isAdminOnly ? 'disabled' : ''}"
name={formKey}
let:uniqueId
>
<label for={uniqueId}>
<span class="txt">
{label} - {isAdminOnly ? "Admins only" : "Custom rule"}
</label>
</span>
<svelte:component
this={ruleInputComponent}
id={uniqueId}
bind:this={editorRef}
bind:value={rule}
baseCollection={collection}
disabled={isAdminOnly}
/>
{#if isAdminOnly}
<button type="button" class="lock-toggle link-success" on:click={unlock}>
<i class="ri-lock-unlock-line" />
<span class="txt">Set custom rule</span>
</button>
{:else}
<button type="button" class="lock-toggle link-hint" on:click={lock}>
<i class="ri-lock-line" />
<span class="txt">Set Admins only</span>
</button>
{/if}
</label>
<div class="help-block">
<slot {isAdminOnly}>
<p>
{#if isAdminOnly}
Only admins will be able to perform this action (unlock to change)
{:else}
Leave empty to grant everyone access
{/if}
</p>
</slot>
</div>
</Field>
</div>
<svelte:component
this={ruleInputComponent}
id={uniqueId}
bind:this={editorRef}
bind:value={rule}
baseCollection={collection}
disabled={isAdminOnly}
/>
<div class="help-block">
<slot {isAdminOnly}>
<p>
{#if isAdminOnly}
Only admins will be able to perform this action (
<button type="button" class="link-hint" on:click={unlock}>unlock to change</button>
).
{:else}
Leave empty to grant everyone access.
{/if}
</p>
</slot>
</div>
</Field>
{/if}
<style>
.rule-block {
display: flex;
align-items: flex-start;
gap: var(--xsSpacing);
}
.rule-toggle-btn {
margin-top: 15px;
.lock-toggle {
margin-left: auto;
display: inline-flex;
align-items: center;
gap: 5px;
font-size: var(--smFontSize);
}
</style>
@@ -77,7 +77,7 @@
// fetch a paginated records list
const resultList = await pb.collection('${collection?.name}').getList(1, 50, {
filter: 'created >= "2022-01-01 00:00:00" && someFiled1 != someField2',
filter: 'created >= "2022-01-01 00:00:00" && someField1 != someField2',
});
// you can also fetch all records at once via getFullList
@@ -101,7 +101,7 @@
final resultList = await pb.collection('${collection?.name}').getList(
page: 1,
perPage: 50,
filter: 'created >= "2022-01-01 00:00:00" && someFiled1 != someField2',
filter: 'created >= "2022-01-01 00:00:00" && someField1 != someField2',
);
// you can also fetch all records at once via getFullList
@@ -54,7 +54,7 @@
{#if hasErrors}
<i
class="ri-error-warning-fill txt-danger"
transition:scale={{ duration: 150, start: 0.7 }}
transition:scale|local={{ duration: 150, start: 0.7 }}
use:tooltip={{ text: "Has errors", position: "left" }}
/>
{/if}
@@ -71,7 +71,7 @@
{#if hasErrors}
<i
class="ri-error-warning-fill txt-danger"
transition:scale={{ duration: 150, start: 0.7 }}
transition:scale|local={{ duration: 150, start: 0.7 }}
use:tooltip={{ text: "Has errors", position: "left" }}
/>
{/if}
-8
View File
@@ -346,10 +346,6 @@ button {
$thumbActiveColor: var(--baseAlt4Color)
);
}
&:focus,
&.active {
border-color: var(--primaryColor);
}
&[readonly],
&.readonly {
cursor: default;
@@ -359,7 +355,6 @@ button {
&.disabled {
cursor: default;
color: var(--txtDisabledColor);
border-color: var(--baseAlt2Color);
}
&.txt-mono {
line-height: var(--smLineHeight);
@@ -536,9 +531,6 @@ select {
> label {
color: var(--txtDisabledColor);
}
label, %input {
border-color: var(--baseAlt2Color);
}
&.required > label:after {
opacity: 0.5;
}