merge v0.23.0-rc changes

This commit is contained in:
Gani Georgiev
2024-09-29 19:23:19 +03:00
parent ad92992324
commit 844f18cac3
753 changed files with 85141 additions and 63396 deletions
+1 -1
View File
@@ -107,7 +107,7 @@
</button>
{#if active}
<div class="accordion-content" transition:slide={{ duration: 150 }}>
<div class="accordion-content" transition:slide={{ delay: 10, duration: 150 }}>
<slot />
</div>
{/if}
@@ -0,0 +1,24 @@
<script>
import CommonHelper from "@/utils/CommonHelper";
export let value = "";
export let options = []; // [{label: "Option 1", value: "opt1"}, {label: "Option 2", value: "opt2"}, ...]
const uniqueId = "list_" + CommonHelper.randomString(5);
</script>
<input
type={$$restProps.type || "text"}
list={uniqueId}
{value}
on:input={(e) => {
value = e.target.value;
}}
{...$$restProps}
/>
<datalist id={uniqueId}>
{#each options as opt}
<option value={opt.value}>{opt.label || ""}</option>
{/each}
</datalist>
+3 -2
View File
@@ -34,7 +34,7 @@
JSON.stringify({
index: i,
group: group,
})
}),
);
dispatch("drag", e);
@@ -79,6 +79,7 @@
}
</script>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
draggable={!disabled}
class="draggable"
@@ -102,7 +103,7 @@
<style>
.draggable {
user-select: none;
user-select: text;
outline: 0;
min-width: 0;
}
@@ -109,7 +109,7 @@
addLabelListeners();
}
$: if (editor && baseCollection?.schema) {
$: if (editor && baseCollection?.fields) {
editor.dispatch({
effects: [langCompartment.reconfigure(ruleLang())],
});
@@ -172,7 +172,7 @@
// Return a collection keys hash string that can be used to compare with previous states.
function getCollectionKeysChangeHash(collection) {
return JSON.stringify([collection?.name, collection?.type, collection?.schema]);
return JSON.stringify([collection?.name, collection?.type, collection?.fields]);
}
// Merge the base collection in a new list with the provided collections.
+88 -7
View File
@@ -1,6 +1,8 @@
<script>
import { createEventDispatcher } from "svelte";
import ApiClient from "@/utils/ApiClient";
import { addInfoToast } from "@/stores/toasts";
import { confirm } from "@/stores/confirmation";
import Field from "@/components/base/Field.svelte";
const dispatch = createEventDispatcher();
@@ -9,22 +11,27 @@
let password = "";
let passwordConfirm = "";
let isLoading = false;
let isUploading = false;
let backupFileInput;
$: isBusy = isLoading || isUploading;
async function submit() {
if (isLoading) {
if (isBusy) {
return;
}
isLoading = true;
try {
await ApiClient.admins.create({
await ApiClient.collection("_superusers").create({
email,
password,
passwordConfirm,
});
await ApiClient.admins.authWithPassword(email, password);
await ApiClient.collection("_superusers").authWithPassword(email, password);
dispatch("submit");
} catch (err) {
@@ -33,11 +40,61 @@
isLoading = false;
}
function resetSelectedBackupFile() {
if (backupFileInput) {
backupFileInput.value = "";
}
}
function uploadBackupConfirm(file) {
if (!file) {
return;
}
confirm(
`Note that we don't perform validations for the uploaded backup files. Proceed with caution and only if you trust the file source.\n\n` +
`Do you really want to upload and initialize "${file.name}"?`,
() => {
uploadBackup(file);
},
() => {
resetSelectedBackupFile();
},
);
}
async function uploadBackup(file) {
if (!file || isBusy) {
return;
}
isUploading = true;
try {
await ApiClient.backups.upload({ file: file });
await ApiClient.backups.restore(file.name);
addInfoToast("Please wait while extracting the uploaded archive!");
// optimistic restore completion
await new Promise((r) => setTimeout(r, 2000));
dispatch("submit");
} catch (err) {
ApiClient.error(err);
}
resetSelectedBackupFile();
isUploading = false;
}
</script>
<form class="block" autocomplete="off" on:submit|preventDefault={submit}>
<div class="content txt-center m-b-base">
<h4>Create your first admin account in order to continue</h4>
<h4>Create your first superuser account in order to continue</h4>
</div>
<Field class="form-field required" name="email" let:uniqueId>
@@ -56,7 +113,7 @@
bind:value={password}
required
/>
<div class="help-block">Minimum 10 characters.</div>
<div class="help-block">Recommended at least 10 characters.</div>
</Field>
<Field class="form-field required" name="passwordConfirm" let:uniqueId>
@@ -67,10 +124,34 @@
<button
type="submit"
class="btn btn-lg btn-block btn-next"
class:btn-disabled={isLoading}
class:btn-disabled={isBusy}
class:btn-loading={isLoading}
>
<span class="txt">Create and login</span>
<span class="txt">Create superuser and login</span>
<i class="ri-arrow-right-line" />
</button>
</form>
<hr />
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<label
for="backupFileInput"
class="btn btn-lg btn-hint btn-transparent btn-block"
class:btn-disabled={isBusy}
class:btn-loading={isUploading}
>
<i class="ri-upload-cloud-line" />
<span class="txt">Or initialize from backup</span>
</label>
<input
bind:this={backupFileInput}
id="backupFileInput"
type="file"
class="hidden"
accept=".zip"
on:change={(e) => {
uploadBackupConfirm(e.target?.files?.[0]);
}}
/>
@@ -1,38 +0,0 @@
<script>
import tooltip from "@/actions/tooltip";
import CommonHelper from "@/utils/CommonHelper";
const detailedDateFormat = "yyyy-MM-dd HH:mm:ss.SSS";
export let model;
let tooltipDates = [];
$: if (model) {
refreshTooltipDates();
}
function refreshTooltipDates() {
tooltipDates = [];
if (model.created) {
tooltipDates.push(
"Created: " + CommonHelper.formatToLocalDate(model.created, detailedDateFormat) + " Local"
);
}
if (model.updated) {
tooltipDates.push(
"Updated: " + CommonHelper.formatToLocalDate(model.updated, detailedDateFormat) + " Local"
);
}
}
</script>
<i
class="ri-calendar-event-line txt-disabled"
use:tooltip={{
text: tooltipDates.join("\n"),
position: "left",
}}
/>
+2 -2
View File
@@ -1,7 +1,7 @@
<script>
import CommonHelper from "@/utils/CommonHelper";
import Select from "@/components/base/Select.svelte";
import BaseSelectOption from "@/components/base/BaseSelectOption.svelte";
import Select from "@/components/base/Select.svelte";
import CommonHelper from "@/utils/CommonHelper";
// original select props
export let items = [];
+1 -1
View File
@@ -2,7 +2,7 @@
import CommonHelper from "@/utils/CommonHelper";
import Dragline from "@/components/base/Dragline.svelte";
const widthStorageKey = "@adminSidebarWidth";
const widthStorageKey = "@superuserSidebarWidth";
let classes = "";
export { classes as class }; // export reserved keyword
+12 -8
View File
@@ -1,4 +1,6 @@
<script>
import { superuser } from "@/stores/superuser";
export let center = false;
let classes = "";
@@ -13,13 +15,15 @@
<footer class="page-footer">
<slot name="footer" />
<a href={import.meta.env.PB_DOCS_URL} target="_blank" rel="noopener noreferrer">
<i class="ri-book-open-line txt-sm" />
<span class="txt">Docs</span>
</a>
<span class="delimiter">|</span>
<a href={import.meta.env.PB_RELEASES} target="_blank" rel="noopener noreferrer" title="Releases">
<span class="txt">PocketBase {import.meta.env.PB_VERSION}</span>
</a>
{#if $superuser?.id}
<a href={import.meta.env.PB_DOCS_URL} target="_blank" rel="noopener noreferrer">
<i class="ri-book-open-line txt-sm" />
<span class="txt">Docs</span>
</a>
<span class="delimiter">|</span>
<a href={import.meta.env.PB_RELEASES} target="_blank" rel="noopener noreferrer" title="Releases">
<span class="txt">PocketBase {import.meta.env.PB_VERSION}</span>
</a>
{/if}
</footer>
</div>
@@ -2,35 +2,32 @@
import { tick } from "svelte";
import tooltip from "@/actions/tooltip";
export let mask = false;
export let value = "";
export let mask = "******";
let inputElem;
let locked = false;
$: locked = value === mask;
async function unlock() {
value = "";
locked = false;
mask = false;
await tick();
inputElem?.focus();
}
</script>
{#if locked}
{#if mask}
<div class="form-field-addon">
<button
type="button"
class="btn btn-transparent btn-circle"
use:tooltip={{ position: "left", text: "Set new value" }}
on:click={() => unlock()}
on:click|preventDefault={unlock}
>
<i class="ri-key-line" />
</button>
</div>
<input readonly type="text" placeholder={mask} {...$$restProps} />
<input readonly type="text" placeholder="******" {...$$restProps} />
{:else}
<input bind:this={inputElem} bind:value type="password" autocomplete="new-password" {...$$restProps} />
{/if}
+67
View File
@@ -0,0 +1,67 @@
<script>
import CodeBlock from "@/components/base/CodeBlock.svelte";
const SDK_PREFERENCE_KEY = "pb_sdk_preference";
let classes = "m-b-sm";
export { classes as class }; // export reserved keyword
export let js = "";
export let dart = "";
let activeTab = localStorage.getItem(SDK_PREFERENCE_KEY) || "javascript";
$: if (activeTab) {
// store user preference
localStorage.setItem(SDK_PREFERENCE_KEY, activeTab);
}
$: sdkExamples = [
{
title: "JavaScript",
language: "javascript",
content: js,
url: import.meta.env.PB_JS_SDK_URL,
},
{
title: "Dart",
language: "dart",
content: dart,
url: import.meta.env.PB_DART_SDK_URL,
},
];
</script>
<div class="tabs sdk-tabs {classes}">
<div class="tabs-header compact combined left">
{#each sdkExamples as example (example.language)}
<button
class="tab-item"
class:active={activeTab === example.language}
on:click={() => (activeTab = example.language)}
>
<div class="txt">{example.title}</div>
</button>
{/each}
</div>
<div class="tabs-content">
{#each sdkExamples as example (example.language)}
<div class="tab-item" class:active={activeTab === example.language}>
<CodeBlock language={example.language} content={example.content} />
<div class="txt-right">
<em class="txt-sm txt-hint">
<a href={example.url} target="_blank" rel="noopener noreferrer">
{example.title} SDK
</a>
</em>
</div>
</div>
{/each}
</div>
</div>
<style>
.sdk-tabs .tabs-header .tab-item {
min-width: 100px;
}
</style>
+2 -2
View File
@@ -1,7 +1,7 @@
<script>
import CommonHelper from "@/utils/CommonHelper";
import { createEventDispatcher, onMount } from "svelte";
import { fly } from "svelte/transition";
import CommonHelper from "@/utils/CommonHelper";
const dispatch = createEventDispatcher();
const uniqueId = "search_" + CommonHelper.randomString(7);
@@ -10,7 +10,7 @@
export let placeholder = 'Search term or filter like created > "2022-01-01"...';
// autocomplete filter component fields
export let autocompleteCollection = CommonHelper.initCollection();
export let autocompleteCollection = null;
export let extraAutocompleteKeys = [];
let filterComponent;
+16 -4
View File
@@ -1,8 +1,8 @@
<script>
import { onMount, createEventDispatcher } from "svelte";
import tooltip from "@/actions/tooltip";
import Toggler from "@/components/base/Toggler.svelte";
import CommonHelper from "@/utils/CommonHelper";
import { onMount } from "svelte";
export let id = "";
export let noOptionsText = "No options found";
@@ -13,7 +13,8 @@
export let disabled = false;
export let readonly = false;
export let upside = false;
export let selected = multiple ? [] : undefined;
export let zeroFunc = () => (multiple ? [] : undefined);
export let selected = zeroFunc();
export let toggle = multiple; // toggle option on click
export let closable = true; // close the dropdown on option select/deselect
export let labelComponent = undefined; // custom component to use for each selected option label
@@ -23,6 +24,8 @@
export let searchable = false; // whether to show the dropdown options search input
export let searchFunc = undefined; // custom search option filter: `function(item, searchTerm):boolean`
const dispatch = createEventDispatcher();
let classes = "";
export { classes as class }; // export reserved keyword
@@ -54,9 +57,11 @@
let normalized = CommonHelper.toArray(selected);
if (CommonHelper.inArray(normalized, item)) {
CommonHelper.removeByValue(normalized, item);
selected = normalized;
selected = multiple ? normalized : normalized?.[0] || zeroFunc();
}
dispatch("change", { selected });
// emulate native change event
container?.dispatchEvent(new CustomEvent("change", { detail: selected, bubbles: true }));
}
@@ -71,6 +76,8 @@
selected = item;
}
dispatch("change", { selected });
// emulate native change event
container?.dispatchEvent(new CustomEvent("change", { detail: selected, bubbles: true }));
}
@@ -80,7 +87,12 @@
}
export function reset() {
selected = multiple ? [] : undefined;
selected = zeroFunc();
dispatch("change", { selected });
// emulate native change event
container?.dispatchEvent(new CustomEvent("change", { detail: selected, bubbles: true }));
}
export function showDropdown() {