Skip to content

Commit

Permalink
feat: add hub support for apps
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenfiszel committed Jan 7, 2023
1 parent b5edb7e commit 50453ca
Show file tree
Hide file tree
Showing 24 changed files with 500 additions and 111 deletions.
69 changes: 69 additions & 0 deletions backend/windmill-api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1769,6 +1769,75 @@ paths:
flow:
$ref: "../../openflow.openapi.yaml#/components/schemas/OpenFlow"

/apps/hub/list:
get:
summary: list all available hub apps
operationId: listHubApps
tags:
- app
responses:
"200":
description: hub apps list
content:
application/json:
schema:
type: object
properties:
apps:
type: array
items:
type: object
properties:
id:
type: number
app_id:
type: number
summary:
type: string
apps:
type: array
items:
type: string
approved:
type: boolean
votes:
type: number
required:
- id
- app_id
- summary
- apps
- approved
- votes

/apps/hub/get/{id}:
get:
summary: get hub app by id
operationId: getHubAppById
tags:
- app
parameters:
- $ref: "#/components/parameters/PathId"
responses:
"200":
description: app
content:
application/json:
schema:
type: object
properties:
app:
type: object
properties:
summary:
type: string
value: {}
required:
- summary
- value
required:
- app

/scripts/hub/get/{path}:
get:
summary: get hub script content by path
Expand Down
42 changes: 41 additions & 1 deletion backend/windmill-api/src/apps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use axum::{
};
use hyper::StatusCode;
use magic_crypt::MagicCryptTrait;
use reqwest::Client;
use serde::{Deserialize, Serialize};
use serde_json::{json, Map, Value};
use sha2::{Digest, Sha256};
Expand All @@ -31,7 +32,9 @@ use windmill_common::{
apps::ListAppQuery,
error::{to_anyhow, Error, JsonResult, Result},
users::owner_to_token_owner,
utils::{not_found_if_none, paginate, Pagination, StripPath},
utils::{
http_get_from_hub, list_elems_from_hub, not_found_if_none, paginate, Pagination, StripPath,
},
};
use windmill_queue::{push, JobPayload, RawCode};

Expand All @@ -53,6 +56,12 @@ pub fn unauthed_service() -> Router {
.route("/public_app/:secret", get(get_public_app_by_secret))
}

pub fn global_service() -> Router {
Router::new()
.route("/hub/list", get(list_hub_apps))
.route("/hub/get/:id", get(get_hub_app_by_id))
}

#[derive(FromRow, Deserialize, Serialize)]
pub struct ListableApp {
pub id: i64,
Expand Down Expand Up @@ -352,6 +361,37 @@ async fn create_app(
Ok((StatusCode::CREATED, app.path))
}

async fn list_hub_apps(
Authed { email, .. }: Authed,
Extension(http_client): Extension<Client>,
) -> JsonResult<serde_json::Value> {
let flows = list_elems_from_hub(
http_client,
"https://hub.windmill.dev/searchUiData?approved=true",
&email,
)
.await?;
Ok(Json(flows))
}

pub async fn get_hub_app_by_id(
Authed { email, .. }: Authed,
Path(id): Path<i32>,
Extension(http_client): Extension<Client>,
) -> JsonResult<serde_json::Value> {
let value = http_get_from_hub(
http_client,
&format!("https://hub.windmill.dev/apps/{id}/json"),
&email,
false,
)
.await?
.json()
.await
.map_err(to_anyhow)?;
Ok(Json(value))
}

async fn delete_app(
authed: Authed,
Extension(user_db): Extension<UserDB>,
Expand Down
1 change: 1 addition & 0 deletions backend/windmill-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ pub async fn run_server(
.nest("/workers", worker_ping::global_service())
.nest("/scripts", scripts::global_service())
.nest("/flows", flows::global_service())
.nest("/apps", apps::global_service())
.nest("/schedules", schedule::global_service())
.route_layer(from_extractor::<Authed>())
.route_layer(from_extractor::<users::Tokened>())
Expand Down
14 changes: 4 additions & 10 deletions frontend/src/lib/components/apps/components/form/AppForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
let runnableComponent: RunnableComponent
let isLoading: boolean = false
let ownClick: boolean = false
$: outputs = $worldStore?.outputsById[id] as {
result: Output<Array<any>>
Expand All @@ -40,20 +39,16 @@
$: outputs?.loading.subscribe({
next: (value) => {
isLoading = value
if (ownClick && !value) {
ownClick = false
}
}
})
$: loading = isLoading && ownClick
</script>

<InputValue {id} input={configuration.label} bind:value={labelValue} />
<InputValue {id} input={configuration.color} bind:value={color} />
<InputValue {id} input={configuration.size} bind:value={size} />

<RunnableWrapper
noMinH
bind:runnableComponent
bind:componentInput
{id}
Expand All @@ -62,7 +57,7 @@
forceSchemaDisplay={true}
>
<AlignWrapper {horizontalAlignment}>
<div class="flex flex-col gap-2 px-4 w-full">
<div class="flex flex-col gap-2 px-4 w-full ">
<div>
{#if componentInput?.type != 'runnable' || Object.values(componentInput?.fields ?? {}).filter((x) => x.type == 'user').length == 0}
<span class="text-gray-600 italic text-sm py-2">
Expand All @@ -73,14 +68,13 @@
</div>
<div class="flex justify-end">
<Button
{loading}
btnClasses="mt-1"
loading={isLoading}
btnClasses="my-1"
on:pointerdown={(e) => {
e?.stopPropagation()
window.dispatchEvent(new Event('pointerup'))
}}
on:click={() => {
ownClick = true
runnableComponent?.runComponent()

if (recomputeIds) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import SchemaForm from '$lib/components/SchemaForm.svelte'
import TestJobLoader from '$lib/components/TestJobLoader.svelte'
import { AppService, type CompletedJob } from '$lib/gen'
import { defaultIfEmptyString, emptySchema } from '$lib/utils'
import { defaultIfEmptyString, emptySchema, sendUserToast } from '$lib/utils'
import { getContext, onMount } from 'svelte'
import type { AppInputs, Runnable } from '../../inputType'
import type { Output } from '../../rx'
Expand All @@ -21,16 +21,17 @@
export let autoRefresh: boolean = true
export let result: any = undefined
export let forceSchemaDisplay: boolean = false
export let noMinH = false
const { worldStore, runnableComponents, workspace, appPath, isEditor, jobs } =
const { worldStore, runnableComponents, workspace, appPath, isEditor, jobs, noBackend } =
getContext<AppEditorContext>('AppEditorContext')
onMount(() => {
if (autoRefresh) {
$runnableComponents[id] = async () => {
await executeComponent()
await executeComponent(true)
}
executeComponent()
executeComponent(true)
}
})
Expand All @@ -43,7 +44,7 @@
function setDebouncedExecute() {
executeTimeout && clearTimeout(executeTimeout)
executeTimeout = setTimeout(() => {
executeComponent()
executeComponent(true)
}, 200)
}
Expand Down Expand Up @@ -176,7 +177,13 @@
[]
)
async function executeComponent() {
async function executeComponent(noToast = false) {
if (noBackend) {
if (!noToast) {
sendUserToast('This app is not connected to a windmill backend, it is a static preview')
}
return
}
if (runnable?.type === 'runnableByName' && !runnable.inlineScript) {
return
}
Expand Down Expand Up @@ -294,7 +301,7 @@
<slot />
</div>
{:else}
<div class="grow min-w-1/2 min-h-[66%]">
<div class="grow min-w-1/2 {noMinH ? '' : 'min-h-[66%]'}">
<slot />
</div>
{/if}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
<script lang="ts">
import { getContext, onMount } from 'svelte'
import type { AppInput } from '../../inputType'
import type { AppEditorContext } from '../../types'
import { isScriptByNameDefined, isScriptByPathDefined } from '../../utils'
import NonRunnableComponent from './NonRunnableComponent.svelte'
import RunnableComponent from './RunnableComponent.svelte'
export let componentInput: AppInput | undefined
export let id: string
export let result: any = undefined
export let noMinH = false
export let extraQueryParams: Record<string, any> = {}
export let autoRefresh: boolean = true
export let runnableComponent: RunnableComponent | undefined = undefined
export let forceSchemaDisplay: boolean = false
const { staticExporter, noBackend } = getContext<AppEditorContext>('AppEditorContext')
if (noBackend && componentInput?.type == 'runnable') {
result = componentInput?.['value']
}
onMount(() => {
$staticExporter[id] = () => result
})
function isRunnableDefined() {
return isScriptByNameDefined(componentInput) || isScriptByPathDefined(componentInput)
}
Expand All @@ -30,6 +42,7 @@
{id}
{extraQueryParams}
{forceSchemaDisplay}
{noMinH}
>
<slot />
</RunnableComponent>
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/lib/components/apps/editor/AppEditor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@
workspace: $workspaceStore ?? '',
onchange: () => saveDraft(),
isEditor: true,
jobs: writable([])
jobs: writable([]),
staticExporter: writable({}),
noBackend: false
})
let timeout: NodeJS.Timeout | undefined = undefined
Expand Down Expand Up @@ -128,6 +130,7 @@
{policy}
isEditor
{context}
noBackend={false}
/>
{:else}
<SplitPanesWrapper>
Expand Down

0 comments on commit 50453ca

Please sign in to comment.