mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-12 00:06:14 +00:00
feat(frontend): add impersonate api + local resolution of import by lsp v0
This commit is contained in:
@@ -1048,6 +1048,27 @@ paths:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
/users/tokens/impersonate:
|
||||
post:
|
||||
summary: create token to impersonate a user (require superadmin)
|
||||
operationId: createTokenImpersonate
|
||||
tags:
|
||||
- user
|
||||
requestBody:
|
||||
description: new token
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/NewTokenImpersonate"
|
||||
responses:
|
||||
"201":
|
||||
description: token created
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
/users/tokens/delete/{token_prefix}:
|
||||
delete:
|
||||
summary: delete token
|
||||
@@ -2344,6 +2365,24 @@ paths:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
/scripts_u/tokened_raw/{workspace}/{token}/{path}:
|
||||
get:
|
||||
summary: raw script by path with a token (mostly used by lsp to be used with import maps to resolve scripts)
|
||||
operationId: rawScriptByPathTokened
|
||||
tags:
|
||||
- script
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/Token"
|
||||
- $ref: "#/components/parameters/ScriptPath"
|
||||
responses:
|
||||
"200":
|
||||
description: script content
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
/w/{workspace}/scripts/exists/p/{path}:
|
||||
get:
|
||||
summary: exists script by path
|
||||
@@ -4535,6 +4574,12 @@ components:
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
Token:
|
||||
name: token
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
AccountId:
|
||||
name: id
|
||||
in: path
|
||||
@@ -5132,6 +5177,19 @@ components:
|
||||
type: string
|
||||
format: date-time
|
||||
|
||||
NewTokenImpersonate:
|
||||
type: object
|
||||
properties:
|
||||
label:
|
||||
type: string
|
||||
expiration:
|
||||
type: string
|
||||
format: date-time
|
||||
impersonate_email:
|
||||
type: string
|
||||
required:
|
||||
- impersonate_email
|
||||
|
||||
ListableVariable:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
@@ -149,6 +149,7 @@ pub async fn run_server(
|
||||
.nest("/schedules", schedule::global_service())
|
||||
.route_layer(from_extractor::<Authed>())
|
||||
.route_layer(from_extractor::<users::Tokened>())
|
||||
.nest("/scripts_u", scripts::global_unauthed_service())
|
||||
.nest(
|
||||
"/w/:workspace_id/apps_u",
|
||||
apps::unauthed_service()
|
||||
|
||||
@@ -13,7 +13,7 @@ use windmill_parser::MainArgSignature;
|
||||
use crate::{
|
||||
db::{UserDB, DB},
|
||||
schedule::clear_schedule,
|
||||
users::{maybe_refresh_folders, require_owner_of_path, Authed},
|
||||
users::{maybe_refresh_folders, require_owner_of_path, AuthCache, Authed},
|
||||
webhook_util::{WebhookMessage, WebhookShared},
|
||||
HTTP_CLIENT,
|
||||
};
|
||||
@@ -30,6 +30,7 @@ use sqlx::{FromRow, Postgres, Transaction};
|
||||
use std::{
|
||||
collections::hash_map::DefaultHasher,
|
||||
hash::{Hash, Hasher},
|
||||
sync::Arc,
|
||||
};
|
||||
use windmill_common::{
|
||||
error::{Error, JsonResult, Result},
|
||||
@@ -61,6 +62,13 @@ pub fn global_service() -> Router {
|
||||
.route("/hub/get_full/*path", get(get_full_hub_script_by_path))
|
||||
}
|
||||
|
||||
pub fn global_unauthed_service() -> Router {
|
||||
Router::new().route(
|
||||
"/tokened_raw/:workspace/:token/*path",
|
||||
get(get_tokened_raw_script_by_path),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn workspaced_service() -> Router {
|
||||
Router::new()
|
||||
.route("/list", get(list_scripts))
|
||||
@@ -498,6 +506,18 @@ async fn list_paths(
|
||||
Ok(Json(scripts))
|
||||
}
|
||||
|
||||
async fn get_tokened_raw_script_by_path(
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
Path((w_id, token, path)): Path<(String, String, StripPath)>,
|
||||
Extension(cache): Extension<Arc<AuthCache>>,
|
||||
) -> Result<String> {
|
||||
let authed = cache
|
||||
.get_authed(Some(w_id.clone()), &token)
|
||||
.await
|
||||
.ok_or_else(|| Error::NotAuthorized("Invalid token".to_string()))?;
|
||||
return raw_script_by_path(authed, Extension(user_db), Path((w_id, path))).await;
|
||||
}
|
||||
|
||||
async fn raw_script_by_path(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
|
||||
@@ -7,5 +7,6 @@ http://localhost {
|
||||
|
||||
https://localhost {
|
||||
bind {$ADDRESS}
|
||||
reverse_proxy /api/* http://localhost:8000
|
||||
reverse_proxy /ws/* http://localhost:3001
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
import { toSocket, WebSocketMessageReader, WebSocketMessageWriter } from 'vscode-ws-jsonrpc'
|
||||
import { CloseAction, ErrorAction, RequestType } from 'vscode-languageclient'
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
languages.typescript.typescriptDefaults.setModeConfiguration({
|
||||
completionItems: false,
|
||||
definitions: false,
|
||||
@@ -71,19 +70,21 @@
|
||||
import type { DocumentUri, MessageTransports } from 'vscode-languageclient'
|
||||
import { dirtyStore } from './common/confirmationModal/dirtyStore'
|
||||
import { buildWorkerDefinition } from './build_workers'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { UserService } from '$lib/gen'
|
||||
|
||||
let divEl: HTMLDivElement | null = null
|
||||
let editor: meditor.IStandaloneCodeEditor
|
||||
|
||||
export let lang: 'typescript' | 'python' | 'go' | 'shell'
|
||||
export let code: string = ''
|
||||
export let hash: string = randomHash()
|
||||
export let cmdEnterAction: (() => void) | undefined = undefined
|
||||
export let formatAction: (() => void) | undefined = undefined
|
||||
export let automaticLayout = true
|
||||
export let websocketAlive = { pyright: false, black: false, deno: false, go: false }
|
||||
export let shouldBindKey: boolean = true
|
||||
export let fixedOverflowWidgets = true
|
||||
export let path: string = randomHash()
|
||||
|
||||
let websockets: [MonacoLanguageClient, WebSocket][] = []
|
||||
let websocketInterval: NodeJS.Timer | undefined
|
||||
@@ -92,7 +93,8 @@
|
||||
let disposeMethod: () => void | undefined
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const uri = `file:///tmp/monaco/${hash}.${langToExt(lang)}`
|
||||
const uri =
|
||||
lang == 'go' ? `file:///tmp/monaco/${randomHash()}.go` : `file:///${path}.${langToExt(lang)}`
|
||||
|
||||
// if (lang != 'typescript') {
|
||||
buildWorkerDefinition('../../../workers', import.meta.url, false)
|
||||
@@ -286,6 +288,7 @@
|
||||
command = vscode.commands.registerCommand(
|
||||
'deno.cache',
|
||||
(uris: DocumentUri[] = []) => {
|
||||
console.log('cache', uris)
|
||||
languageClient.sendRequest(new RequestType('deno/cache'), {
|
||||
referrer: { uri },
|
||||
uris: uris.map((uri) => ({ uri }))
|
||||
@@ -306,6 +309,36 @@
|
||||
|
||||
const wsProtocol = $page.url.protocol == 'https:' ? 'wss' : 'ws'
|
||||
if (lang == 'typescript') {
|
||||
let expiration = new Date()
|
||||
expiration.setHours(expiration.getHours() + 2)
|
||||
const token = await UserService.createToken({
|
||||
requestBody: { label: 'Ephemeral lsp token', expiration: expiration.toISOString() }
|
||||
})
|
||||
let root =
|
||||
$page.url.protocol +
|
||||
'//' +
|
||||
$page.url.host +
|
||||
'/api/scripts_u/tokened_raw/' +
|
||||
$workspaceStore +
|
||||
'/' +
|
||||
token
|
||||
const importMap = {
|
||||
imports: {
|
||||
'file:///': root + '/'
|
||||
}
|
||||
}
|
||||
let path_splitted = path.split('/')
|
||||
for (let c = 0; c < path_splitted.length; c++) {
|
||||
let key = 'file://./'
|
||||
for (let i = 0; i < c; i++) {
|
||||
key += '../'
|
||||
}
|
||||
let url = path_splitted.slice(0, -c - 1).join('/')
|
||||
let ending = c == path_splitted.length - 1 ? '' : '/'
|
||||
importMap['imports'][key] = `${root}/${url}${ending}`
|
||||
}
|
||||
console.log(importMap)
|
||||
const encodedImportMap = 'data:text/plain;base64,' + btoa(JSON.stringify(importMap))
|
||||
await connectToLanguageServer(
|
||||
`${wsProtocol}://${$page.url.host}/ws/deno`,
|
||||
'deno',
|
||||
@@ -313,7 +346,7 @@
|
||||
certificateStores: null,
|
||||
enablePaths: [],
|
||||
config: null,
|
||||
importMap: null,
|
||||
importMap: encodedImportMap,
|
||||
internalDebug: false,
|
||||
lint: false,
|
||||
path: null,
|
||||
@@ -321,7 +354,6 @@
|
||||
unsafelyIgnoreCertificateErrors: null,
|
||||
unstable: true,
|
||||
enable: true,
|
||||
cache: null,
|
||||
codeLens: {
|
||||
implementations: true,
|
||||
references: true,
|
||||
@@ -340,7 +372,13 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
undefined
|
||||
() => {
|
||||
return [
|
||||
{
|
||||
enable: true
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
} else if (lang === 'python') {
|
||||
await connectToLanguageServer(
|
||||
|
||||
@@ -149,6 +149,7 @@
|
||||
<div class="pl-2 h-full !overflow-visible">
|
||||
{#key lang}
|
||||
<Editor
|
||||
{path}
|
||||
bind:code
|
||||
bind:websocketAlive
|
||||
bind:this={editor}
|
||||
|
||||
@@ -216,6 +216,7 @@
|
||||
<div class="border h-full">
|
||||
{#if inlineScript.language != 'frontend'}
|
||||
<Editor
|
||||
path={inlineScript.path}
|
||||
bind:this={editor}
|
||||
class="flex flex-1 grow h-full"
|
||||
lang={scriptLangToEditorLang(inlineScript?.language)}
|
||||
|
||||
@@ -180,6 +180,7 @@
|
||||
<Pane size={isScript ? 30 : 50} minSize={20}>
|
||||
{#if value.type === 'rawscript'}
|
||||
<Editor
|
||||
path={value['path']}
|
||||
bind:websocketAlive
|
||||
bind:this={editor}
|
||||
class="h-full relative"
|
||||
|
||||
Vendored
-1
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 17 KiB |
@@ -30,6 +30,7 @@ class LanguageServerWebSocketHandler(websocket.WebSocketHandler):
|
||||
# Create an instance of the language server
|
||||
self.proc = process.Subprocess(
|
||||
self.procargs,
|
||||
env=os.environ,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
)
|
||||
@@ -85,7 +86,6 @@ class MainHandler(web.RequestHandler):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
monaco_path = "/tmp/monaco"
|
||||
os.makedirs(monaco_path, exist_ok=True)
|
||||
print("The monaco directory is created!")
|
||||
|
||||
Reference in New Issue
Block a user