removed js sdk dto helpers

This commit is contained in:
Gani Georgiev
2023-08-14 21:20:49 +03:00
parent cbf1215bb1
commit 5960dc5f2d
94 changed files with 1226 additions and 1213 deletions
@@ -1,7 +1,6 @@
<script>
import { createEventDispatcher } from "svelte";
import { slide } from "svelte/transition";
import { Admin } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import ApiClient from "@/utils/ApiClient";
import tooltip from "@/actions/tooltip";
@@ -16,7 +15,7 @@
const formId = "admin_" + CommonHelper.randomString(5);
let panel;
let admin = new Admin();
let admin = {};
let isSaving = false;
let confirmClose = false; // prevent close recursion
let avatar = 0;
@@ -25,11 +24,10 @@
let passwordConfirm = "";
let changePasswordToggle = false;
$: isNew = !!admin?.id;
$: hasChanges =
(admin.$isNew && email != "") ||
changePasswordToggle ||
email !== admin.email ||
avatar !== admin.avatar;
(isNew && email != "") || changePasswordToggle || email !== admin.email || avatar !== admin.avatar;
export function show(model) {
load(model);
@@ -44,7 +42,7 @@
}
function load(model) {
admin = model?.$clone ? model.$clone() : new Admin();
admin = structuredClone(model || {});
reset(); // reset form
}
@@ -65,13 +63,13 @@
isSaving = true;
const data = { email, avatar };
if (admin.$isNew || changePasswordToggle) {
if (isNew || changePasswordToggle) {
data["password"] = password;
data["passwordConfirm"] = passwordConfirm;
}
let request;
if (admin.$isNew) {
if (isNew) {
request = ApiClient.admins.create(data);
} else {
request = ApiClient.admins.update(admin.id, data);
@@ -81,7 +79,7 @@
.then(async (result) => {
confirmClose = false;
hide();
addSuccessToast(admin.$isNew ? "Successfully created admin." : "Successfully updated admin.");
addSuccessToast(isNew ? "Successfully created admin." : "Successfully updated admin.");
if (ApiClient.authStore.model?.id === result.id) {
ApiClient.authStore.save(ApiClient.authStore.token, result);
@@ -137,12 +135,12 @@
>
<svelte:fragment slot="header">
<h4>
{admin.$isNew ? "New admin" : "Edit admin"}
{isNew ? "New admin" : "Edit admin"}
</h4>
</svelte:fragment>
<form id={formId} class="grid" autocomplete="off" on:submit|preventDefault={save}>
{#if !admin.$isNew}
{#if !isNew}
<Field class="form-field readonly" name="id" let:uniqueId>
<label for={uniqueId}>
<i class={CommonHelper.getFieldTypeIcon("primary")} />
@@ -187,14 +185,14 @@
<input type="email" autocomplete="off" id={uniqueId} required bind:value={email} />
</Field>
{#if !admin.$isNew}
{#if !isNew}
<Field class="form-field form-field-toggle" let:uniqueId>
<input type="checkbox" id={uniqueId} bind:checked={changePasswordToggle} />
<label for={uniqueId}>Change password</label>
</Field>
{/if}
{#if admin.$isNew || changePasswordToggle}
{#if isNew || changePasswordToggle}
<div class="col-12">
<div class="grid" transition:slide|local={{ duration: 150 }}>
<div class="col-sm-6">
@@ -233,7 +231,7 @@
</form>
<svelte:fragment slot="footer">
{#if !admin.$isNew}
{#if !isNew}
<button type="button" aria-label="More" class="btn btn-sm btn-circle btn-transparent">
<!-- empty span for alignment -->
<span />
@@ -258,7 +256,7 @@
class:btn-loading={isSaving}
disabled={!hasChanges || isSaving}
>
<span class="txt">{admin.$isNew ? "Create" : "Save changes"}</span>
<span class="txt">{isNew ? "Create" : "Save changes"}</span>
</button>
</svelte:fragment>
</OverlayPanel>
@@ -268,7 +268,7 @@
result.push("@request.auth.updated");
// load auth collection fields
const authCollections = cachedCollections.filter((collection) => collection.$isAuth);
const authCollections = cachedCollections.filter((collection) => collection.type === "auth");
for (const collection of authCollections) {
const authKeys = getCollectionFieldKeys(collection.id, "@request.auth.");
for (const k of authKeys) {
+1 -2
View File
@@ -1,7 +1,6 @@
<script>
import { createEventDispatcher, onMount } from "svelte";
import { fly } from "svelte/transition";
import { Collection } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
const dispatch = createEventDispatcher();
@@ -11,7 +10,7 @@
export let placeholder = 'Search term or filter like created > "2022-01-01"...';
// autocomplete filter component fields
export let autocompleteCollection = new Collection();
export let autocompleteCollection = CommonHelper.initCollection();
export let extraAutocompleteKeys = [];
let filterComponent;
@@ -1,6 +1,5 @@
<script>
import { scale, slide } from "svelte/transition";
import { Collection } from "pocketbase";
import { errors } from "@/stores/errors";
import tooltip from "@/actions/tooltip";
import Field from "@/components/base/Field.svelte";
@@ -8,9 +7,9 @@
import MultipleValueInput from "@/components/base/MultipleValueInput.svelte";
import Accordion from "@/components/base/Accordion.svelte";
export let collection = new Collection();
export let collection;
$: if (collection.$isAuth && CommonHelper.isEmpty(collection.options)) {
$: if (collection.type === "auth" && CommonHelper.isEmpty(collection.options)) {
collection.options = {
allowEmailAuth: true,
allowUsernameAuth: true,
@@ -1,5 +1,4 @@
<script>
import { Collection } from "pocketbase";
import OverlayPanel from "@/components/base/OverlayPanel.svelte";
const baseTabs = {
@@ -81,19 +80,19 @@
};
let docsPanel;
let collection = new Collection();
let collection = {};
let activeTab;
let tabs = [];
$: if (collection.$isAuth) {
$: if (collection.type === "auth") {
tabs = Object.assign({}, baseTabs, authTabs);
if (!collection?.options.allowUsernameAuth && !collection?.options.allowEmailAuth) {
if (!collection.options.allowUsernameAuth && !collection.options.allowEmailAuth) {
delete tabs["auth-with-password"];
}
if (!collection?.options.allowOAuth2Auth) {
if (!collection.options.allowOAuth2Auth) {
delete tabs["auth-with-oauth2"];
}
} else if (collection.$isView) {
} else if (collection.type === "view") {
tabs = Object.assign({}, baseTabs);
delete tabs.create;
delete tabs.update;
@@ -127,7 +126,7 @@
<OverlayPanel bind:this={docsPanel} on:hide on:show class="docs-panel">
<div class="docs-content-wrapper">
<aside class="docs-sidebar" class:compact={collection?.$isAuth}>
<aside class="docs-sidebar" class:compact={collection?.type === "auth"}>
<nav class="sidebar-content">
{#each Object.entries(tabs) as [key, tab], i (key)}
<!-- add a separator before the first auth tab -->
@@ -1,5 +1,4 @@
<script>
import { Collection, SchemaField } from "pocketbase";
import { setErrors } from "@/stores/errors";
import CommonHelper from "@/utils/CommonHelper";
import IndexesList from "@/components/collections/IndexesList.svelte";
@@ -17,7 +16,7 @@
import SchemaFieldRelation from "@/components/collections/schema/SchemaFieldRelation.svelte";
import Draggable from "@/components/base/Draggable.svelte";
export let collection = new Collection();
export let collection;
const fieldComponents = {
text: SchemaFieldText,
@@ -34,7 +33,6 @@
};
$: if (typeof collection.schema === "undefined") {
collection = collection || new Collection();
collection.schema = [];
}
@@ -48,7 +46,7 @@
}
function newField(fieldType = "text") {
const field = new SchemaField({
const field = CommonHelper.initSchemaField({
name: getUniqueFieldName(),
type: fieldType,
});
@@ -70,7 +68,7 @@
}
function hasFieldWithName(name) {
return !!collection.schema.find((field) => field.name === name);
return !!collection?.schema?.find((field) => field.name === name);
}
function getSchemaFieldIndex(field) {
@@ -95,7 +93,7 @@
<code class="txt-sm">id</code> ,
<code class="txt-sm">created</code> ,
<code class="txt-sm">updated</code>
{#if collection.$isAuth}
{#if collection.type === "auth"}
,
<code class="txt-sm">username</code> ,
<code class="txt-sm">email</code> ,
@@ -1,11 +1,10 @@
<script>
import { onMount } from "svelte";
import { Collection } from "pocketbase";
import { errors, removeError } from "@/stores/errors";
import CommonHelper from "@/utils/CommonHelper";
import Field from "@/components/base/Field.svelte";
export let collection = new Collection();
export let collection;
let codeEditorComponent;
let isCodeEditorComponentLoading = false;
@@ -1,11 +1,10 @@
<script>
import { slide } from "svelte/transition";
import { Collection } from "pocketbase";
import tooltip from "@/actions/tooltip";
import CommonHelper from "@/utils/CommonHelper";
import RuleField from "@/components/collections/RuleField.svelte";
export let collection = new Collection();
export let collection;
$: fields = CommonHelper.getAllCollectionIdentifiers(collection);
@@ -80,7 +79,7 @@
<RuleField label="View rule" formKey="viewRule" {collection} bind:rule={collection.viewRule} />
{#if !collection?.$isView}
{#if collection?.type !== "view"}
<RuleField label="Create rule" formKey="createRule" {collection} bind:rule={collection.createRule}>
<svelte:fragment slot="afterLabel" let:isAdminOnly>
{#if !isAdminOnly}
@@ -100,7 +99,7 @@
<RuleField label="Delete rule" formKey="deleteRule" {collection} bind:rule={collection.deleteRule} />
{/if}
{#if collection?.$isAuth}
{#if collection?.type === "auth"}
<RuleField
label="Manage rule"
formKey="options.manageRule"
@@ -10,6 +10,8 @@
$: isCollectionRenamed = oldCollection?.name != newCollection?.name;
$: isNewCollectionView = newCollection?.type === "view";
$: renamedFields =
newCollection?.schema?.filter(
(field) => field.id && !field.toDelete && field.originalName != field.name
@@ -26,7 +28,7 @@
return old.options?.maxSelect != 1 && field.options?.maxSelect == 1;
}) || [];
$: showChanges = !newCollection?.$isView || isCollectionRenamed;
$: showChanges = !isNewCollectionView || isCollectionRenamed;
export async function show(original, changed) {
oldCollection = original;
@@ -91,7 +93,7 @@
</li>
{/if}
{#if !newCollection?.$isView}
{#if !isNewCollectionView}
{#each multipleToSingleFields as field}
<li>
Multiple to single value conversion of field
@@ -1,7 +1,6 @@
<script>
import { createEventDispatcher, tick } from "svelte";
import { scale } from "svelte/transition";
import { Collection } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import ApiClient from "@/utils/ApiClient";
import { errors, setErrors, removeError } from "@/stores/errors";
@@ -36,13 +35,17 @@
let collectionPanel;
let confirmChangesPanel;
let original = null;
let collection = new Collection();
let collection = CommonHelper.initCollection();
let isSaving = false;
let confirmClose = false; // prevent close recursion
let activeTab = TAB_SCHEMA;
let initialFormHash = calculateFormHash(collection);
let schemaTabError = "";
$: isAuth = collection.type === TYPE_AUTH;
$: isView = collection.type === TYPE_VIEW;
$: if ($errors.schema || $errors.options?.query) {
// extract the direct schema field error, otherwise - return a generic message
schemaTabError = CommonHelper.getNestedVal($errors, "schema.message") || "Has errors";
@@ -50,18 +53,18 @@
schemaTabError = "";
}
$: isSystemUpdate = !collection.$isNew && collection.system;
$: isSystemUpdate = !!collection.id && collection.system;
$: hasChanges = initialFormHash != calculateFormHash(collection);
$: canSave = collection.$isNew || hasChanges;
$: canSave = !collection.id || hasChanges;
$: if (activeTab === TAB_OPTIONS && collection.type !== TYPE_AUTH) {
$: if (activeTab === TAB_OPTIONS && collection.type !== "auth") {
// reset selected tab
changeTab(TAB_SCHEMA);
}
$: if (collection.type === TYPE_VIEW) {
$: if (collection.type === "view") {
// reset non-view fields
collection.createRule = null;
collection.updateRule = null;
@@ -70,7 +73,7 @@
}
// update indexes on collection rename
$: if (collection?.name && original?.name != collection?.name) {
$: if (collection.name && original?.name != collection.name && collection.indexes.length > 0) {
collection.indexes = collection.indexes?.map((idx) =>
CommonHelper.replaceIndexTableName(idx, collection.name)
);
@@ -99,10 +102,10 @@
if (typeof model !== "undefined") {
original = model;
collection = model.$clone();
collection = structuredClone(model);
} else {
original = null;
collection = new Collection();
collection = CommonHelper.initCollection();
}
// normalize
@@ -115,7 +118,7 @@
}
function saveConfirm() {
if (collection.$isNew) {
if (!collection.id) {
save();
} else {
confirmChangesPanel?.show(original, collection);
@@ -132,7 +135,7 @@
const data = exportFormData();
let request;
if (collection.$isNew) {
if (!collection.id) {
request = ApiClient.collections.create(data);
} else {
request = ApiClient.collections.update(collection.id, data);
@@ -148,13 +151,11 @@
hide();
addSuccessToast(
collection.$isNew
? "Successfully created collection."
: "Successfully updated collection."
!collection.id ? "Successfully created collection." : "Successfully updated collection."
);
dispatch("save", {
isNew: collection.$isNew,
isNew: !collection.id,
collection: result,
});
})
@@ -167,7 +168,7 @@
}
function exportFormData() {
const data = collection.$export();
const data = Object.assign({}, collection);
data.schema = data.schema.slice(0);
// remove deleted fields
@@ -186,12 +187,12 @@
return; // nothing to delete
}
confirm(`Do you really want to delete collection "${original?.name}" and all its records?`, () => {
confirm(`Do you really want to delete collection "${original.name}" and all its records?`, () => {
return ApiClient.collections
.delete(original?.id)
.delete(original.id)
.then(() => {
hide();
addSuccessToast(`Successfully deleted collection "${original?.name}".`);
addSuccessToast(`Successfully deleted collection "${original.name}".`);
dispatch("delete", original);
removeCollection(original);
})
@@ -223,7 +224,7 @@
}
async function duplicate() {
const clone = original?.$clone();
const clone = original ? structuredClone(original) : null;
if (clone) {
clone.id = "";
@@ -277,10 +278,10 @@
>
<svelte:fragment slot="header">
<h4 class="upsert-panel-title">
{collection.$isNew ? "New collection" : "Edit collection"}
{!collection.id ? "New collection" : "Edit collection"}
</h4>
{#if !collection.$isNew && !collection.system}
{#if !!collection.id && !collection.system}
<div class="flex-fill" />
<button type="button" aria-label="More" class="btn btn-sm btn-circle btn-transparent flex-gap-0">
<i class="ri-more-line" />
@@ -321,8 +322,8 @@
required
disabled={isSystemUpdate}
spellcheck="false"
autofocus={collection.$isNew}
placeholder={collection.$isAuth ? `eg. "users"` : `eg. "posts"`}
autofocus={!collection.id}
placeholder={isAuth ? `eg. "users"` : `eg. "posts"`}
value={collection.name}
on:input={(e) => {
collection.name = CommonHelper.slugify(e.target.value);
@@ -333,15 +334,13 @@
<div class="form-field-addon">
<button
type="button"
class="btn btn-sm p-r-10 p-l-10 {collection.$isNew
? 'btn-outline'
: 'btn-transparent'}"
disabled={!collection.$isNew}
class="btn btn-sm p-r-10 p-l-10 {!collection.id ? 'btn-outline' : 'btn-transparent'}"
disabled={!!collection.id}
>
<!-- empty span for alignment -->
<span />
<span class="txt">Type: {collectionTypes[collection.type] || "N/A"}</span>
{#if collection.$isNew}
{#if !collection.id}
<i class="ri-arrow-down-s-fill" />
<Toggler class="dropdown dropdown-right dropdown-nowrap m-t-5">
{#each Object.entries(collectionTypes) as [type, label]}
@@ -375,7 +374,7 @@
class:active={activeTab === TAB_SCHEMA}
on:click={() => changeTab(TAB_SCHEMA)}
>
<span class="txt">{collection?.$isView ? "Query" : "Fields"}</span>
<span class="txt">{isView ? "Query" : "Fields"}</span>
{#if !CommonHelper.isEmpty(schemaTabError)}
<i
class="ri-error-warning-fill txt-danger"
@@ -401,7 +400,7 @@
{/if}
</button>
{#if collection.$isAuth}
{#if isAuth}
<button
type="button"
class="tab-item"
@@ -424,7 +423,7 @@
<div class="tabs-content">
<!-- avoid rerendering the fields tab -->
<div class="tab-item" class:active={activeTab === TAB_SCHEMA}>
{#if collection.$isView}
{#if isView}
<CollectionQueryTab bind:collection />
{:else}
<CollectionFieldsTab bind:collection />
@@ -437,7 +436,7 @@
</div>
{/if}
{#if collection.$isAuth}
{#if isAuth}
<div class="tab-item" class:active={activeTab === TAB_OPTIONS}>
<CollectionAuthOptionsTab bind:collection />
</div>
@@ -455,7 +454,7 @@
disabled={!canSave || isSaving}
on:click={() => saveConfirm()}
>
<span class="txt">{collection.$isNew ? "Create" : "Save changes"}</span>
<span class="txt">{!collection.id ? "Create" : "Save changes"}</span>
</button>
</svelte:fragment>
</OverlayPanel>
@@ -1,9 +1,8 @@
<script>
import { Collection } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
export let collectionA = new Collection();
export let collectionB = new Collection();
export let collectionA = CommonHelper.initCollection();
export let collectionB = CommonHelper.initCollection();
export let deleteMissing = false;
let schemaA = [];
let schemaB = [];
@@ -39,7 +38,7 @@
$: hasAnyChange = CommonHelper.hasCollectionChanges(collectionA, collectionB, deleteMissing);
const mainModelProps = Object.keys(new Collection().$export()).filter(
const mainModelProps = Object.keys(CommonHelper.initCollection()).filter(
(key) => !["schema", "created", "updated"].includes(key)
);
@@ -1,12 +1,11 @@
<script>
import { Collection } from "pocketbase";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import CodeBlock from "@/components/base/CodeBlock.svelte";
import SdkTabs from "@/components/collections/docs/SdkTabs.svelte";
import FieldsQueryParam from "@/components/collections/docs/FieldsQueryParam.svelte";
export let collection = new Collection();
export let collection;
let responseTab = 200;
let responses = [];
@@ -1,12 +1,11 @@
<script>
import { Collection } from "pocketbase";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import CodeBlock from "@/components/base/CodeBlock.svelte";
import SdkTabs from "@/components/collections/docs/SdkTabs.svelte";
import FieldsQueryParam from "@/components/collections/docs/FieldsQueryParam.svelte";
export let collection = new Collection();
export let collection;
let responseTab = 200;
let responses = [];
@@ -1,12 +1,11 @@
<script>
import { Collection } from "pocketbase";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import CodeBlock from "@/components/base/CodeBlock.svelte";
import SdkTabs from "@/components/collections/docs/SdkTabs.svelte";
import FieldsQueryParam from "@/components/collections/docs/FieldsQueryParam.svelte";
export let collection = new Collection();
export let collection;
let responseTab = 200;
let responses = [];
@@ -1,12 +1,11 @@
<script>
import { Collection } from "pocketbase";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import CodeBlock from "@/components/base/CodeBlock.svelte";
import SdkTabs from "@/components/collections/docs/SdkTabs.svelte";
import FieldsQueryParam from "@/components/collections/docs/FieldsQueryParam.svelte";
export let collection = new Collection();
export let collection;
let responseTab = 200;
let responses = [];
@@ -1,11 +1,10 @@
<script>
import { Collection } from "pocketbase";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import CodeBlock from "@/components/base/CodeBlock.svelte";
import SdkTabs from "@/components/collections/docs/SdkTabs.svelte";
export let collection = new Collection();
export let collection;
let responseTab = 204;
let responses = [];
@@ -1,11 +1,10 @@
<script>
import { Collection } from "pocketbase";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import CodeBlock from "@/components/base/CodeBlock.svelte";
import SdkTabs from "@/components/collections/docs/SdkTabs.svelte";
export let collection = new Collection();
export let collection;
let responseTab = 204;
let responses = [];
@@ -1,11 +1,10 @@
<script>
import { Collection } from "pocketbase";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import CodeBlock from "@/components/base/CodeBlock.svelte";
import SdkTabs from "@/components/collections/docs/SdkTabs.svelte";
export let collection = new Collection();
export let collection;
let responseTab = 204;
let responses = [];
@@ -1,17 +1,18 @@
<script>
import { Collection } from "pocketbase";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import CodeBlock from "@/components/base/CodeBlock.svelte";
import SdkTabs from "@/components/collections/docs/SdkTabs.svelte";
import FieldsQueryParam from "@/components/collections/docs/FieldsQueryParam.svelte";
export let collection = new Collection();
export let collection;
let responseTab = 200;
let responses = [];
let baseData = {};
$: isAuth = collection.type === "auth";
$: adminsOnly = collection?.createRule === null;
$: backendAbsUrl = CommonHelper.getApiExampleUrl(ApiClient.baseUrl);
@@ -48,7 +49,7 @@
},
];
$: if (collection.$isAuth) {
$: if (isAuth) {
baseData = {
username: "test_username",
email: "test@example.com",
@@ -91,7 +92,7 @@ const pb = new PocketBase('${backendAbsUrl}');
const data = ${JSON.stringify(Object.assign({}, baseData, CommonHelper.dummyCollectionSchemaData(collection)), null, 4)};
const record = await pb.collection('${collection?.name}').create(data);
` + (collection?.isAuth ?
` + (isAuth ?
`
// (optional) send an email verification request
await pb.collection('${collection?.name}').requestVerification('test@example.com');
@@ -108,7 +109,7 @@ final pb = PocketBase('${backendAbsUrl}');
final body = <String, dynamic>${JSON.stringify(Object.assign({}, baseData, CommonHelper.dummyCollectionSchemaData(collection)), null, 2)};
final record = await pb.collection('${collection?.name}').create(body: body);
` + (collection?.isAuth ?
` + (isAuth ?
`
// (optional) send an email verification request
await pb.collection('${collection?.name}').requestVerification('test@example.com');
@@ -156,7 +157,7 @@ await pb.collection('${collection?.name}').requestVerification('test@example.com
</td>
</tr>
{#if collection?.isAuth}
{#if isAuth}
<tr>
<td colspan="3" class="txt-hint">Auth fields</td>
</tr>
@@ -1,11 +1,10 @@
<script>
import { Collection } from "pocketbase";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import CodeBlock from "@/components/base/CodeBlock.svelte";
import SdkTabs from "@/components/collections/docs/SdkTabs.svelte";
export let collection = new Collection();
export let collection;
let responseTab = 204;
let responses = [];
@@ -1,12 +1,11 @@
<script>
import { Collection } from "pocketbase";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import CodeBlock from "@/components/base/CodeBlock.svelte";
import FilterSyntax from "@/components/collections/docs/FilterSyntax.svelte";
import SdkTabs from "@/components/collections/docs/SdkTabs.svelte";
export let collection = new Collection();
export let collection;
let responseTab = 200;
let responses = [];
@@ -1,12 +1,11 @@
<script>
import { Collection } from "pocketbase";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import CodeBlock from "@/components/base/CodeBlock.svelte";
import SdkTabs from "@/components/collections/docs/SdkTabs.svelte";
import FieldsQueryParam from "@/components/collections/docs/FieldsQueryParam.svelte";
export let collection = new Collection();
export let collection;
let responseTab = 200;
let responses = [];
@@ -1,11 +1,10 @@
<script>
import { Collection } from "pocketbase";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import CodeBlock from "@/components/base/CodeBlock.svelte";
import SdkTabs from "@/components/collections/docs/SdkTabs.svelte";
export let collection = new Collection();
export let collection;
$: backendAbsUrl = CommonHelper.getApiExampleUrl(ApiClient.baseUrl);
</script>
@@ -1,11 +1,10 @@
<script>
import { Collection } from "pocketbase";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import CodeBlock from "@/components/base/CodeBlock.svelte";
import SdkTabs from "@/components/collections/docs/SdkTabs.svelte";
export let collection = new Collection();
export let collection;
let responseTab = 204;
let responses = [];
@@ -1,11 +1,10 @@
<script>
import { Collection } from "pocketbase";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import CodeBlock from "@/components/base/CodeBlock.svelte";
import SdkTabs from "@/components/collections/docs/SdkTabs.svelte";
export let collection = new Collection();
export let collection;
let responseTab = 204;
let responses = [];
@@ -1,11 +1,10 @@
<script>
import { Collection } from "pocketbase";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import CodeBlock from "@/components/base/CodeBlock.svelte";
import SdkTabs from "@/components/collections/docs/SdkTabs.svelte";
export let collection = new Collection();
export let collection;
let responseTab = 204;
let responses = [];
@@ -1,11 +1,10 @@
<script>
import { Collection } from "pocketbase";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import CodeBlock from "@/components/base/CodeBlock.svelte";
import SdkTabs from "@/components/collections/docs/SdkTabs.svelte";
export let collection = new Collection();
export let collection;
let responseTab = 204;
let responses = [];
@@ -1,17 +1,18 @@
<script>
import { Collection } from "pocketbase";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import CodeBlock from "@/components/base/CodeBlock.svelte";
import SdkTabs from "@/components/collections/docs/SdkTabs.svelte";
import FieldsQueryParam from "@/components/collections/docs/FieldsQueryParam.svelte";
export let collection = new Collection();
export let collection;
let responseTab = 200;
let responses = [];
let baseData = {};
$: isAuth = collection?.type === "auth";
$: adminsOnly = collection?.updateRule === null;
$: backendAbsUrl = CommonHelper.getApiExampleUrl(ApiClient.baseUrl);
@@ -58,7 +59,7 @@
},
];
$: if (collection.$isAuth) {
$: if (collection.type === "auth") {
baseData = {
username: "test_username_update",
emailVisibility: false,
@@ -159,7 +160,7 @@ final record = await pb.collection('${collection?.name}').update('RECORD_ID', bo
</tr>
</thead>
<tbody>
{#if collection?.isAuth}
{#if isAuth}
<tr>
<td colspan="3" class="txt-hint">Auth fields</td>
</tr>
@@ -1,12 +1,11 @@
<script>
import { Collection } from "pocketbase";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import CodeBlock from "@/components/base/CodeBlock.svelte";
import SdkTabs from "@/components/collections/docs/SdkTabs.svelte";
import FieldsQueryParam from "@/components/collections/docs/FieldsQueryParam.svelte";
export let collection = new Collection();
export let collection;
let responseTab = 200;
let responses = [];
@@ -5,7 +5,6 @@
<script>
import { createEventDispatcher, onMount } from "svelte";
import { slide } from "svelte/transition";
import { SchemaField } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import tooltip from "@/actions/tooltip";
import { errors, setErrors } from "@/stores/errors";
@@ -23,7 +22,7 @@
};
export let key = "";
export let field = new SchemaField();
export let field = CommonHelper.initSchemaField();
let nameInput;
let showOptions = false;
@@ -72,7 +72,7 @@
return;
}
if (selectedColection.isAuth) {
if (selectedColection.type === "auth") {
displayFieldsList = displayFieldsList.concat(authFields);
}
+1 -2
View File
@@ -1,12 +1,11 @@
<script>
import { LogRequest } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import CodeBlock from "@/components/base/CodeBlock.svelte";
import FormattedDate from "@/components/base/FormattedDate.svelte";
import OverlayPanel from "@/components/base/OverlayPanel.svelte";
let logPanel;
let item = new LogRequest();
let item = {};
export function show(model) {
item = model;
+2 -2
View File
@@ -162,7 +162,7 @@
<span class="txt">API Preview</span>
</button>
{#if !$activeCollection.$isView}
{#if $activeCollection.type !== "view"}
<button type="button" class="btn btn-expanded" on:click={() => recordUpsertPanel?.show()}>
<i class="ri-add-line" />
<span class="txt">New record</span>
@@ -184,7 +184,7 @@
bind:filter
bind:sort
on:select={(e) => {
$activeCollection.$isView
$activeCollection.type === "view"
? recordPreviewPanel.show(e?.detail)
: recordUpsertPanel?.show(e?.detail);
}}
@@ -1,5 +1,4 @@
<script>
import { Record } from "pocketbase";
import OverlayPanel from "@/components/base/OverlayPanel.svelte";
import RecordFieldValue from "./RecordFieldValue.svelte";
import CopyIcon from "@/components/base/CopyIcon.svelte";
@@ -8,7 +7,7 @@
export let collection;
let recordPanel;
let record = new Record();
let record = {};
$: hasEditorField = !!collection?.schema?.find((f) => f.type === "editor");
@@ -1,7 +1,6 @@
<script>
import { createEventDispatcher, tick } from "svelte";
import { slide } from "svelte/transition";
import { Record } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import ApiClient from "@/utils/ApiClient";
import tooltip from "@/actions/tooltip";
@@ -46,6 +45,8 @@
let isNew = true;
let isLoaded = false;
$: isAuthCollection = collection?.type === "auth";
$: hasEditorField = !!collection?.schema?.find((f) => f.type === "editor");
$: hasFileChanges =
@@ -55,7 +56,7 @@
$: hasChanges = hasFileChanges || originalSerializedData != serializedData;
$: isNew = !original || original.$isNew;
$: isNew = !original || !original.id;
$: canSave = isNew || hasChanges;
@@ -80,8 +81,8 @@
async function load(model) {
isLoaded = false;
setErrors({}); // reset errors
original = model || new Record();
record = original.$clone();
original = model || {};
record = structuredClone(original);
uploadedFilesMap = {};
deletedFileNamesMap = {};
@@ -102,13 +103,13 @@
async function replaceOriginal(newOriginal) {
setErrors({}); // reset errors
original = newOriginal || new Record();
original = newOriginal || {};
uploadedFilesMap = {};
deletedFileNamesMap = {};
// to avoid layout shifts we replace only the file and non-schema fields
const skipFields = collection?.schema?.filter((f) => f.type != "file")?.map((f) => f.name) || [];
for (let k in newOriginal.$export()) {
for (let k in newOriginal) {
if (skipFields.includes(k)) {
continue;
}
@@ -150,20 +151,20 @@
}
function areRecordsEqual(recordA, recordB) {
const cloneA = recordA?.$clone();
const cloneB = recordB?.$clone();
const cloneA = structuredClone(recordA || {});
const cloneB = structuredClone(recordB || {});
const fileFields = collection?.schema?.filter((f) => f.type === "file");
for (let field of fileFields) {
delete cloneA?.[field.name];
delete cloneB?.[field.name];
delete cloneA[field.name];
delete cloneB[field.name];
}
// delete password props
delete cloneA?.password;
delete cloneA?.passwordConfirm;
delete cloneB?.password;
delete cloneB?.passwordConfirm;
delete cloneA.password;
delete cloneA.passwordConfirm;
delete cloneB.password;
delete cloneB.passwordConfirm;
return JSON.stringify(cloneA) == JSON.stringify(cloneB);
}
@@ -232,7 +233,7 @@
}
function exportFormData() {
const data = record?.$export() || {};
const data = structuredClone(record || {});
const formData = new FormData();
const exportableFields = {
@@ -243,7 +244,7 @@
exportableFields[field.name] = true;
}
if (collection?.isAuth) {
if (isAuthCollection) {
exportableFields["username"] = true;
exportableFields["email"] = true;
exportableFields["emailVisibility"] = true;
@@ -331,7 +332,7 @@
}
async function duplicate() {
const clone = original?.$clone();
let clone = original ? structuredClone(original) : null;
if (clone) {
clone.id = "";
@@ -369,7 +370,7 @@
class="
record-panel
{hasEditorField ? 'overlay-panel-xl' : 'overlay-panel-lg'}
{collection?.$isAuth && !isNew ? 'colored-header' : ''}
{isAuthCollection && !isNew ? 'colored-header' : ''}
"
beforeHide={() => {
if (hasChanges && confirmClose) {
@@ -400,7 +401,7 @@
<button type="button" aria-label="More" class="btn btn-sm btn-circle btn-transparent flex-gap-0">
<i class="ri-more-line" />
<Toggler class="dropdown dropdown-right dropdown-nowrap">
{#if collection.$isAuth && !original.verified && original.email}
{#if isAuthCollection && !original.verified && original.email}
<button
type="button"
class="dropdown-item closable"
@@ -410,7 +411,7 @@
<span class="txt">Send verification email</span>
</button>
{/if}
{#if collection.$isAuth && original.email}
{#if isAuthCollection && original.email}
<button
type="button"
class="dropdown-item closable"
@@ -436,7 +437,7 @@
</button>
{/if}
{#if collection.$isAuth && !isNew}
{#if isAuthCollection && !isNew}
<div class="tabs-header stretched">
<button
type="button"
@@ -523,7 +524,7 @@
/>
</Field>
{#if collection?.isAuth}
{#if isAuthCollection}
<AuthFields bind:record {isNew} {collection} />
{#if collection?.schema?.length}
@@ -564,7 +565,7 @@
{/each}
</form>
{#if collection.$isAuth && !isNew}
{#if isAuthCollection && !isNew}
<div class="tab-item" class:active={activeTab === tabProviderKey}>
<ExternalAuthsList {record} />
</div>
+14 -10
View File
@@ -37,6 +37,10 @@
clearList();
}
$: isView = collection?.type === "view";
$: isAuth = collection?.type === "auth";
$: fields = collection?.schema || [];
$: relFields = fields.filter((field) => field.type === "relation");
@@ -57,12 +61,12 @@
updateStoredHiddenColumns();
}
$: hasCreated = !collection?.$isView || (records.length > 0 && records[0].created != "");
$: hasCreated = !isView || (records.length > 0 && records[0].created != "");
$: hasUpdated = !collection?.$isView || (records.length > 0 && records[0].updated != "");
$: hasUpdated = !isView || (records.length > 0 && records[0].updated != "");
$: collumnsToHide = [].concat(
collection.$isAuth
isAuth
? [
{ id: "@username", name: "username" },
{ id: "@email", name: "email" },
@@ -278,7 +282,7 @@
<table class="table" class:table-loading={isLoading}>
<thead>
<tr>
{#if !collection.$isView}
{#if !isView}
<th class="bulk-select-col min-width">
{#if isLoading}
<span class="loader loader-sm" />
@@ -306,7 +310,7 @@
</SortHeader>
{/if}
{#if collection.$isAuth}
{#if isAuth}
{#if !hiddenColumns.includes("@username")}
<SortHeader class="col-type-text col-field-id" name="username" bind:sort>
<div class="col-header-content">
@@ -371,7 +375,7 @@
</tr>
</thead>
<tbody>
{#each records as record (!collection.$isView ? record.id : record)}
{#each records as record (!isView ? record.id : record)}
<tr
tabindex="0"
class="row-handle"
@@ -383,7 +387,7 @@
}
}}
>
{#if !collection.$isView}
{#if !isView}
<td class="bulk-select-col min-width">
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="form-field" on:click|stopPropagation>
@@ -406,7 +410,7 @@
<div class="txt">{record.id}</div>
</div>
{#if collection.$isAuth}
{#if isAuth}
{#if record.verified}
<i
class="ri-checkbox-circle-fill txt-sm txt-success"
@@ -423,7 +427,7 @@
</td>
{/if}
{#if collection.$isAuth}
{#if isAuth}
{#if !hiddenColumns.includes("@username")}
<td class="col-type-text col-field-username">
{#if CommonHelper.isEmpty(record.username)}
@@ -489,7 +493,7 @@
>
<span class="txt">Clear filters</span>
</button>
{:else if !collection?.$isView}
{:else if !isView}
<button
type="button"
class="btn btn-secondary btn-expanded m-t-sm"
@@ -40,6 +40,8 @@
loadList(true); // reset list on filter change
}
$: isView = collection?.type === "view";
$: isLoading = isLoadingList || isLoadingSelected;
$: canLoadMore = lastItemsCount == batchSize;
@@ -139,7 +141,7 @@
const result = await ApiClient.collection(collectionId).getList(page, batchSize, {
filter: CommonHelper.normalizeSearchFilter(filter, fallbackSearchFields),
sort: !collection?.$isView ? "-created" : "",
sort: !isView ? "-created" : "",
skipTotal: 1,
$cancelKey: uniqueId + "loadList",
});
@@ -208,7 +210,7 @@
autocompleteCollection={collection}
on:submit={(e) => (filter = e.detail)}
/>
{#if !collection?.$isView}
{#if !isView}
<button
type="button"
class="btn btn-transparent btn-hint p-l-sm p-r-sm"
@@ -252,7 +254,7 @@
<div class="content">
<RecordInfo {record} {displayFields} />
</div>
{#if !collection?.$isView}
{#if !isView}
<div class="actions nonintrusive">
<button
type="button"
@@ -1,15 +1,14 @@
<script>
import { slide } from "svelte/transition";
import { Collection, Record } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import tooltip from "@/actions/tooltip";
import { confirm } from "@/stores/confirmation";
import { removeError } from "@/stores/errors";
import Field from "@/components/base/Field.svelte";
export let collection = new Collection();
export let record = new Record();
export let isNew = record.$isNew;
export let record;
export let collection;
export let isNew = !!record.id;
let originalUsername = record.username || null;
@@ -1,8 +1,7 @@
<script>
import { SchemaField } from "pocketbase";
import Field from "@/components/base/Field.svelte";
export let field = new SchemaField();
export let field;
export let value = false;
</script>
@@ -1,11 +1,10 @@
<script>
import { SchemaField } from "pocketbase";
import Flatpickr from "svelte-flatpickr";
import CommonHelper from "@/utils/CommonHelper";
import Field from "@/components/base/Field.svelte";
import tooltip from "@/actions/tooltip";
export let field = new SchemaField();
export let field;
export let value = undefined;
let pickerValue = value;
@@ -1,10 +1,9 @@
<script>
import { SchemaField } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import Field from "@/components/base/Field.svelte";
import TinyMCE from "@tinymce/tinymce-svelte";
export let field = new SchemaField();
export let field;
export let value = undefined;
</script>
@@ -1,9 +1,8 @@
<script>
import { SchemaField } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import Field from "@/components/base/Field.svelte";
export let field = new SchemaField();
export let field;
export let value = undefined;
</script>
@@ -1,5 +1,4 @@
<script>
import { SchemaField } from "pocketbase";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import tooltip from "@/actions/tooltip";
@@ -10,10 +9,10 @@
import { onMount } from "svelte";
export let record;
export let field;
export let value = "";
export let uploadedFiles = []; // Array<File> array
export let deletedFileNames = []; // Array<string> array
export let field = new SchemaField();
let fileInput;
let filesListElem;
@@ -1,9 +1,8 @@
<script>
import { SchemaField } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import Field from "@/components/base/Field.svelte";
export let field = new SchemaField();
export let field;
export let value = undefined;
let serialized = JSON.stringify(typeof value === "undefined" ? null : value, null, 2);
@@ -1,9 +1,8 @@
<script>
import { SchemaField } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import Field from "@/components/base/Field.svelte";
export let field = new SchemaField();
export let field;
export let value = undefined;
</script>
@@ -1,6 +1,5 @@
<script>
import { onDestroy } from "svelte";
import { SchemaField } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import ApiClient from "@/utils/ApiClient";
import tooltip from "@/actions/tooltip";
@@ -11,9 +10,9 @@
const batchSize = 100;
export let field;
export let value;
export let picker;
export let field = new SchemaField();
let fieldRef;
let list = [];
@@ -1,10 +1,9 @@
<script>
import { SchemaField } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import Select from "@/components/base/Select.svelte";
import Field from "@/components/base/Field.svelte";
export let field = new SchemaField();
export let field;
export let value = undefined;
$: isMultiple = field.options?.maxSelect > 1;
@@ -1,10 +1,9 @@
<script>
import { SchemaField } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import Field from "@/components/base/Field.svelte";
import AutoExpandTextarea from "@/components/base/AutoExpandTextarea.svelte";
export let field = new SchemaField();
export let field;
export let value = undefined;
</script>
@@ -1,9 +1,8 @@
<script>
import { SchemaField } from "pocketbase";
import CommonHelper from "@/utils/CommonHelper";
import Field from "@/components/base/Field.svelte";
export let field = new SchemaField();
export let field;
export let value = undefined;
</script>
+6 -7
View File
@@ -1,4 +1,4 @@
import PocketBase, { LocalAuthStore, Admin, isTokenExpired } from "pocketbase";
import PocketBase, { LocalAuthStore, isTokenExpired } from "pocketbase";
// ---
import CommonHelper from "@/utils/CommonHelper";
import { replace } from "svelte-spa-router";
@@ -8,7 +8,6 @@ import { setErrors } from "@/stores/errors";
import { setAdmin } from "@/stores/admin";
import { protectedFilesCollectionsCache } from "@/stores/collections";
const adminFileTokenKey = "pb_admin_file_token";
/**
@@ -107,7 +106,7 @@ class AppAuthStore extends LocalAuthStore {
save(token, model) {
super.save(token, model);
if (model instanceof Admin) {
if (model && !model.collectionId) { // not an auth record
setAdmin(model);
}
}
@@ -122,13 +121,13 @@ class AppAuthStore extends LocalAuthStore {
}
}
const client = new PocketBase(
const pb = new PocketBase(
import.meta.env.PB_BACKEND_URL,
new AppAuthStore("pb_admin_auth")
);
if (client.authStore.model instanceof Admin) {
setAdmin(client.authStore.model);
if (pb.authStore.model && !pb.authStore.model.collectionId) { // not an auth record
setAdmin(pb.authStore.model);
}
export default client;
export default pb;
+50 -5
View File
@@ -944,25 +944,28 @@ export default class CommonHelper {
static dummyCollectionRecord(collection) {
const fields = collection?.schema || [];
const isAuth = collection?.type === "auth";
const isView = collection?.type === "view";
const dummy = {
"id": "RECORD_ID",
"collectionId": collection?.id,
"collectionName": collection?.name,
};
if (collection?.isAuth) {
if (isAuth) {
dummy["username"] = "username123";
dummy["verified"] = false;
dummy["emailVisibility"] = true;
dummy["email"] = "test@example.com";
}
const hasCreated = !collection?.$isView || CommonHelper.extractColumnsFromQuery(collection?.options?.query).includes("created");
const hasCreated = !isView || CommonHelper.extractColumnsFromQuery(collection?.options?.query).includes("created");
if (hasCreated) {
dummy["created"] = "2022-01-01 01:00:00.123Z";
}
const hasUpdated = !collection?.$isView || CommonHelper.extractColumnsFromQuery(collection?.options?.query).includes("updated");
const hasUpdated = !isView || CommonHelper.extractColumnsFromQuery(collection?.options?.query).includes("updated");
if (hasUpdated) {
dummy["updated"] = "2022-01-01 23:59:59.456Z";
}
@@ -1542,11 +1545,11 @@ export default class CommonHelper {
let result = [prefix + "id"];
if (collection.$isView) {
if (collection.type === "view") {
for (let col of CommonHelper.extractColumnsFromQuery(collection.options.query)) {
CommonHelper.pushUnique(result, prefix + col);
}
} else if (collection.$isAuth) {
} else if (collection.type === "auth") {
result.push(prefix + "username");
result.push(prefix + "email");
result.push(prefix + "emailVisibility");
@@ -1800,4 +1803,46 @@ export default class CommonHelper {
return fallbackFields.map((f) => `${f}~${searchTerm}`).join("||");
}
/**
* Iniitialize a new blank Collection POJO and merge it with the provided data (if any).
*
* @param {Object} [data]
* @return {Object}
*/
static initCollection(data) {
return Object.assign({
id: '',
created: '',
updated: '',
name: '',
type: 'base',
system: false,
listRule: null,
viewRule: null,
createRule: null,
updateRule: null,
deleteRule: null,
schema: [],
indexes: [],
options: {},
}, data);
}
/**
* Iniitialize a new blank SchemaField POJO and merge it with the provided data (if any).
*
* @param {Object} [data]
* @return {Object}
*/
static initSchemaField(data) {
return Object.assign({
id: '',
name: '',
type: 'text',
system: false,
required: false,
options: {},
}, data);
}
}