|
1 |
| -<script lang="ts"> |
2 |
| - import { onMount, onDestroy } from "svelte" |
3 |
| - import { params, goto } from "@roxi/routify" |
4 |
| - import { |
5 |
| - licensing, |
6 |
| - auth, |
7 |
| - sideBarCollapsed, |
8 |
| - enrichedApps, |
9 |
| - } from "@/stores/portal" |
10 |
| - import AppContextMenuModals from "@/components/start/AppContextMenuModals.svelte" |
11 |
| - import getAppContextMenuItems from "@/components/start/getAppContextMenuItems" |
12 |
| - import FavouriteAppButton from "../FavouriteAppButton.svelte" |
13 |
| - import { |
14 |
| - Link, |
15 |
| - Body, |
16 |
| - Button, |
17 |
| - Icon, |
18 |
| - TooltipPosition, |
19 |
| - TooltipType, |
20 |
| - } from "@budibase/bbui" |
21 |
| - import { sdk, getThemeClassNames } from "@budibase/shared-core" |
22 |
| - import { API } from "@/api" |
23 |
| - import ErrorSVG from "./ErrorSVG.svelte" |
24 |
| - import { ClientAppSkeleton } from "@budibase/frontend-core" |
25 |
| - import { contextMenuStore } from "@/stores/builder" |
26 |
| - import type { EnrichedApp } from "@/types" |
| 1 | +<script> |
| 2 | + import { redirect } from "@roxi/routify" |
27 | 3 |
|
28 |
| - $: app = $enrichedApps.find(app => app.appId === $params.appId)! |
29 |
| - $: iframeUrl = getIframeURL(app) |
30 |
| - $: isBuilder = sdk.users.isBuilder($auth.user, app?.devId) |
31 |
| -
|
32 |
| - let loading = true |
33 |
| - let appContextMenuModals: AppContextMenuModals |
34 |
| -
|
35 |
| - const getIframeURL = (app: EnrichedApp) => { |
36 |
| - const workspaceUrl = |
37 |
| - app.status === "published" ? `/app${app.url}` : `/${app.devId}` |
38 |
| -
|
39 |
| - return `${workspaceUrl}${app.defaultWorkspaceAppUrl}` |
40 |
| - } |
41 |
| -
|
42 |
| - $: iframeUrl && (loading = true) // If the iframe changes, set loading to true |
43 |
| -
|
44 |
| - let noScreens = false |
45 |
| -
|
46 |
| - // Normally fetched in builder/src/pages/builder/app/[application]/_layout.svelte |
47 |
| - const fetchScreens = async (appId: string | undefined) => { |
48 |
| - if (!appId) return |
49 |
| -
|
50 |
| - const pkg = await API.fetchAppPackage(appId) |
51 |
| - noScreens = pkg.screens.length === 0 |
52 |
| - } |
53 |
| -
|
54 |
| - $: fetchScreens(app?.devId) |
55 |
| -
|
56 |
| - const receiveMessage = async (message: MessageEvent) => { |
57 |
| - if (message.data.type === "docLoaded") { |
58 |
| - loading = false |
59 |
| - } |
60 |
| - } |
61 |
| -
|
62 |
| - onMount(() => { |
63 |
| - window.addEventListener("message", receiveMessage) |
64 |
| - }) |
65 |
| -
|
66 |
| - onDestroy(() => { |
67 |
| - window.removeEventListener("message", receiveMessage) |
68 |
| - }) |
69 |
| -
|
70 |
| - const openContextMenu = (e: MouseEvent) => { |
71 |
| - e.preventDefault() |
72 |
| - e.stopPropagation() |
73 |
| -
|
74 |
| - const items = getAppContextMenuItems({ |
75 |
| - app, |
76 |
| - onDuplicate: appContextMenuModals.showDuplicateModal, |
77 |
| - onExportDev: appContextMenuModals.showExportDevModal, |
78 |
| - onExportProd: appContextMenuModals.showExportProdModal, |
79 |
| - onDelete: appContextMenuModals.showDeleteModal, |
80 |
| - }) |
81 |
| -
|
82 |
| - contextMenuStore.open(`${app.appId}-view`, items, { |
83 |
| - x: e.clientX, |
84 |
| - y: e.clientY, |
85 |
| - }) |
86 |
| - } |
| 4 | + $redirect("../") |
87 | 5 | </script>
|
88 |
| - |
89 |
| -<!-- svelte-ignore a11y-click-events-have-key-events --> |
90 |
| -<!-- svelte-ignore a11y-no-static-element-interactions --> |
91 |
| -<div class="container"> |
92 |
| - <div class="header"> |
93 |
| - {#if $sideBarCollapsed} |
94 |
| - <div class="headerButton" on:click={() => sideBarCollapsed.set(false)}> |
95 |
| - <Icon |
96 |
| - name="sidebar" |
97 |
| - hoverable |
98 |
| - tooltip="Expand" |
99 |
| - tooltipPosition={TooltipPosition.Right} |
100 |
| - tooltipType={TooltipType.Info} |
101 |
| - hoverColor={"var(--ink)"} |
102 |
| - /> |
103 |
| - </div> |
104 |
| - {:else} |
105 |
| - <div class="headerButton" on:click={() => sideBarCollapsed.set(true)}> |
106 |
| - <Icon |
107 |
| - name="sidebar-simple" |
108 |
| - hoverable |
109 |
| - tooltip="Collapse" |
110 |
| - tooltipType={TooltipType.Info} |
111 |
| - tooltipPosition={TooltipPosition.Top} |
112 |
| - hoverColor={"var(--ink)"} |
113 |
| - size="S" |
114 |
| - /> |
115 |
| - </div> |
116 |
| - {/if} |
117 |
| - {#if isBuilder} |
118 |
| - <Button |
119 |
| - size="M" |
120 |
| - secondary |
121 |
| - on:click={() => $goto(`/builder/app/${app.devId}`)} |
122 |
| - > |
123 |
| - Edit |
124 |
| - </Button> |
125 |
| - {/if} |
126 |
| - <div class="headerButton"> |
127 |
| - <FavouriteAppButton {app} /> |
128 |
| - </div> |
129 |
| - <div class="headerButton" on:click={() => window.open(iframeUrl, "_blank")}> |
130 |
| - <Icon |
131 |
| - name="arrow-square-out" |
132 |
| - disabled={noScreens} |
133 |
| - hoverable |
134 |
| - tooltip="Open in new tab" |
135 |
| - tooltipType={TooltipType.Info} |
136 |
| - tooltipPosition={TooltipPosition.Top} |
137 |
| - hoverColor={"var(--ink)"} |
138 |
| - size="S" |
139 |
| - /> |
140 |
| - </div> |
141 |
| - <Icon |
142 |
| - color={`${app.appId}-view` === $contextMenuStore.id |
143 |
| - ? "var(--hover-color)" |
144 |
| - : undefined} |
145 |
| - on:contextmenu={openContextMenu} |
146 |
| - on:click={openContextMenu} |
147 |
| - size="S" |
148 |
| - hoverable |
149 |
| - name="dots-three" |
150 |
| - /> |
151 |
| - </div> |
152 |
| - {#if noScreens} |
153 |
| - <div class="noScreens"> |
154 |
| - <ErrorSVG /> |
155 |
| - <Body>You haven't added any screens to your app yet.</Body> |
156 |
| - <Body> |
157 |
| - <Link size="L" href={`/builder/app/${app.devId}/design`} |
158 |
| - >Click here</Link |
159 |
| - > to add some. |
160 |
| - </Body> |
161 |
| - </div> |
162 |
| - {:else} |
163 |
| - <div |
164 |
| - class:hide={!loading || !app?.features?.skeletonLoader} |
165 |
| - class="loading" |
166 |
| - > |
167 |
| - <div class="loadingThemeWrapper {getThemeClassNames(app.theme)}"> |
168 |
| - <ClientAppSkeleton |
169 |
| - noAnimation |
170 |
| - hideDevTools={app?.status === "published"} |
171 |
| - sideNav={app?.navigation?.navigation === "Left"} |
172 |
| - hideFooter={$licensing.brandingEnabled} |
173 |
| - /> |
174 |
| - </div> |
175 |
| - </div> |
176 |
| - <iframe |
177 |
| - class:hide={loading && app?.features?.skeletonLoader} |
178 |
| - src={iframeUrl} |
179 |
| - title={app.name} |
180 |
| - /> |
181 |
| - {/if} |
182 |
| -</div> |
183 |
| -<AppContextMenuModals {app} bind:this={appContextMenuModals} /> |
184 |
| - |
185 |
| -<style> |
186 |
| - .headerButton { |
187 |
| - color: var(--grey-7); |
188 |
| - cursor: pointer; |
189 |
| - } |
190 |
| -
|
191 |
| - .headerButton:hover { |
192 |
| - color: var(--ink); |
193 |
| - } |
194 |
| -
|
195 |
| - .container { |
196 |
| - flex: 1 1 auto; |
197 |
| - display: flex; |
198 |
| - flex-direction: column; |
199 |
| - justify-content: flex-start; |
200 |
| - align-items: stretch; |
201 |
| - padding: 0 var(--spacing-l) var(--spacing-l) var(--spacing-l); |
202 |
| - } |
203 |
| -
|
204 |
| - .header { |
205 |
| - display: flex; |
206 |
| - justify-content: flex-start; |
207 |
| - align-items: center; |
208 |
| - gap: var(--spacing-xl); |
209 |
| - flex: 0 0 50px; |
210 |
| - } |
211 |
| -
|
212 |
| - .loading { |
213 |
| - height: 100%; |
214 |
| - border: 1px solid var(--spectrum-global-color-gray-300); |
215 |
| - border-radius: var(--spacing-s); |
216 |
| - overflow: hidden; |
217 |
| - } |
218 |
| - .loadingThemeWrapper { |
219 |
| - height: 100%; |
220 |
| - container-type: inline-size; |
221 |
| - } |
222 |
| -
|
223 |
| - .hide { |
224 |
| - visibility: hidden; |
225 |
| - height: 0; |
226 |
| - border: none; |
227 |
| - } |
228 |
| -
|
229 |
| - iframe { |
230 |
| - flex: 1 1 auto; |
231 |
| - border-radius: var(--spacing-s); |
232 |
| - border: 1px solid var(--spectrum-global-color-gray-300); |
233 |
| - } |
234 |
| -
|
235 |
| - .noScreens { |
236 |
| - width: 100%; |
237 |
| - height: 100%; |
238 |
| - display: flex; |
239 |
| - align-items: center; |
240 |
| - justify-content: center; |
241 |
| - flex-direction: column; |
242 |
| - padding: 20px; |
243 |
| - box-sizing: border-box; |
244 |
| - } |
245 |
| -
|
246 |
| - .noScreens :global(svg) { |
247 |
| - width: 100px; |
248 |
| - height: 100px; |
249 |
| - margin-bottom: 10px; |
250 |
| - } |
251 |
| -</style> |
0 commit comments