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
511e939b
Commit
511e939b
authored
Feb 14, 2024
by
Timothy J. Baek
Browse files
feat: admin settings
parent
b0a07e52
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
527 additions
and
52 deletions
+527
-52
backend/apps/web/main.py
backend/apps/web/main.py
+12
-1
backend/apps/web/routers/auths.py
backend/apps/web/routers/auths.py
+40
-4
backend/apps/web/routers/chats.py
backend/apps/web/routers/chats.py
+11
-1
backend/apps/web/routers/users.py
backend/apps/web/routers/users.py
+19
-1
backend/config.py
backend/config.py
+3
-0
src/lib/apis/auths/index.ts
src/lib/apis/auths/index.ts
+57
-0
src/lib/apis/chats/index.ts
src/lib/apis/chats/index.ts
+1
-1
src/lib/apis/users/index.ts
src/lib/apis/users/index.ts
+57
-0
src/lib/components/admin/Settings/General.svelte
src/lib/components/admin/Settings/General.svelte
+108
-0
src/lib/components/admin/Settings/Users.svelte
src/lib/components/admin/Settings/Users.svelte
+82
-0
src/lib/components/admin/SettingsModal.svelte
src/lib/components/admin/SettingsModal.svelte
+107
-0
src/lib/components/layout/Sidebar.svelte
src/lib/components/layout/Sidebar.svelte
+11
-3
src/routes/(app)/admin/+page.svelte
src/routes/(app)/admin/+page.svelte
+19
-41
No files found.
backend/apps/web/main.py
View file @
511e939b
...
...
@@ -11,7 +11,15 @@ from apps.web.routers import (
configs
,
utils
,
)
from
config
import
WEBUI_VERSION
,
WEBUI_AUTH
,
DEFAULT_MODELS
,
DEFAULT_PROMPT_SUGGESTIONS
,
ENABLE_SIGNUP
from
config
import
(
WEBUI_VERSION
,
WEBUI_AUTH
,
DEFAULT_MODELS
,
DEFAULT_PROMPT_SUGGESTIONS
,
DEFAULT_USER_ROLE
,
ENABLE_SIGNUP
,
USER_PERMISSIONS
,
)
app
=
FastAPI
()
...
...
@@ -20,6 +28,9 @@ origins = ["*"]
app
.
state
.
ENABLE_SIGNUP
=
ENABLE_SIGNUP
app
.
state
.
DEFAULT_MODELS
=
DEFAULT_MODELS
app
.
state
.
DEFAULT_PROMPT_SUGGESTIONS
=
DEFAULT_PROMPT_SUGGESTIONS
app
.
state
.
DEFAULT_USER_ROLE
=
DEFAULT_USER_ROLE
app
.
state
.
USER_PERMISSIONS
=
USER_PERMISSIONS
app
.
add_middleware
(
CORSMiddleware
,
...
...
backend/apps/web/routers/auths.py
View file @
511e939b
...
...
@@ -19,7 +19,12 @@ from apps.web.models.auths import (
)
from
apps.web.models.users
import
Users
from
utils.utils
import
get_password_hash
,
get_current_user
,
get_admin_user
,
create_token
from
utils.utils
import
(
get_password_hash
,
get_current_user
,
get_admin_user
,
create_token
,
)
from
utils.misc
import
get_gravatar_url
,
validate_email_format
from
constants
import
ERROR_MESSAGES
...
...
@@ -116,16 +121,24 @@ async def signin(form_data: SigninForm):
@
router
.
post
(
"/signup"
,
response_model
=
SigninResponse
)
async
def
signup
(
request
:
Request
,
form_data
:
SignupForm
):
if
not
request
.
app
.
state
.
ENABLE_SIGNUP
:
raise
HTTPException
(
status
.
HTTP_403_FORBIDDEN
,
detail
=
ERROR_MESSAGES
.
ACCESS_PROHIBITED
)
raise
HTTPException
(
status
.
HTTP_403_FORBIDDEN
,
detail
=
ERROR_MESSAGES
.
ACCESS_PROHIBITED
)
if
not
validate_email_format
(
form_data
.
email
.
lower
()):
raise
HTTPException
(
status
.
HTTP_400_BAD_REQUEST
,
detail
=
ERROR_MESSAGES
.
INVALID_EMAIL_FORMAT
)
raise
HTTPException
(
status
.
HTTP_400_BAD_REQUEST
,
detail
=
ERROR_MESSAGES
.
INVALID_EMAIL_FORMAT
)
if
Users
.
get_user_by_email
(
form_data
.
email
.
lower
()):
raise
HTTPException
(
400
,
detail
=
ERROR_MESSAGES
.
EMAIL_TAKEN
)
try
:
role
=
"admin"
if
Users
.
get_num_users
()
==
0
else
"pending"
role
=
(
"admin"
if
Users
.
get_num_users
()
==
0
else
request
.
app
.
state
.
DEFAULT_USER_ROLE
)
hashed
=
get_password_hash
(
form_data
.
password
)
user
=
Auths
.
insert_new_auth
(
form_data
.
email
.
lower
(),
hashed
,
form_data
.
name
,
role
...
...
@@ -164,3 +177,26 @@ async def get_sign_up_status(request: Request, user=Depends(get_admin_user)):
async
def
toggle_sign_up
(
request
:
Request
,
user
=
Depends
(
get_admin_user
)):
request
.
app
.
state
.
ENABLE_SIGNUP
=
not
request
.
app
.
state
.
ENABLE_SIGNUP
return
request
.
app
.
state
.
ENABLE_SIGNUP
############################
# Default User Role
############################
@
router
.
get
(
"/signup/user/role"
)
async
def
get_default_user_role
(
request
:
Request
,
user
=
Depends
(
get_admin_user
)):
return
request
.
app
.
state
.
DEFAULT_USER_ROLE
class
UpdateRoleForm
(
BaseModel
):
role
:
str
@
router
.
post
(
"/signup/user/role"
)
async
def
update_default_user_role
(
request
:
Request
,
form_data
:
UpdateRoleForm
,
user
=
Depends
(
get_admin_user
)
):
if
form_data
.
role
in
[
"pending"
,
"user"
,
"admin"
]:
request
.
app
.
state
.
DEFAULT_USER_ROLE
=
form_data
.
role
return
request
.
app
.
state
.
DEFAULT_USER_ROLE
backend/apps/web/routers/chats.py
View file @
511e939b
...
...
@@ -165,7 +165,17 @@ async def update_chat_by_id(
@
router
.
delete
(
"/{id}"
,
response_model
=
bool
)
async
def
delete_chat_by_id
(
id
:
str
,
user
=
Depends
(
get_current_user
)):
async
def
delete_chat_by_id
(
request
:
Request
,
id
:
str
,
user
=
Depends
(
get_current_user
)):
if
(
user
.
role
==
"user"
and
not
request
.
app
.
state
.
USER_PERMISSIONS
[
"chat"
][
"deletion"
]
):
raise
HTTPException
(
status_code
=
status
.
HTTP_401_UNAUTHORIZED
,
detail
=
ERROR_MESSAGES
.
ACCESS_PROHIBITED
,
)
result
=
Chats
.
delete_chat_by_id_and_user_id
(
id
,
user
.
id
)
return
result
...
...
backend/apps/web/routers/users.py
View file @
511e939b
from
fastapi
import
Response
from
fastapi
import
Response
,
Request
from
fastapi
import
Depends
,
FastAPI
,
HTTPException
,
status
from
datetime
import
datetime
,
timedelta
from
typing
import
List
,
Union
,
Optional
...
...
@@ -26,6 +26,24 @@ async def get_users(skip: int = 0, limit: int = 50, user=Depends(get_admin_user)
return
Users
.
get_users
(
skip
,
limit
)
############################
# User Permissions
############################
@
router
.
get
(
"/permissions/user"
)
async
def
get_user_permissions
(
request
:
Request
,
user
=
Depends
(
get_admin_user
)):
return
request
.
app
.
state
.
USER_PERMISSIONS
@
router
.
post
(
"/permissions/user"
)
async
def
update_user_permissions
(
request
:
Request
,
form_data
:
dict
,
user
=
Depends
(
get_admin_user
)
):
request
.
app
.
state
.
USER_PERMISSIONS
=
form_data
return
request
.
app
.
state
.
USER_PERMISSIONS
############################
# UpdateUserRole
############################
...
...
backend/config.py
View file @
511e939b
...
...
@@ -93,6 +93,9 @@ DEFAULT_PROMPT_SUGGESTIONS = os.environ.get(
},
],
)
DEFAULT_USER_ROLE
=
"pending"
USER_PERMISSIONS
=
{
"chat"
:
{
"deletion"
:
True
}}
####################################
# WEBUI_VERSION
...
...
src/lib/apis/auths/index.ts
View file @
511e939b
...
...
@@ -178,6 +178,63 @@ export const getSignUpEnabledStatus = async (token: string) => {
return
res
;
};
export
const
getDefaultUserRole
=
async
(
token
:
string
)
=>
{
let
error
=
null
;
const
res
=
await
fetch
(
`
${
WEBUI_API_BASE_URL
}
/auths/signup/user/role`
,
{
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
updateDefaultUserRole
=
async
(
token
:
string
,
role
:
string
)
=>
{
let
error
=
null
;
const
res
=
await
fetch
(
`
${
WEBUI_API_BASE_URL
}
/auths/signup/user/role`
,
{
method
:
'
POST
'
,
headers
:
{
'
Content-Type
'
:
'
application/json
'
,
Authorization
:
`Bearer
${
token
}
`
},
body
:
JSON
.
stringify
({
role
:
role
})
})
.
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
toggleSignUpEnabledStatus
=
async
(
token
:
string
)
=>
{
let
error
=
null
;
...
...
src/lib/apis/chats/index.ts
View file @
511e939b
...
...
@@ -272,7 +272,7 @@ export const deleteChatById = async (token: string, id: string) => {
return
json
;
})
.
catch
((
err
)
=>
{
error
=
err
;
error
=
err
.
detail
;
console
.
log
(
err
);
return
null
;
...
...
src/lib/apis/users/index.ts
View file @
511e939b
import
{
WEBUI_API_BASE_URL
}
from
'
$lib/constants
'
;
export
const
getUserPermissions
=
async
(
token
:
string
)
=>
{
let
error
=
null
;
const
res
=
await
fetch
(
`
${
WEBUI_API_BASE_URL
}
/users/permissions/user`
,
{
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
updateUserPermissions
=
async
(
token
:
string
,
permissions
:
object
)
=>
{
let
error
=
null
;
const
res
=
await
fetch
(
`
${
WEBUI_API_BASE_URL
}
/users/permissions/user`
,
{
method
:
'
POST
'
,
headers
:
{
'
Content-Type
'
:
'
application/json
'
,
Authorization
:
`Bearer
${
token
}
`
},
body
:
JSON
.
stringify
({
...
permissions
})
})
.
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
updateUserRole
=
async
(
token
:
string
,
id
:
string
,
role
:
string
)
=>
{
let
error
=
null
;
...
...
src/lib/components/admin/Settings/General.svelte
0 → 100644
View file @
511e939b
<script lang="ts">
import {
getDefaultUserRole,
getSignUpEnabledStatus,
toggleSignUpEnabledStatus,
updateDefaultUserRole
} from '$lib/apis/auths';
import { onMount } from 'svelte';
export let saveHandler: Function;
let signUpEnabled = true;
let defaultUserRole = 'pending';
const toggleSignUpEnabled = async () => {
signUpEnabled = await toggleSignUpEnabledStatus(localStorage.token);
};
const updateDefaultUserRoleHandler = async (role) => {
defaultUserRole = await updateDefaultUserRole(localStorage.token, role);
};
onMount(async () => {
signUpEnabled = await getSignUpEnabledStatus(localStorage.token);
defaultUserRole = await getDefaultUserRole(localStorage.token);
});
</script>
<form
class="flex flex-col h-full justify-between space-y-3 text-sm"
on:submit|preventDefault={() => {
// console.log('submit');
saveHandler();
}}
>
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80">
<div>
<div class=" mb-2 text-sm font-medium">General Settings</div>
<div class=" flex w-full justify-between">
<div class=" self-center text-xs font-medium">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">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">Disabled</span>
{/if}
</button>
</div>
<div class=" flex w-full justify-between">
<div class=" self-center text-xs font-medium">Default User Role</div>
<div class="flex items-center relative">
<select
class="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">Pending</option>
<option value="user">User</option>
<option value="admin">Admin</option>
</select>
</div>
</div>
</div>
</div>
<div class="flex justify-end pt-3 text-sm font-medium">
<button
class=" px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-gray-100 transition rounded"
type="submit"
>
Save
</button>
</div>
</form>
src/lib/components/admin/Settings/Users.svelte
0 → 100644
View file @
511e939b
<script lang="ts">
import { getSignUpEnabledStatus, toggleSignUpEnabledStatus } from '$lib/apis/auths';
import { getUserPermissions, updateUserPermissions } from '$lib/apis/users';
import { onMount } from 'svelte';
export let saveHandler: Function;
let permissions = {
chat: {
deletion: true
}
};
onMount(async () => {
permissions = await getUserPermissions(localStorage.token);
});
</script>
<form
class="flex flex-col h-full justify-between space-y-3 text-sm"
on:submit|preventDefault={async () => {
// console.log('submit');
await updateUserPermissions(localStorage.token, permissions);
saveHandler();
}}
>
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80">
<div>
<div class=" mb-2 text-sm font-medium">User Permission</div>
<div class=" flex w-full justify-between">
<div class=" self-center text-xs font-medium">Allow Chat Deletion</div>
<button
class="p-1 px-3 text-xs flex rounded transition"
on:click={() => {
permissions.chat.deletion = !permissions.chat.deletion;
}}
type="button"
>
{#if permissions.chat.deletion}
<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">Allow</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">Don't Allow</span>
{/if}
</button>
</div>
</div>
</div>
<div class="flex justify-end pt-3 text-sm font-medium">
<button
class=" px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-gray-100 transition rounded"
type="submit"
>
Save
</button>
</div>
</form>
src/lib/components/admin/SettingsModal.svelte
0 → 100644
View file @
511e939b
<script>
import Modal from '../common/Modal.svelte';
import General from './Settings/General.svelte';
import Users from './Settings/Users.svelte';
export let show = false;
let selectedTab = 'general';
</script>
<Modal bind:show>
<div>
<div class=" flex justify-between dark:text-gray-300 px-5 py-4">
<div class=" text-lg font-medium self-center">Admin Settings</div>
<button
class="self-center"
on:click={() => {
show = false;
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="w-5 h-5"
>
<path
d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
/>
</svg>
</button>
</div>
<hr class=" dark:border-gray-800" />
<div class="flex flex-col md:flex-row w-full p-4 md:space-x-4">
<div
class="tabs flex flex-row overflow-x-auto space-x-1 md:space-x-0 md:space-y-1 md:flex-col flex-1 md:flex-none md:w-40 dark:text-gray-200 text-xs text-left mb-3 md:mb-0"
>
<button
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
'general'
? 'bg-gray-200 dark:bg-gray-700'
: ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
on:click={() => {
selectedTab = 'general';
}}
>
<div class=" self-center mr-2">
<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="M6.955 1.45A.5.5 0 0 1 7.452 1h1.096a.5.5 0 0 1 .497.45l.17 1.699c.484.12.94.312 1.356.562l1.321-1.081a.5.5 0 0 1 .67.033l.774.775a.5.5 0 0 1 .034.67l-1.08 1.32c.25.417.44.873.561 1.357l1.699.17a.5.5 0 0 1 .45.497v1.096a.5.5 0 0 1-.45.497l-1.699.17c-.12.484-.312.94-.562 1.356l1.082 1.322a.5.5 0 0 1-.034.67l-.774.774a.5.5 0 0 1-.67.033l-1.322-1.08c-.416.25-.872.44-1.356.561l-.17 1.699a.5.5 0 0 1-.497.45H7.452a.5.5 0 0 1-.497-.45l-.17-1.699a4.973 4.973 0 0 1-1.356-.562L4.108 13.37a.5.5 0 0 1-.67-.033l-.774-.775a.5.5 0 0 1-.034-.67l1.08-1.32a4.971 4.971 0 0 1-.561-1.357l-1.699-.17A.5.5 0 0 1 1 8.548V7.452a.5.5 0 0 1 .45-.497l1.699-.17c.12-.484.312-.94.562-1.356L2.629 4.107a.5.5 0 0 1 .034-.67l.774-.774a.5.5 0 0 1 .67-.033L5.43 3.71a4.97 4.97 0 0 1 1.356-.561l.17-1.699ZM6 8c0 .538.212 1.026.558 1.385l.057.057a2 2 0 0 0 2.828-2.828l-.058-.056A2 2 0 0 0 6 8Z"
clip-rule="evenodd"
/>
</svg>
</div>
<div class=" self-center">General</div>
</button>
<button
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
'users'
? 'bg-gray-200 dark:bg-gray-700'
: ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
on:click={() => {
selectedTab = 'users';
}}
>
<div class=" self-center mr-2">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-4 h-4"
>
<path
d="M8 8a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5ZM3.156 11.763c.16-.629.44-1.21.813-1.72a2.5 2.5 0 0 0-2.725 1.377c-.136.287.102.58.418.58h1.449c.01-.077.025-.156.045-.237ZM12.847 11.763c.02.08.036.16.046.237h1.446c.316 0 .554-.293.417-.579a2.5 2.5 0 0 0-2.722-1.378c.374.51.653 1.09.813 1.72ZM14 7.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0ZM3.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM5 13c-.552 0-1.013-.455-.876-.99a4.002 4.002 0 0 1 7.753 0c.136.535-.324.99-.877.99H5Z"
/>
</svg>
</div>
<div class=" self-center">Users</div>
</button>
</div>
<div class="flex-1 md:min-h-[380px]">
{#if selectedTab === 'general'}
<General
saveHandler={() => {
show = false;
}}
/>
{:else if selectedTab === 'users'}
<Users
saveHandler={() => {
show = false;
}}
/>
{/if}
</div>
</div>
</div>
</Modal>
src/lib/components/layout/Sidebar.svelte
View file @
511e939b
...
...
@@ -15,6 +15,7 @@
getChatListByTagName,
updateChatById
} from '$lib/apis/chats';
import toast from 'svelte-french-toast';
let show = false;
let navElement;
...
...
@@ -64,10 +65,17 @@
};
const deleteChat = async (id) => {
goto('/');
const res = await deleteChatById(localStorage.token, id).catch((error) => {
toast.error(error);
chatDeleteId = null;
await deleteChatById(localStorage.token, id);
await chats.set(await getChatList(localStorage.token));
return null;
});
if (res) {
goto('/');
await chats.set(await getChatList(localStorage.token));
}
};
const saveSettings = async (updated) => {
...
...
src/routes/(app)/admin/+page.svelte
View file @
511e939b
...
...
@@ -9,13 +9,14 @@
import { updateUserRole, getUsers, deleteUserById } from '$lib/apis/users';
import { getSignUpEnabledStatus, toggleSignUpEnabledStatus } from '$lib/apis/auths';
import EditUserModal from '$lib/components/admin/EditUserModal.svelte';
import SettingsModal from '$lib/components/admin/SettingsModal.svelte';
let loaded = false;
let users = [];
let selectedUser = null;
let s
ignUpEnabled = tru
e;
let s
howSettingsModal = fals
e;
let showEditUserModal = false;
const updateRoleHandler = async (id, role) => {
...
...
@@ -50,17 +51,11 @@
}
};
const toggleSignUpEnabled = async () => {
signUpEnabled = await toggleSignUpEnabledStatus(localStorage.token);
};
onMount(async () => {
if ($user?.role !== 'admin') {
await goto('/');
} else {
users = await getUsers(localStorage.token);
signUpEnabled = await getSignUpEnabledStatus(localStorage.token);
}
loaded = true;
});
...
...
@@ -77,6 +72,8 @@
/>
{/key}
<SettingsModal bind:show={showSettingsModal} />
<div
class=" bg-white dark:bg-gray-900 dark:text-gray-100 min-h-screen w-full flex justify-center font-mona"
>
...
...
@@ -91,42 +88,23 @@
class="flex items-center space-x-1 border border-gray-200 dark:border-gray-600 px-3 py-1 rounded-lg"
type="button"
on:click={() => {
toggleSignUpEnabled()
;
showSettingsModal = !showSettingsModal
;
}}
>
{#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>
<div class=" text-xs">
New Sign Up <span class=" font-semibold">Enabled</span>
</div>
{: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>
<div class=" text-xs">
New Sign Up <span class=" font-semibold">Disabled</span>
</div>
{/if}
<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="M6.955 1.45A.5.5 0 0 1 7.452 1h1.096a.5.5 0 0 1 .497.45l.17 1.699c.484.12.94.312 1.356.562l1.321-1.081a.5.5 0 0 1 .67.033l.774.775a.5.5 0 0 1 .034.67l-1.08 1.32c.25.417.44.873.561 1.357l1.699.17a.5.5 0 0 1 .45.497v1.096a.5.5 0 0 1-.45.497l-1.699.17c-.12.484-.312.94-.562 1.356l1.082 1.322a.5.5 0 0 1-.034.67l-.774.774a.5.5 0 0 1-.67.033l-1.322-1.08c-.416.25-.872.44-1.356.561l-.17 1.699a.5.5 0 0 1-.497.45H7.452a.5.5 0 0 1-.497-.45l-.17-1.699a4.973 4.973 0 0 1-1.356-.562L4.108 13.37a.5.5 0 0 1-.67-.033l-.774-.775a.5.5 0 0 1-.034-.67l1.08-1.32a4.971 4.971 0 0 1-.561-1.357l-1.699-.17A.5.5 0 0 1 1 8.548V7.452a.5.5 0 0 1 .45-.497l1.699-.17c.12-.484.312-.94.562-1.356L2.629 4.107a.5.5 0 0 1 .034-.67l.774-.774a.5.5 0 0 1 .67-.033L5.43 3.71a4.97 4.97 0 0 1 1.356-.561l.17-1.699ZM6 8c0 .538.212 1.026.558 1.385l.057.057a2 2 0 0 0 2.828-2.828l-.058-.056A2 2 0 0 0 6 8Z"
clip-rule="evenodd"
/>
</svg>
<div class=" text-xs">Admin Settings</div>
</button>
</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