Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
chenpangpang
open-webui
Commits
25336f85
"...composable_kernel_rocm.git" did not exist on "3b945fc97a7585620b93fdf3421f8befc66c6661"
Commit
25336f85
authored
Jun 03, 2024
by
Timothy J. Baek
Browse files
feat: admin details in account pending overlay
parent
61867c15
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
318 additions
and
263 deletions
+318
-263
backend/apps/webui/main.py
backend/apps/webui/main.py
+7
-0
backend/apps/webui/routers/auths.py
backend/apps/webui/routers/auths.py
+60
-45
backend/apps/webui/routers/users.py
backend/apps/webui/routers/users.py
+6
-1
backend/config.py
backend/config.py
+14
-0
backend/main.py
backend/main.py
+1
-17
src/lib/apis/auths/index.ts
src/lib/apis/auths/index.ts
+82
-0
src/lib/components/admin/Settings/General.svelte
src/lib/components/admin/Settings/General.svelte
+82
-161
src/lib/components/layout/Overlay/AccountPending.svelte
src/lib/components/layout/Overlay/AccountPending.svelte
+59
-0
src/routes/(app)/+layout.svelte
src/routes/(app)/+layout.svelte
+7
-39
No files found.
backend/apps/webui/main.py
View file @
25336f85
...
@@ -14,6 +14,8 @@ from apps.webui.routers import (
...
@@ -14,6 +14,8 @@ from apps.webui.routers import (
)
)
from
config
import
(
from
config
import
(
WEBUI_BUILD_HASH
,
WEBUI_BUILD_HASH
,
SHOW_ADMIN_DETAILS
,
ADMIN_EMAIL
,
WEBUI_AUTH
,
WEBUI_AUTH
,
DEFAULT_MODELS
,
DEFAULT_MODELS
,
DEFAULT_PROMPT_SUGGESTIONS
,
DEFAULT_PROMPT_SUGGESTIONS
,
...
@@ -37,6 +39,11 @@ app.state.config = AppConfig()
...
@@ -37,6 +39,11 @@ app.state.config = AppConfig()
app
.
state
.
config
.
ENABLE_SIGNUP
=
ENABLE_SIGNUP
app
.
state
.
config
.
ENABLE_SIGNUP
=
ENABLE_SIGNUP
app
.
state
.
config
.
JWT_EXPIRES_IN
=
JWT_EXPIRES_IN
app
.
state
.
config
.
JWT_EXPIRES_IN
=
JWT_EXPIRES_IN
app
.
state
.
config
.
SHOW_ADMIN_DETAILS
=
SHOW_ADMIN_DETAILS
app
.
state
.
config
.
ADMIN_EMAIL
=
ADMIN_EMAIL
app
.
state
.
config
.
DEFAULT_MODELS
=
DEFAULT_MODELS
app
.
state
.
config
.
DEFAULT_MODELS
=
DEFAULT_MODELS
app
.
state
.
config
.
DEFAULT_PROMPT_SUGGESTIONS
=
DEFAULT_PROMPT_SUGGESTIONS
app
.
state
.
config
.
DEFAULT_PROMPT_SUGGESTIONS
=
DEFAULT_PROMPT_SUGGESTIONS
app
.
state
.
config
.
DEFAULT_USER_ROLE
=
DEFAULT_USER_ROLE
app
.
state
.
config
.
DEFAULT_USER_ROLE
=
DEFAULT_USER_ROLE
...
...
backend/apps/webui/routers/auths.py
View file @
25336f85
...
@@ -270,72 +270,87 @@ async def add_user(form_data: AddUserForm, user=Depends(get_admin_user)):
...
@@ -270,72 +270,87 @@ async def add_user(form_data: AddUserForm, user=Depends(get_admin_user)):
############################
############################
#
ToggleSignUp
#
GetAdminDetails
############################
############################
@
router
.
get
(
"/signup/enabled"
,
response_model
=
bool
)
@
router
.
get
(
"/admin/details"
)
async
def
get_sign_up_status
(
request
:
Request
,
user
=
Depends
(
get_admin_user
)):
async
def
get_admin_details
(
request
:
Request
,
user
=
Depends
(
get_current_user
)):
return
request
.
app
.
state
.
config
.
ENABLE_SIGNUP
if
request
.
app
.
state
.
config
.
SHOW_ADMIN_DETAILS
:
admin_email
=
request
.
app
.
state
.
config
.
ADMIN_EMAIL
admin_name
=
None
print
(
admin_email
,
admin_name
)
if
admin_email
:
admin
=
Users
.
get_user_by_email
(
admin_email
)
if
admin
:
admin_name
=
admin
.
name
else
:
admin
=
Users
.
get_first_user
()
if
admin
:
admin_email
=
admin
.
email
admin_name
=
admin
.
name
@
router
.
get
(
"/signup/enabled/toggle"
,
response_model
=
bool
)
return
{
async
def
toggle_sign_up
(
request
:
Request
,
user
=
Depends
(
get_admin_user
)):
"name"
:
admin_name
,
request
.
app
.
state
.
config
.
ENABLE_SIGNUP
=
not
request
.
app
.
state
.
config
.
ENABLE_SIGNUP
"email"
:
admin_email
,
return
request
.
app
.
state
.
config
.
ENABLE_SIGNUP
}
else
:
raise
HTTPException
(
400
,
detail
=
ERROR_MESSAGES
.
ACTION_PROHIBITED
)
############################
############################
#
Default User Role
#
ToggleSignUp
############################
############################
@
router
.
get
(
"/signup/user/role"
)
@
router
.
get
(
"/admin/config"
)
async
def
get_default_user_role
(
request
:
Request
,
user
=
Depends
(
get_admin_user
)):
async
def
get_admin_config
(
request
:
Request
,
user
=
Depends
(
get_admin_user
)):
return
request
.
app
.
state
.
config
.
DEFAULT_USER_ROLE
return
{
"SHOW_ADMIN_DETAILS"
:
request
.
app
.
state
.
config
.
SHOW_ADMIN_DETAILS
,
"ENABLE_SIGNUP"
:
request
.
app
.
state
.
config
.
ENABLE_SIGNUP
,
"DEFAULT_USER_ROLE"
:
request
.
app
.
state
.
config
.
DEFAULT_USER_ROLE
,
"JWT_EXPIRES_IN"
:
request
.
app
.
state
.
config
.
JWT_EXPIRES_IN
,
"ENABLE_COMMUNITY_SHARING"
:
request
.
app
.
state
.
config
.
ENABLE_COMMUNITY_SHARING
,
}
class
UpdateRoleForm
(
BaseModel
):
class
AdminConfig
(
BaseModel
):
role
:
str
SHOW_ADMIN_DETAILS
:
bool
ENABLE_SIGNUP
:
bool
DEFAULT_USER_ROLE
:
str
JWT_EXPIRES_IN
:
str
ENABLE_COMMUNITY_SHARING
:
bool
@
router
.
post
(
"/
signup/user/role
"
)
@
router
.
post
(
"/
admin/config
"
)
async
def
update_
default_user_role
(
async
def
update_
admin_config
(
request
:
Request
,
form_data
:
UpdateRoleForm
,
user
=
Depends
(
get_admin_user
)
request
:
Request
,
form_data
:
AdminConfig
,
user
=
Depends
(
get_admin_user
)
):
):
if
form_data
.
role
in
[
"pending"
,
"user"
,
"admin"
]:
request
.
app
.
state
.
config
.
SHOW_ADMIN_DETAILS
=
form_data
.
SHOW_ADMIN_DETAILS
request
.
app
.
state
.
config
.
DEFAULT_USER_ROLE
=
form_data
.
role
request
.
app
.
state
.
config
.
ENABLE_SIGNUP
=
form_data
.
ENABLE_SIGNUP
return
request
.
app
.
state
.
config
.
DEFAULT_USER_ROLE
############################
# JWT Expiration
############################
@
router
.
get
(
"/token/expires"
)
async
def
get_token_expires_duration
(
request
:
Request
,
user
=
Depends
(
get_admin_user
)):
return
request
.
app
.
state
.
config
.
JWT_EXPIRES_IN
class
UpdateJWTExpiresDurationForm
(
BaseModel
):
duration
:
str
if
form_data
.
DEFAULT_USER_ROLE
in
[
"pending"
,
"user"
,
"admin"
]:
request
.
app
.
state
.
config
.
DEFAULT_USER_ROLE
=
form_data
.
DEFAULT_USER_ROLE
@
router
.
post
(
"/token/expires/update"
)
async
def
update_token_expires_duration
(
request
:
Request
,
form_data
:
UpdateJWTExpiresDurationForm
,
user
=
Depends
(
get_admin_user
),
):
pattern
=
r
"^(-1|0|(-?\d+(\.\d+)?)(ms|s|m|h|d|w))$"
pattern
=
r
"^(-1|0|(-?\d+(\.\d+)?)(ms|s|m|h|d|w))$"
# Check if the input string matches the pattern
# Check if the input string matches the pattern
if
re
.
match
(
pattern
,
form_data
.
duration
):
if
re
.
match
(
pattern
,
form_data
.
JWT_EXPIRES_IN
):
request
.
app
.
state
.
config
.
JWT_EXPIRES_IN
=
form_data
.
duration
request
.
app
.
state
.
config
.
JWT_EXPIRES_IN
=
form_data
.
JWT_EXPIRES_IN
return
request
.
app
.
state
.
config
.
JWT_EXPIRES_IN
else
:
request
.
app
.
state
.
config
.
ENABLE_COMMUNITY_SHARING
=
(
return
request
.
app
.
state
.
config
.
JWT_EXPIRES_IN
form_data
.
ENABLE_COMMUNITY_SHARING
)
return
{
"SHOW_ADMIN_DETAILS"
:
request
.
app
.
state
.
config
.
SHOW_ADMIN_DETAILS
,
"ENABLE_SIGNUP"
:
request
.
app
.
state
.
config
.
ENABLE_SIGNUP
,
"DEFAULT_USER_ROLE"
:
request
.
app
.
state
.
config
.
DEFAULT_USER_ROLE
,
"JWT_EXPIRES_IN"
:
request
.
app
.
state
.
config
.
JWT_EXPIRES_IN
,
"ENABLE_COMMUNITY_SHARING"
:
request
.
app
.
state
.
config
.
ENABLE_COMMUNITY_SHARING
,
}
############################
############################
...
...
backend/apps/webui/routers/users.py
View file @
25336f85
...
@@ -19,7 +19,12 @@ from apps.webui.models.users import (
...
@@ -19,7 +19,12 @@ from apps.webui.models.users import (
from
apps.webui.models.auths
import
Auths
from
apps.webui.models.auths
import
Auths
from
apps.webui.models.chats
import
Chats
from
apps.webui.models.chats
import
Chats
from
utils.utils
import
get_verified_user
,
get_password_hash
,
get_admin_user
from
utils.utils
import
(
get_verified_user
,
get_password_hash
,
get_current_user
,
get_admin_user
,
)
from
constants
import
ERROR_MESSAGES
from
constants
import
ERROR_MESSAGES
from
config
import
SRC_LOG_LEVELS
from
config
import
SRC_LOG_LEVELS
...
...
backend/config.py
View file @
25336f85
...
@@ -601,6 +601,20 @@ WEBUI_BANNERS = PersistentConfig(
...
@@ -601,6 +601,20 @@ WEBUI_BANNERS = PersistentConfig(
[
BannerModel
(
**
banner
)
for
banner
in
json
.
loads
(
"[]"
)],
[
BannerModel
(
**
banner
)
for
banner
in
json
.
loads
(
"[]"
)],
)
)
SHOW_ADMIN_DETAILS
=
PersistentConfig
(
"SHOW_ADMIN_DETAILS"
,
"auth.admin.show"
,
os
.
environ
.
get
(
"SHOW_ADMIN_DETAILS"
,
"true"
).
lower
()
==
"true"
,
)
ADMIN_EMAIL
=
PersistentConfig
(
"ADMIN_EMAIL"
,
"auth.admin.email"
,
os
.
environ
.
get
(
"ADMIN_EMAIL"
,
None
),
)
####################################
####################################
# WEBUI_SECRET_KEY
# WEBUI_SECRET_KEY
####################################
####################################
...
...
backend/main.py
View file @
25336f85
...
@@ -879,23 +879,7 @@ class UrlForm(BaseModel):
...
@@ -879,23 +879,7 @@ class UrlForm(BaseModel):
async
def
update_webhook_url
(
form_data
:
UrlForm
,
user
=
Depends
(
get_admin_user
)):
async
def
update_webhook_url
(
form_data
:
UrlForm
,
user
=
Depends
(
get_admin_user
)):
app
.
state
.
config
.
WEBHOOK_URL
=
form_data
.
url
app
.
state
.
config
.
WEBHOOK_URL
=
form_data
.
url
webui_app
.
state
.
WEBHOOK_URL
=
app
.
state
.
config
.
WEBHOOK_URL
webui_app
.
state
.
WEBHOOK_URL
=
app
.
state
.
config
.
WEBHOOK_URL
return
{
"url"
:
app
.
state
.
config
.
WEBHOOK_URL
}
return
{
"url"
:
app
.
state
.
config
.
WEBHOOK_URL
,
}
@
app
.
get
(
"/api/community_sharing"
,
response_model
=
bool
)
async
def
get_community_sharing_status
(
request
:
Request
,
user
=
Depends
(
get_admin_user
)):
return
webui_app
.
state
.
config
.
ENABLE_COMMUNITY_SHARING
@
app
.
get
(
"/api/community_sharing/toggle"
,
response_model
=
bool
)
async
def
toggle_community_sharing
(
request
:
Request
,
user
=
Depends
(
get_admin_user
)):
webui_app
.
state
.
config
.
ENABLE_COMMUNITY_SHARING
=
(
not
webui_app
.
state
.
config
.
ENABLE_COMMUNITY_SHARING
)
return
webui_app
.
state
.
config
.
ENABLE_COMMUNITY_SHARING
@
app
.
get
(
"/api/version"
)
@
app
.
get
(
"/api/version"
)
...
...
src/lib/apis/auths/index.ts
View file @
25336f85
import
{
WEBUI_API_BASE_URL
}
from
'
$lib/constants
'
;
import
{
WEBUI_API_BASE_URL
}
from
'
$lib/constants
'
;
export
const
getAdminDetails
=
async
(
token
:
string
)
=>
{
let
error
=
null
;
const
res
=
await
fetch
(
`
${
WEBUI_API_BASE_URL
}
/auths/admin/details`
,
{
method
:
'
GET
'
,
headers
:
{
'
Content-Type
'
:
'
application/json
'
,
Authorization
:
`Bearer
${
token
}
`
}
})
.
then
(
async
(
res
)
=>
{
if
(
!
res
.
ok
)
throw
await
res
.
json
();
return
res
.
json
();
})
.
catch
((
err
)
=>
{
console
.
log
(
err
);
error
=
err
.
detail
;
return
null
;
});
if
(
error
)
{
throw
error
;
}
return
res
;
};
export
const
getAdminConfig
=
async
(
token
:
string
)
=>
{
let
error
=
null
;
const
res
=
await
fetch
(
`
${
WEBUI_API_BASE_URL
}
/auths/admin/config`
,
{
method
:
'
GET
'
,
headers
:
{
'
Content-Type
'
:
'
application/json
'
,
Authorization
:
`Bearer
${
token
}
`
}
})
.
then
(
async
(
res
)
=>
{
if
(
!
res
.
ok
)
throw
await
res
.
json
();
return
res
.
json
();
})
.
catch
((
err
)
=>
{
console
.
log
(
err
);
error
=
err
.
detail
;
return
null
;
});
if
(
error
)
{
throw
error
;
}
return
res
;
};
export
const
updateAdminConfig
=
async
(
token
:
string
,
body
:
object
)
=>
{
let
error
=
null
;
const
res
=
await
fetch
(
`
${
WEBUI_API_BASE_URL
}
/auths/admin/config`
,
{
method
:
'
POST
'
,
headers
:
{
'
Content-Type
'
:
'
application/json
'
,
Authorization
:
`Bearer
${
token
}
`
},
body
:
JSON
.
stringify
(
body
)
})
.
then
(
async
(
res
)
=>
{
if
(
!
res
.
ok
)
throw
await
res
.
json
();
return
res
.
json
();
})
.
catch
((
err
)
=>
{
console
.
log
(
err
);
error
=
err
.
detail
;
return
null
;
});
if
(
error
)
{
throw
error
;
}
return
res
;
};
export
const
getSessionUser
=
async
(
token
:
string
)
=>
{
export
const
getSessionUser
=
async
(
token
:
string
)
=>
{
let
error
=
null
;
let
error
=
null
;
...
...
src/lib/components/admin/Settings/General.svelte
View file @
25336f85
...
@@ -6,61 +6,44 @@
...
@@ -6,61 +6,44 @@
updateWebhookUrl
updateWebhookUrl
} from '$lib/apis';
} from '$lib/apis';
import {
import {
getAdminConfig,
getDefaultUserRole,
getDefaultUserRole,
getJWTExpiresDuration,
getJWTExpiresDuration,
getSignUpEnabledStatus,
getSignUpEnabledStatus,
toggleSignUpEnabledStatus,
toggleSignUpEnabledStatus,
updateAdminConfig,
updateDefaultUserRole,
updateDefaultUserRole,
updateJWTExpiresDuration
updateJWTExpiresDuration
} from '$lib/apis/auths';
} from '$lib/apis/auths';
import Switch from '$lib/components/common/Switch.svelte';
import { onMount, getContext } from 'svelte';
import { onMount, getContext } from 'svelte';
const i18n = getContext('i18n');
const i18n = getContext('i18n');
export let saveHandler: Function;
export let saveHandler: Function;
let signUpEnabled = true;
let defaultUserRole = 'pending';
let JWTExpiresIn = '';
let adminConfig = null;
let webhookUrl = '';
let webhookUrl = '';
let communitySharingEnabled = true;
const toggleSignUpEnabled = async () => {
const updateHandler = async () => {
signUpEnabled = await toggleSignUpEnabledStatus(localStorage.token);
};
const updateDefaultUserRoleHandler = async (role) => {
defaultUserRole = await updateDefaultUserRole(localStorage.token, role);
};
const updateJWTExpiresDurationHandler = async (duration) => {
JWTExpiresIn = await updateJWTExpiresDuration(localStorage.token, duration);
};
const updateWebhookUrlHandler = async () => {
webhookUrl = await updateWebhookUrl(localStorage.token, webhookUrl);
webhookUrl = await updateWebhookUrl(localStorage.token, webhookUrl);
}
;
const res = await updateAdminConfig(localStorage.token, adminConfig)
;
const toggleCommunitySharingEnabled = async () => {
if (res) {
communitySharingEnabled = await toggleCommunitySharingEnabledStatus(localStorage.token);
toast.success(i18n.t('Settings updated successfully'));
} else {
toast.error(i18n.t('Failed to update settings'));
}
};
};
onMount(async () => {
onMount(async () => {
await Promise.all([
await Promise.all([
(async () => {
(async () => {
signUpEnabled = await getSignUpEnabledStatus(localStorage.token);
adminConfig = await getAdminConfig(localStorage.token);
})(),
(async () => {
defaultUserRole = await getDefaultUserRole(localStorage.token);
})(),
(async () => {
JWTExpiresIn = await getJWTExpiresDuration(localStorage.token);
})(),
})(),
(async () => {
(async () => {
webhookUrl = await getWebhookUrl(localStorage.token);
webhookUrl = await getWebhookUrl(localStorage.token);
})(),
(async () => {
communitySharingEnabled = await getCommunitySharingEnabledStatus(localStorage.token);
})()
})()
]);
]);
});
});
...
@@ -69,156 +52,94 @@
...
@@ -69,156 +52,94 @@
<form
<form
class="flex flex-col h-full justify-between space-y-3 text-sm"
class="flex flex-col h-full justify-between space-y-3 text-sm"
on:submit|preventDefault={() => {
on:submit|preventDefault={() => {
updateJWTExpiresDurationHandler(JWTExpiresIn);
updateHandler();
updateWebhookUrlHandler();
saveHandler();
saveHandler();
}}
}}
>
>
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80">
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-[22rem]">
<div>
{#if adminConfig !== null}
<div class=" mb-2 text-sm font-medium">{$i18n.t('General Settings')}</div>
<div>
<div class=" mb-3 text-sm font-medium">{$i18n.t('General Settings')}</div>
<div class=" flex w-full justify-between">
<div class=" self-center text-xs font-medium">{$i18n.t('Enable New Sign Ups')}</div>
<div class=" flex w-full justify-between pr-2">
<div class=" self-center text-xs font-medium">{$i18n.t('Enable New Sign Ups')}</div>
<button
class="p-1 px-3 text-xs flex rounded transition"
on:click={() => {
toggleSignUpEnabled();
}}
type="button"
>
{#if signUpEnabled}
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-4 h-4"
>
<path
d="M11.5 1A3.5 3.5 0 0 0 8 4.5V7H2.5A1.5 1.5 0 0 0 1 8.5v5A1.5 1.5 0 0 0 2.5 15h7a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 9.5 7V4.5a2 2 0 1 1 4 0v1.75a.75.75 0 0 0 1.5 0V4.5A3.5 3.5 0 0 0 11.5 1Z"
/>
</svg>
<span class="ml-2 self-center">{$i18n.t('Enabled')}</span>
{:else}
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-4 h-4"
>
<path
fill-rule="evenodd"
d="M8 1a3.5 3.5 0 0 0-3.5 3.5V7A1.5 1.5 0 0 0 3 8.5v5A1.5 1.5 0 0 0 4.5 15h7a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 11.5 7V4.5A3.5 3.5 0 0 0 8 1Zm2 6V4.5a2 2 0 1 0-4 0V7h4Z"
clip-rule="evenodd"
/>
</svg>
<span class="ml-2 self-center">{$i18n.t('Disabled')}</span>
{/if}
</button>
</div>
<div class=" flex w-full justify-between">
<Switch bind:state={adminConfig.ENABLE_SIGNUP} />
<div class=" self-center text-xs font-medium">{$i18n.t('Default User Role')}</div>
<div class="flex items-center relative">
<select
class="dark:bg-gray-900 w-fit pr-8 rounded py-2 px-2 text-xs bg-transparent outline-none text-right"
bind:value={defaultUserRole}
placeholder="Select a theme"
on:change={(e) => {
updateDefaultUserRoleHandler(e.target.value);
}}
>
<option value="pending">{$i18n.t('pending')}</option>
<option value="user">{$i18n.t('user')}</option>
<option value="admin">{$i18n.t('admin')}</option>
</select>
</div>
</div>
</div>
<div class=" flex w-full justify-between">
<div class=" my-3 flex w-full justify-between">
<div class=" self-center text-xs font-medium">{$i18n.t('Enable Community Sharing')}</div>
<div class=" self-center text-xs font-medium">{$i18n.t('Default User Role')}</div>
<div class="flex items-center relative">
<button
<select
class="p-1 px-3 text-xs flex rounded transition"
class="dark:bg-gray-900 w-fit pr-8 rounded px-2 text-xs bg-transparent outline-none text-right"
on:click={() => {
bind:value={adminConfig.DEFAULT_USER_ROLE}
toggleCommunitySharingEnabled();
placeholder="Select a role"
}}
type="button"
>
{#if communitySharingEnabled}
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-4 h-4"
>
>
<path
<option value="pending">{$i18n.t('pending')}</option>
d="M11.5 1A3.5 3.5 0 0 0 8 4.5V7H2.5A1.5 1.5 0 0 0 1 8.5v5A1.5 1.5 0 0 0 2.5 15h7a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 9.5 7V4.5a2 2 0 1 1 4 0v1.75a.75.75 0 0 0 1.5 0V4.5A3.5 3.5 0 0 0 11.5 1Z"
<option value="user">{$i18n.t('user')}</option>
/>
<option value="admin">{$i18n.t('admin')}</option>
</svg>
</select>
<span class="ml-2 self-center">{$i18n.t('Enabled')}</span>
</div>
{:else}
</div>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-4 h-4"
>
<path
fill-rule="evenodd"
d="M8 1a3.5 3.5 0 0 0-3.5 3.5V7A1.5 1.5 0 0 0 3 8.5v5A1.5 1.5 0 0 0 4.5 15h7a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 11.5 7V4.5A3.5 3.5 0 0 0 8 1Zm2 6V4.5a2 2 0 1 0-4 0V7h4Z"
clip-rule="evenodd"
/>
</svg>
<span class="ml-2 self-center">{$i18n.t('Disabled')}</span>
{/if}
</button>
</div>
<hr class=" dark:border-gray-
70
0 my-
3
" />
<hr class=" dark:border-gray-
85
0 my-
2
" />
<div class="
w-full
justify-between">
<div class="
my-3 flex w-full items-center
justify-between
pr-2
">
<div class="
flex w-full justify-between
">
<div class="
self-center text-xs font-medium
">
<div class=" self-center text-xs font-medium">{$i18n.t('Webhook URL')}</div>
{$i18n.t('Show Admin Details in Account Pending Overlay')}
</div>
</div>
<div class="flex mt-2 space-x-2">
<Switch bind:state={adminConfig.SHOW_ADMIN_DETAILS} />
<input
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
type="text"
placeholder={`https://example.com/webhook`}
bind:value={webhookUrl}
/>
</div>
</div>
</div>
<hr class=" dark:border-gray-700 my-3" />
<div class="my-3 flex w-full items-center justify-between pr-2">
<div class=" self-center text-xs font-medium">{$i18n.t('Enable Community Sharing')}</div>
<div class=" w-full justify-between">
<Switch bind:state={adminConfig.ENABLE_COMMUNITY_SHARING} />
<div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">{$i18n.t('JWT Expiration')}</div>
</div>
</div>
<div class="flex mt-2 space-x-2">
<hr class=" dark:border-gray-850 my-2" />
<input
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
<div class=" w-full justify-between">
type="text"
<div class="flex w-full justify-between">
placeholder={`e.g.) "30m","1h", "10d". `}
<div class=" self-center text-xs font-medium">{$i18n.t('JWT Expiration')}</div>
bind:value={JWTExpiresIn}
</div>
/>
<div class="flex mt-2 space-x-2">
<input
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
type="text"
placeholder={`e.g.) "30m","1h", "10d". `}
bind:value={adminConfig.JWT_EXPIRES_IN}
/>
</div>
<div class="mt-2 text-xs text-gray-400 dark:text-gray-500">
{$i18n.t('Valid time units:')}
<span class=" text-gray-300 font-medium"
>{$i18n.t("'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.")}</span
>
</div>
</div>
</div>
<div class="mt-2 text-xs text-gray-400 dark:text-gray-500">
<hr class=" dark:border-gray-850 my-2" />
{$i18n.t('Valid time units:')}
<span class=" text-gray-300 font-medium"
<div class=" w-full justify-between">
>{$i18n.t("'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.")}</span
<div class="flex w-full justify-between">
>
<div class=" self-center text-xs font-medium">{$i18n.t('Webhook URL')}</div>
</div>
<div class="flex mt-2 space-x-2">
<input
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
type="text"
placeholder={`https://example.com/webhook`}
bind:value={webhookUrl}
/>
</div>
</div>
</div>
</div>
</div>
</div>
{/if}
</div>
</div>
<div class="flex justify-end pt-3 text-sm font-medium">
<div class="flex justify-end pt-3 text-sm font-medium">
...
...
src/lib/components/layout/Overlay/AccountPending.svelte
0 → 100644
View file @
25336f85
<script lang="ts">
import { getAdminDetails } from '$lib/apis/auths';
import { onMount, tick, getContext } from 'svelte';
const i18n = getContext('i18n');
let adminDetails = null;
onMount(async () => {
adminDetails = await getAdminDetails(localStorage.token).catch((err) => {
console.error(err);
return null;
});
});
</script>
<div class="fixed w-full h-full flex z-[999]">
<div
class="absolute w-full h-full backdrop-blur-lg bg-white/10 dark:bg-gray-900/50 flex justify-center"
>
<div class="m-auto pb-10 flex flex-col justify-center">
<div class="max-w-md">
<div class="text-center dark:text-white text-2xl font-medium z-50">
Account Activation Pending<br /> Contact Admin for WebUI Access
</div>
<div class=" mt-4 text-center text-sm dark:text-gray-200 w-full">
Your account status is currently pending activation.<br /> To access the WebUI, please reach
out to the administrator. Admins can manage user statuses from the Admin Panel.
</div>
{#if adminDetails}
<div class="mt-4 text-sm font-medium text-center">
<div>Admin: {adminDetails.name} ({adminDetails.email})</div>
</div>
{/if}
<div class=" mt-6 mx-auto relative group w-fit">
<button
class="relative z-20 flex px-5 py-2 rounded-full bg-white border border-gray-100 dark:border-none hover:bg-gray-100 text-gray-700 transition font-medium text-sm"
on:click={async () => {
location.href = '/';
}}
>
{$i18n.t('Check Again')}
</button>
<button
class="text-xs text-center w-full mt-2 text-gray-400 underline"
on:click={async () => {
localStorage.removeItem('token');
location.href = '/auth';
}}>{$i18n.t('Sign Out')}</button
>
</div>
</div>
</div>
</div>
</div>
src/routes/(app)/+layout.svelte
View file @
25336f85
...
@@ -37,6 +37,8 @@
...
@@ -37,6 +37,8 @@
import { getBanners } from '$lib/apis/configs';
import { getBanners } from '$lib/apis/configs';
import { getUserSettings } from '$lib/apis/users';
import { getUserSettings } from '$lib/apis/users';
import Help from '$lib/components/layout/Help.svelte';
import Help from '$lib/components/layout/Help.svelte';
import AccountPending from '$lib/components/layout/Overlay/AccountPending.svelte';
import { error } from '@sveltejs/kit';
const i18n = getContext('i18n');
const i18n = getContext('i18n');
...
@@ -74,7 +76,10 @@
...
@@ -74,7 +76,10 @@
// IndexedDB Not Found
// IndexedDB Not Found
}
}
const userSettings = await getUserSettings(localStorage.token);
const userSettings = await getUserSettings(localStorage.token).catch((error) => {
console.error(error);
return null;
});
if (userSettings) {
if (userSettings) {
await settings.set(userSettings.ui);
await settings.set(userSettings.ui);
...
@@ -186,44 +191,7 @@
...
@@ -186,44 +191,7 @@
>
>
{#if loaded}
{#if loaded}
{#if !['user', 'admin'].includes($user.role)}
{#if !['user', 'admin'].includes($user.role)}
<div class="fixed w-full h-full flex z-[999]">
<AccountPending />
<div
class="absolute w-full h-full backdrop-blur-lg bg-white/10 dark:bg-gray-900/50 flex justify-center"
>
<div class="m-auto pb-10 flex flex-col justify-center">
<div class="max-w-md">
<div class="text-center dark:text-white text-2xl font-medium z-50">
Account Activation Pending<br /> Contact Admin for WebUI Access
</div>
<div class=" mt-4 text-center text-sm dark:text-gray-200 w-full">
Your account status is currently pending activation. To access the WebUI, please
reach out to the administrator. Admins can manage user statuses from the Admin
Panel.
</div>
<div class=" mt-6 mx-auto relative group w-fit">
<button
class="relative z-20 flex px-5 py-2 rounded-full bg-white border border-gray-100 dark:border-none hover:bg-gray-100 text-gray-700 transition font-medium text-sm"
on:click={async () => {
location.href = '/';
}}
>
{$i18n.t('Check Again')}
</button>
<button
class="text-xs text-center w-full mt-2 text-gray-400 underline"
on:click={async () => {
localStorage.removeItem('token');
location.href = '/auth';
}}>{$i18n.t('Sign Out')}</button
>
</div>
</div>
</div>
</div>
</div>
{:else if localDBChats.length > 0}
{:else if localDBChats.length > 0}
<div class="fixed w-full h-full flex z-50">
<div class="fixed w-full h-full flex z-50">
<div
<div
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment