mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-21 08:02:26 +00:00
feat: add update checker on version info
This commit is contained in:
@@ -41,6 +41,20 @@ paths:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
/uptodate:
|
||||
get:
|
||||
summary: is backend up to date
|
||||
operationId: backendUptodate
|
||||
tags:
|
||||
- settings
|
||||
responses:
|
||||
"200":
|
||||
description: is backend up to date
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
/ee_license:
|
||||
get:
|
||||
summary: get license id
|
||||
|
||||
@@ -30,6 +30,8 @@ use tower_http::{
|
||||
};
|
||||
use windmill_common::utils::rd_string;
|
||||
|
||||
use windmill_common::error::AppError;
|
||||
|
||||
mod apps;
|
||||
mod audit;
|
||||
mod capture;
|
||||
@@ -189,6 +191,7 @@ pub async fn run_server(
|
||||
)
|
||||
.nest("/oauth", oauth2::global_service())
|
||||
.route("/version", get(git_v))
|
||||
.route("/uptodate", get(is_up_to_date))
|
||||
.route("/ee_license", get(ee_license))
|
||||
.route("/openapi.yaml", get(openapi)),
|
||||
)
|
||||
@@ -211,6 +214,31 @@ pub async fn run_server(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn is_up_to_date() -> Result<String, AppError> {
|
||||
let error_reading_version = || anyhow::anyhow!("Error reading latest released version");
|
||||
let version = HTTP_CLIENT
|
||||
.get("https://api.github.com/repos/windmill-labs/windmill/releases/latest")
|
||||
.send()
|
||||
.await?
|
||||
.json::<serde_json::Value>()
|
||||
.await?
|
||||
.get("tag_name")
|
||||
.ok_or_else(error_reading_version)?
|
||||
.as_str()
|
||||
.ok_or_else(error_reading_version)?
|
||||
.to_string();
|
||||
let release = GIT_VERSION
|
||||
.split('-')
|
||||
.next()
|
||||
.ok_or_else(error_reading_version)?
|
||||
.to_string();
|
||||
if version == release {
|
||||
Ok("yes".to_string())
|
||||
} else {
|
||||
Ok(format!("Update: {GIT_VERSION} -> {version}"))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
async fn git_v() -> String {
|
||||
format!("EE {GIT_VERSION}")
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* LICENSE-AGPL for a copy of the license.
|
||||
*/
|
||||
|
||||
use axum::response::Response;
|
||||
#[cfg(feature = "axum")]
|
||||
use axum::{
|
||||
body::{self, BoxBody},
|
||||
@@ -107,3 +108,28 @@ impl<T> OrElseNotFound<T> for Option<T> {
|
||||
self.ok_or_else(|| Error::NotFound(s.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
// Make our own error that wraps `anyhow::Error`.
|
||||
pub struct AppError(anyhow::Error);
|
||||
|
||||
// Tell axum how to convert `AppError` into a response.
|
||||
impl IntoResponse for AppError {
|
||||
fn into_response(self) -> Response {
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Something went wrong: {}", self.0),
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
}
|
||||
|
||||
// This enables using `?` on functions that return `Result<_, anyhow::Error>` to turn them into
|
||||
// `Result<_, AppError>`. That way you don't need to do that manually.
|
||||
impl<E> From<E> for AppError
|
||||
where
|
||||
E: Into<anyhow::Error>,
|
||||
{
|
||||
fn from(err: E) -> Self {
|
||||
Self(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { SettingsService } from '$lib/gen'
|
||||
import { onMount } from 'svelte'
|
||||
import WindmillIcon from './icons/WindmillIcon.svelte'
|
||||
import Uptodate from './Uptodate.svelte'
|
||||
import Version from './Version.svelte'
|
||||
|
||||
export let subtitle: string | undefined = undefined
|
||||
export let title = 'Windmill'
|
||||
export let disableLogo = false
|
||||
let version = ''
|
||||
|
||||
onMount(async () => {
|
||||
version = await SettingsService.backendVersion()
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="center-center min-h-screen p-4 relative bg-gray-50">
|
||||
@@ -42,7 +37,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="absolute top-0 right-0 text-2xs text-gray-800 italic px-3 py-1">
|
||||
<span class="font-mono">{version}</span>
|
||||
<div class="absolute top-0 right-0 text-2xs text-gray-600 italic px-3 py-1">
|
||||
<span class="font-mono flex flex-col">
|
||||
<div>Windmill <Version /></div><div><Uptodate /></div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { UserService, SettingsService, GlobalUserInfo } from '$lib/gen'
|
||||
import { UserService, GlobalUserInfo } from '$lib/gen'
|
||||
import TableCustom from '$lib/components/TableCustom.svelte'
|
||||
import PageHeader from '$lib/components/PageHeader.svelte'
|
||||
import InviteGlobalUser from '$lib/components/InviteGlobalUser.svelte'
|
||||
@@ -8,12 +8,13 @@
|
||||
import SearchItems from './SearchItems.svelte'
|
||||
import { page } from '$app/stores'
|
||||
import { goto } from '$app/navigation'
|
||||
import Version from './Version.svelte'
|
||||
import Uptodate from './Uptodate.svelte'
|
||||
|
||||
let drawer: Drawer
|
||||
let filter = ''
|
||||
|
||||
export function openDrawer() {
|
||||
loadVersion()
|
||||
listUsers()
|
||||
drawer?.openDrawer?.()
|
||||
}
|
||||
@@ -30,14 +31,9 @@
|
||||
goto(hashRemoved)
|
||||
}
|
||||
|
||||
let version: string | undefined
|
||||
let users: GlobalUserInfo[] = []
|
||||
let filteredUsers: GlobalUserInfo[] = []
|
||||
|
||||
async function loadVersion(): Promise<void> {
|
||||
version = await SettingsService.backendVersion()
|
||||
}
|
||||
|
||||
async function listUsers(): Promise<void> {
|
||||
users = await UserService.listUsersAsSuperAdmin({ perPage: 100000 })
|
||||
}
|
||||
@@ -54,8 +50,8 @@
|
||||
<DrawerContent overflow_y={false} title="Superadmin Settings" on:close={closeDrawer}>
|
||||
<div class="flex flex-col h-full">
|
||||
<div>
|
||||
<div class="text-xs pt-1 text-gray-500">
|
||||
Windmill {version}
|
||||
<div class="text-xs pt-1 text-gray-500 flex flex-col">
|
||||
<div>Windmill <Version /></div><div><Uptodate /></div>
|
||||
</div>
|
||||
|
||||
<PageHeader title="All global users" primary={false} />
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<script lang="ts">
|
||||
import { SettingsService } from '$lib/gen'
|
||||
import Tooltip from './Tooltip.svelte'
|
||||
|
||||
let uptodate: string | undefined = undefined
|
||||
|
||||
loadVersion()
|
||||
|
||||
async function loadVersion() {
|
||||
try {
|
||||
const res = await SettingsService.backendUptodate()
|
||||
console.log(res)
|
||||
if (res != 'yes') {
|
||||
uptodate = res
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Could not fetch latest version', e)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if uptodate}
|
||||
<span class="text-blue-400"
|
||||
>{uptodate} <Tooltip>
|
||||
How to update?<br />
|
||||
- docker: `docker compose up`<br />-
|
||||
<a href="https://github.com/windmill-labs/windmill-helm-charts#install">helm</a>
|
||||
</Tooltip></span
|
||||
>
|
||||
{/if}
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { usersWorkspaceStore } from '$lib/stores'
|
||||
import type { TruncatedToken, NewToken } from '$lib/gen'
|
||||
import { UserService, SettingsService } from '$lib/gen'
|
||||
import { UserService } from '$lib/gen'
|
||||
import { displayDate, copyToClipboard } from '$lib/utils'
|
||||
import { faClipboard, faPlus } from '@fortawesome/free-solid-svg-icons'
|
||||
import TableCustom from '$lib/components/TableCustom.svelte'
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
let newPassword: string | undefined
|
||||
let passwordError: string | undefined
|
||||
let version: string | undefined
|
||||
let tokens: TruncatedToken[]
|
||||
let newToken: string | undefined
|
||||
let newTokenLabel: string | undefined
|
||||
@@ -26,11 +25,11 @@
|
||||
import { goto } from '$app/navigation'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import Tooltip from './Tooltip.svelte'
|
||||
import Version from './Version.svelte'
|
||||
|
||||
let drawer: Drawer
|
||||
|
||||
export function openDrawer() {
|
||||
loadVersion()
|
||||
loadLoginType()
|
||||
listTokens()
|
||||
drawer?.openDrawer()
|
||||
@@ -60,9 +59,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function loadVersion(): Promise<void> {
|
||||
version = await SettingsService.backendVersion()
|
||||
}
|
||||
async function loadLoginType(): Promise<void> {
|
||||
login_type = (await UserService.globalWhoami()).login_type
|
||||
}
|
||||
@@ -96,8 +92,8 @@
|
||||
<DrawerContent title="User Settings" on:close={closeDrawer}>
|
||||
<div class="flex flex-col h-full">
|
||||
<div>
|
||||
<div class="text-xs pt-1 pb-2 text-gray-500">
|
||||
Windmill {version}
|
||||
<div class="text-xs pt-1 pb-2 text-gray-500 flex-col flex">
|
||||
Windmill <Version />
|
||||
</div>
|
||||
|
||||
{#if scopes == undefined}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { SettingsService } from '$lib/gen'
|
||||
|
||||
let version = ''
|
||||
|
||||
loadVersion()
|
||||
|
||||
async function loadVersion() {
|
||||
version = await SettingsService.backendVersion()
|
||||
}
|
||||
</script>
|
||||
|
||||
{version}
|
||||
@@ -3,7 +3,7 @@
|
||||
import { page } from '$app/stores'
|
||||
import { faGithub, faGitlab, faGoogle, faMicrosoft } from '@fortawesome/free-brands-svg-icons'
|
||||
import { onMount } from 'svelte'
|
||||
import { OauthService, SettingsService, UserService, WorkspaceService } from '$lib/gen'
|
||||
import { OauthService, UserService, WorkspaceService } from '$lib/gen'
|
||||
import { clearStores, usersWorkspaceStore, workspaceStore, userStore } from '$lib/stores'
|
||||
import { classNames, parseQueryParams } from '$lib/utils'
|
||||
import { getUserExt } from '$lib/user'
|
||||
@@ -12,6 +12,8 @@
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { isCloudHosted } from '$lib/cloud'
|
||||
import { refreshSuperadmin } from '$lib/refreshUser'
|
||||
import Version from '$lib/components/Version.svelte'
|
||||
import Uptodate from '$lib/components/Uptodate.svelte'
|
||||
|
||||
let email = $page.url.searchParams.get('email') ?? ''
|
||||
let password = $page.url.searchParams.get('password') ?? ''
|
||||
@@ -151,17 +153,11 @@
|
||||
$: if (error) {
|
||||
sendUserToast(error, true)
|
||||
}
|
||||
|
||||
let version = ''
|
||||
|
||||
onMount(async () => {
|
||||
version = await SettingsService.backendVersion()
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col justify-center py-12 sm:px-6 lg:px-8 relative bg-gray-50 h-screen">
|
||||
<div class="absolute top-0 right-0 text-2xs text-gray-800 italic px-3 py-1">
|
||||
<span class="font-mono">{version}</span>
|
||||
<div class="font-mono flex-col flex"><Version /><div><Uptodate /></div></div>
|
||||
</div>
|
||||
<div class="sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<div class="mx-auto flex justify-center">
|
||||
|
||||
Reference in New Issue
Block a user