mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-25 08:00:59 +00:00
fix: script fix no resource + error handling (#2053)
This commit is contained in:
@@ -9,6 +9,7 @@ use axum::{
|
||||
Router,
|
||||
};
|
||||
use magic_crypt::MagicCryptTrait;
|
||||
use serde_json::json;
|
||||
use windmill_audit::{audit_log, ActionKind};
|
||||
use windmill_common::error::{to_anyhow, Error};
|
||||
|
||||
@@ -26,6 +27,17 @@ struct OpenaiResource {
|
||||
organization_id: Option<String>,
|
||||
}
|
||||
|
||||
fn create_openai_json_error(msg: String) -> Error {
|
||||
Error::OpenAIError(
|
||||
serde_json::to_string(&json!({
|
||||
"error": {
|
||||
"message": msg
|
||||
}
|
||||
}))
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
struct Variable {
|
||||
value: String,
|
||||
is_secret: bool,
|
||||
@@ -72,7 +84,7 @@ async fn proxy(
|
||||
tx.commit().await?;
|
||||
|
||||
if openai_resource_path.is_none() {
|
||||
return Err(Error::InternalErr(
|
||||
return Err(create_openai_json_error(
|
||||
"OpenAI resource not configured".to_string(),
|
||||
));
|
||||
}
|
||||
@@ -92,7 +104,7 @@ async fn proxy(
|
||||
tx.commit().await?;
|
||||
|
||||
if resource.is_none() {
|
||||
return Err(Error::InternalErr(
|
||||
return Err(create_openai_json_error(
|
||||
"OpenAI resource missing value".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
@@ -64,6 +64,8 @@ pub enum Error {
|
||||
JsonErr(serde_json::Value),
|
||||
#[error("Custom Status Code: {0:#?}")]
|
||||
CustomStatusCode(StatusCode, serde_json::Value),
|
||||
#[error("{0}")]
|
||||
OpenAIError(String),
|
||||
}
|
||||
|
||||
impl Error {
|
||||
@@ -87,7 +89,9 @@ impl IntoResponse for Error {
|
||||
Self::NotAuthorized(_) => axum::http::StatusCode::UNAUTHORIZED,
|
||||
Self::RequireAdmin(_) => axum::http::StatusCode::FORBIDDEN,
|
||||
Self::CustomStatusCode(code, _) => code,
|
||||
Self::SqlErr(_) | Self::BadRequest(_) => axum::http::StatusCode::BAD_REQUEST,
|
||||
Self::SqlErr(_) | Self::BadRequest(_) | Self::OpenAIError(_) => {
|
||||
axum::http::StatusCode::BAD_REQUEST
|
||||
}
|
||||
_ => axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
};
|
||||
tracing::error!(error = e.to_string());
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
import type DiffEditor from '../DiffEditor.svelte'
|
||||
import { scriptLangToEditorLang } from '$lib/scripts'
|
||||
import Popover from '../Popover.svelte'
|
||||
import Popup from '../common/popup/Popup.svelte'
|
||||
|
||||
// props
|
||||
export let lang: SupportedLanguage
|
||||
@@ -27,12 +28,6 @@
|
||||
return
|
||||
}
|
||||
try {
|
||||
// close popup ^^
|
||||
const elem = document.activeElement as HTMLElement
|
||||
if (elem.blur) {
|
||||
elem.blur()
|
||||
}
|
||||
|
||||
genLoading = true
|
||||
const result = await fixScript({
|
||||
language: lang,
|
||||
@@ -43,8 +38,12 @@
|
||||
generatedCode = result.code
|
||||
explanation = result.explanation
|
||||
} catch (err) {
|
||||
sendUserToast('Failed to generate code', true)
|
||||
console.error(err)
|
||||
if (err?.message) {
|
||||
sendUserToast('Failed to generate code: ' + err.message, true)
|
||||
} else {
|
||||
sendUserToast('Failed to generate code', true)
|
||||
console.error(err)
|
||||
}
|
||||
} finally {
|
||||
genLoading = false
|
||||
}
|
||||
@@ -80,42 +79,42 @@
|
||||
$: !generatedCode && hideDiff()
|
||||
</script>
|
||||
|
||||
{#if error}
|
||||
{#if existsOpenaiResourcePath && SUPPORTED_LANGUAGES.has(lang)}
|
||||
<div class="mt-2">
|
||||
{#if generatedCode}
|
||||
<div class="flex gap-1">
|
||||
<Button
|
||||
title="Discard generated code"
|
||||
size="xs"
|
||||
color="red"
|
||||
spacingSize="xs2"
|
||||
on:click={rejectDiff}
|
||||
variant="contained"
|
||||
startIcon={{ icon: faClose }}
|
||||
>
|
||||
Discard
|
||||
</Button><Button
|
||||
title="Accept generated code"
|
||||
size="xs"
|
||||
color="green"
|
||||
spacingSize="xs2"
|
||||
on:click={acceptDiff}
|
||||
startIcon={{ icon: faCheck }}
|
||||
>
|
||||
Accept
|
||||
</Button>
|
||||
{#if explanation}
|
||||
<Popover>
|
||||
<svelte:fragment slot="text">{explanation}</svelte:fragment>
|
||||
<Button size="xs" color="light" variant="contained" spacingSize="xs2">Explain</Button
|
||||
></Popover
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
{#if error && SUPPORTED_LANGUAGES.has(lang)}
|
||||
<div class="mt-2">
|
||||
{#if generatedCode}
|
||||
<div class="flex gap-1">
|
||||
<Button
|
||||
title="Generate code from prompt"
|
||||
title="Discard generated code"
|
||||
size="xs"
|
||||
color="red"
|
||||
spacingSize="xs2"
|
||||
on:click={rejectDiff}
|
||||
variant="contained"
|
||||
startIcon={{ icon: faClose }}
|
||||
>
|
||||
Discard
|
||||
</Button><Button
|
||||
title="Accept generated code"
|
||||
size="xs"
|
||||
color="green"
|
||||
spacingSize="xs2"
|
||||
on:click={acceptDiff}
|
||||
startIcon={{ icon: faCheck }}
|
||||
>
|
||||
Accept
|
||||
</Button>
|
||||
{#if explanation}
|
||||
<Popover>
|
||||
<svelte:fragment slot="text">{explanation}</svelte:fragment>
|
||||
<Button size="xs" color="light" variant="contained" spacingSize="xs2">Explain</Button
|
||||
></Popover
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
{#if $existsOpenaiResourcePath}
|
||||
<Button
|
||||
title="Fix code"
|
||||
size="xs"
|
||||
color="blue"
|
||||
spacingSize="xs2"
|
||||
@@ -125,7 +124,29 @@
|
||||
>
|
||||
AI Fix
|
||||
</Button>
|
||||
{/if}</div
|
||||
>
|
||||
{/if}
|
||||
{:else}
|
||||
<Popup floatingConfig={{ placement: 'bottom-end', strategy: 'absolute' }}>
|
||||
<svelte:fragment slot="button">
|
||||
<Button
|
||||
title="Fix code"
|
||||
size="xs"
|
||||
color="blue"
|
||||
spacingSize="xs2"
|
||||
startIcon={{ icon: faMagicWandSparkles }}
|
||||
nonCaptureEvent={true}
|
||||
>
|
||||
AI Fix
|
||||
</Button>
|
||||
</svelte:fragment>
|
||||
<div>
|
||||
<p class="text-sm"
|
||||
>Enable Windmill AI in the <a href="/workspace_settings?tab=openai"
|
||||
>workspace settings.</a
|
||||
></p
|
||||
>
|
||||
</div>
|
||||
</Popup>
|
||||
{/if}
|
||||
{/if}</div
|
||||
>
|
||||
{/if}
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
// state
|
||||
let funcDesc: string = ''
|
||||
let genLoading: boolean = false
|
||||
let button: HTMLButtonElement | undefined
|
||||
let input: HTMLInputElement | undefined
|
||||
let generatedCode = ''
|
||||
let selection: Selection | undefined
|
||||
@@ -59,8 +58,12 @@
|
||||
}
|
||||
funcDesc = ''
|
||||
} catch (err) {
|
||||
sendUserToast('Failed to generate code', true)
|
||||
console.error(err)
|
||||
if (err?.message) {
|
||||
sendUserToast('Failed to generate code: ' + err.message, true)
|
||||
} else {
|
||||
sendUserToast('Failed to generate code', true)
|
||||
console.error(err)
|
||||
}
|
||||
} finally {
|
||||
genLoading = false
|
||||
}
|
||||
@@ -162,7 +165,6 @@
|
||||
{#if inlineScript}
|
||||
<Button
|
||||
size="lg"
|
||||
bind:element={button}
|
||||
color="light"
|
||||
btnClasses="!px-2 !bg-surface-secondary hover:!bg-surface-hover"
|
||||
loading={genLoading}
|
||||
@@ -177,7 +179,6 @@
|
||||
size="xs"
|
||||
color="light"
|
||||
spacingSize="md"
|
||||
bind:element={button}
|
||||
startIcon={{ icon: faMagicWandSparkles }}
|
||||
{iconOnly}
|
||||
loading={genLoading}
|
||||
|
||||
Reference in New Issue
Block a user