Add head tag script CRUD in app settings
This commit is contained in:
parent
8f19b4250b
commit
10d8202372
|
@ -44,6 +44,11 @@
|
|||
url={$url("./version")}
|
||||
active={$isActive("./version")}
|
||||
/>
|
||||
<SideNavItem
|
||||
text="Scripts"
|
||||
url={$url("./scripts")}
|
||||
active={$isActive("./scripts")}
|
||||
/>
|
||||
<div class="delete-action">
|
||||
<AbsTooltip
|
||||
position={TooltipPosition.Bottom}
|
||||
|
|
|
@ -170,7 +170,7 @@
|
|||
<Layout noPadding>
|
||||
<Layout gap="XS" noPadding>
|
||||
<Heading>Automations</Heading>
|
||||
<Body size="S">See your automation history and edit advanced settings</Body>
|
||||
<Body>See your automation history and edit advanced settings</Body>
|
||||
</Layout>
|
||||
<Divider />
|
||||
|
||||
|
@ -251,7 +251,6 @@
|
|||
data={runHistory}
|
||||
{customRenderers}
|
||||
placeholderText="No history found"
|
||||
border={false}
|
||||
/>
|
||||
<div class="pagination">
|
||||
<Pagination
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
<script lang="ts">
|
||||
import {
|
||||
Body,
|
||||
Button,
|
||||
Link,
|
||||
Divider,
|
||||
Heading,
|
||||
Layout,
|
||||
Table,
|
||||
Label,
|
||||
Input,
|
||||
TextArea,
|
||||
Select,
|
||||
Helpers,
|
||||
notifications,
|
||||
} from "@budibase/bbui"
|
||||
import { appStore } from "@/stores/builder"
|
||||
import { type AppScript } from "@budibase/types"
|
||||
import { getSequentialName } from "@/helpers/duplicate"
|
||||
import ConfirmDialog from "@/components/common/ConfirmDialog.svelte"
|
||||
|
||||
const schema = {
|
||||
name: {
|
||||
type: "string",
|
||||
label: "Name",
|
||||
},
|
||||
location: {
|
||||
type: "string",
|
||||
label: "Location",
|
||||
},
|
||||
}
|
||||
|
||||
let selectedScript: AppScript | undefined
|
||||
let isNew = false
|
||||
let confirmDeleteModal: any
|
||||
|
||||
$: nameError = selectedScript?.name ? undefined : "Please enter a name"
|
||||
$: invalid = !!nameError
|
||||
|
||||
const addScript = () => {
|
||||
const name = getSequentialName($appStore.scripts, "Script ", {
|
||||
getName: script => script.name,
|
||||
numberFirstItem: true,
|
||||
})
|
||||
selectedScript = { id: Helpers.uuid(), location: "Head", name }
|
||||
isNew = true
|
||||
}
|
||||
|
||||
const editScript = (e: any) => {
|
||||
selectedScript = { ...(e.detail as AppScript) }
|
||||
isNew = false
|
||||
}
|
||||
|
||||
const cancel = () => {
|
||||
selectedScript = undefined
|
||||
}
|
||||
|
||||
const save = async () => {
|
||||
if (!selectedScript) {
|
||||
return
|
||||
}
|
||||
const newScripts = $appStore.scripts
|
||||
.filter(script => script.id !== selectedScript!.id)
|
||||
.concat([selectedScript])
|
||||
await appStore.updateApp({ scripts: newScripts })
|
||||
notifications.success("Script saved successfully")
|
||||
selectedScript = undefined
|
||||
}
|
||||
|
||||
const requestDeletion = () => {
|
||||
confirmDeleteModal?.show()
|
||||
}
|
||||
|
||||
const deleteScript = async () => {
|
||||
if (!selectedScript) {
|
||||
return
|
||||
}
|
||||
const newScripts = $appStore.scripts.filter(
|
||||
script => script.id !== selectedScript!.id
|
||||
)
|
||||
await appStore.updateApp({ scripts: newScripts })
|
||||
notifications.success("Script deleted successfully")
|
||||
selectedScript = undefined
|
||||
}
|
||||
</script>
|
||||
|
||||
<Layout noPadding>
|
||||
<Layout gap="XS" noPadding>
|
||||
<Heading>Scripts</Heading>
|
||||
<div class="header">
|
||||
<Body>
|
||||
Inject analytics, scripts or stylesheets into your app<br />
|
||||
<Link href="#">Learn more about script injection in the docs</Link>
|
||||
</Body>
|
||||
{#if !selectedScript}
|
||||
<Button cta on:click={addScript}>Add script</Button>
|
||||
{/if}
|
||||
</div>
|
||||
</Layout>
|
||||
<Divider />
|
||||
{#if selectedScript}
|
||||
<div class="form">
|
||||
<Label size="L">Name</Label>
|
||||
<Input bind:value={selectedScript.name} error={nameError} />
|
||||
<Label size="L">Location</Label>
|
||||
<Select
|
||||
bind:value={selectedScript.location}
|
||||
options={["Head", "Body"]}
|
||||
placeholder={false}
|
||||
/>
|
||||
<Label size="L">HTML</Label>
|
||||
<TextArea bind:value={selectedScript.html} minHeight={200} />
|
||||
<div />
|
||||
<div class="buttons">
|
||||
{#if !isNew}
|
||||
<Button warning quiet on:click={requestDeletion}>Delete</Button>
|
||||
{/if}
|
||||
<Button secondary on:click={cancel}>Cancel</Button>
|
||||
<Button cta disabled={invalid} on:click={save}>Save</Button>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<Table
|
||||
on:click={editScript}
|
||||
{schema}
|
||||
data={$appStore.scripts}
|
||||
allowSelectRows={false}
|
||||
allowEditColumns={false}
|
||||
allowEditRows={false}
|
||||
placeholderText="You haven't added any scripts yet"
|
||||
/>
|
||||
{/if}
|
||||
</Layout>
|
||||
|
||||
<ConfirmDialog
|
||||
bind:this={confirmDeleteModal}
|
||||
title="Delete script"
|
||||
body="Are you sure you want to delete this script?"
|
||||
onOk={deleteScript}
|
||||
/>
|
||||
|
||||
<style>
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.form {
|
||||
display: grid;
|
||||
grid-template-columns: 100px 480px;
|
||||
row-gap: var(--spacing-l);
|
||||
}
|
||||
.form :global(.spectrum-FieldLabel) {
|
||||
padding-top: 7px;
|
||||
}
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
gap: var(--spacing-l);
|
||||
}
|
||||
</style>
|
|
@ -4,9 +4,12 @@ import {
|
|||
App,
|
||||
AppFeatures,
|
||||
AppIcon,
|
||||
AppScript,
|
||||
AutomationSettings,
|
||||
Plugin,
|
||||
UpdateAppRequest,
|
||||
} from "@budibase/types"
|
||||
import { get } from "svelte/store"
|
||||
|
||||
interface ClientFeatures {
|
||||
spectrumThemes: boolean
|
||||
|
@ -46,6 +49,7 @@ interface AppMetaState {
|
|||
revertableVersion?: string
|
||||
upgradableVersion?: string
|
||||
icon?: AppIcon
|
||||
scripts: AppScript[]
|
||||
}
|
||||
|
||||
export const INITIAL_APP_META_STATE: AppMetaState = {
|
||||
|
@ -79,6 +83,7 @@ export const INITIAL_APP_META_STATE: AppMetaState = {
|
|||
usedPlugins: [],
|
||||
automations: {},
|
||||
routes: {},
|
||||
scripts: [],
|
||||
}
|
||||
|
||||
export class AppMetaStore extends BudiStore<AppMetaState> {
|
||||
|
@ -90,20 +95,12 @@ export class AppMetaStore extends BudiStore<AppMetaState> {
|
|||
this.store.set({ ...INITIAL_APP_META_STATE })
|
||||
}
|
||||
|
||||
syncAppPackage(pkg: {
|
||||
application: App
|
||||
clientLibPath: string
|
||||
hasLock: boolean
|
||||
}) {
|
||||
const { application: app, clientLibPath, hasLock } = pkg
|
||||
|
||||
syncApp(app: App) {
|
||||
this.update(state => ({
|
||||
...state,
|
||||
name: app.name,
|
||||
appId: app.appId,
|
||||
url: app.url || "",
|
||||
hasLock,
|
||||
clientLibPath,
|
||||
libraries: app.componentLibraries,
|
||||
version: app.version,
|
||||
appInstance: app.instance,
|
||||
|
@ -118,9 +115,24 @@ export class AppMetaStore extends BudiStore<AppMetaState> {
|
|||
initialised: true,
|
||||
automations: app.automations || {},
|
||||
hasAppPackage: true,
|
||||
scripts: app.scripts || [],
|
||||
}))
|
||||
}
|
||||
|
||||
syncAppPackage(pkg: {
|
||||
application: App
|
||||
clientLibPath: string
|
||||
hasLock: boolean
|
||||
}) {
|
||||
const { application, clientLibPath, hasLock } = pkg
|
||||
this.update(state => ({
|
||||
...state,
|
||||
hasLock,
|
||||
clientLibPath,
|
||||
}))
|
||||
this.syncApp(application)
|
||||
}
|
||||
|
||||
syncClientFeatures(features: Partial<ClientFeatures>) {
|
||||
this.update(state => ({
|
||||
...state,
|
||||
|
@ -146,6 +158,11 @@ export class AppMetaStore extends BudiStore<AppMetaState> {
|
|||
}))
|
||||
}
|
||||
|
||||
async updateApp(updates: UpdateAppRequest) {
|
||||
const app = await API.saveAppMetadata(get(this.store).appId, updates)
|
||||
this.syncApp(app)
|
||||
}
|
||||
|
||||
// Returned from socket
|
||||
syncMetadata(metadata: { name: string; url: string; icon?: AppIcon }) {
|
||||
const { name, url, icon } = metadata
|
||||
|
|
|
@ -29,6 +29,7 @@ export interface App extends Document {
|
|||
snippets?: Snippet[]
|
||||
creationVersion?: string
|
||||
updatedBy?: string
|
||||
scripts?: AppScript[]
|
||||
}
|
||||
|
||||
export interface AppInstance {
|
||||
|
@ -82,3 +83,10 @@ export interface AppFeatures {
|
|||
export interface AutomationSettings {
|
||||
chainAutomations?: boolean
|
||||
}
|
||||
|
||||
export interface AppScript {
|
||||
id: string
|
||||
name: string
|
||||
location: "Head" | "Body"
|
||||
html?: string
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue