Skip to content

Commit

Permalink
Daily message limit per user (#2417)
Browse files Browse the repository at this point in the history
* set message limit per user

* remove old limit user messages + unused admin page

* fix daily message validation

* refactor message limit input
refactor canSendChat on user to a method on user model

---------

Co-authored-by: timothycarambat <[email protected]>
  • Loading branch information
shatfield4 and timothycarambat authored Oct 15, 2024
1 parent 15ca5e8 commit be6289d
Show file tree
Hide file tree
Showing 19 changed files with 172 additions and 345 deletions.
5 changes: 0 additions & 5 deletions frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ const WorkspaceChat = lazy(() => import("@/pages/WorkspaceChat"));
const AdminUsers = lazy(() => import("@/pages/Admin/Users"));
const AdminInvites = lazy(() => import("@/pages/Admin/Invitations"));
const AdminWorkspaces = lazy(() => import("@/pages/Admin/Workspaces"));
const AdminSystem = lazy(() => import("@/pages/Admin/System"));
const AdminLogs = lazy(() => import("@/pages/Admin/Logging"));
const AdminAgents = lazy(() => import("@/pages/Admin/Agents"));
const GeneralChats = lazy(() => import("@/pages/GeneralSettings/Chats"));
Expand Down Expand Up @@ -168,10 +167,6 @@ export default function App() {
path="/settings/workspace-chats"
element={<ManagerRoute Component={GeneralChats} />}
/>
<Route
path="/settings/system-preferences"
element={<ManagerRoute Component={AdminSystem} />}
/>
<Route
path="/settings/invites"
element={<ManagerRoute Component={AdminInvites} />}
Expand Down
4 changes: 1 addition & 3 deletions frontend/src/components/SettingsButton/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ export default function SettingsButton() {
return (
<ToolTipWrapper id="open-settings">
<Link
to={
!!user?.role ? paths.settings.system() : paths.settings.appearance()
}
to={paths.settings.appearance()}
className="transition-all duration-300 p-2 rounded-full text-white bg-sidebar-button hover:bg-menu-item-selected-gradient hover:border-slate-100 hover:border-opacity-50 border-transparent border"
aria-label="Settings"
data-tooltip-id="open-settings"
Expand Down
5 changes: 0 additions & 5 deletions frontend/src/components/SettingsSidebar/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -278,11 +278,6 @@ const SidebarOptions = ({ user = null, t }) => (
href: paths.settings.invites(),
roles: ["admin", "manager"],
},
{
btnText: t("settings.system"),
href: paths.settings.system(),
roles: ["admin", "manager"],
},
]}
/>
<Option
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/UserMenu/AccountModal/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export default function AccountModal({ user, hideModal }) {
autoComplete="off"
/>
<p className="mt-2 text-xs text-white/60">
Username must be only contain lowercase letters, numbers,
Username must only contain lowercase letters, numbers,
underscores, and hyphens with no spaces
</p>
</div>
Expand Down
128 changes: 0 additions & 128 deletions frontend/src/pages/Admin/System/index.jsx

This file was deleted.

18 changes: 15 additions & 3 deletions frontend/src/pages/Admin/Users/NewUserModal/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,24 @@ import React, { useState } from "react";
import { X } from "@phosphor-icons/react";
import Admin from "@/models/admin";
import { userFromStorage } from "@/utils/request";
import { RoleHintDisplay } from "..";
import { MessageLimitInput, RoleHintDisplay } from "..";

export default function NewUserModal({ closeModal }) {
const [error, setError] = useState(null);
const [role, setRole] = useState("default");
const [messageLimit, setMessageLimit] = useState({
enabled: false,
limit: 10,
});

const handleCreate = async (e) => {
setError(null);
e.preventDefault();
const data = {};
const form = new FormData(e.target);
for (var [key, value] of form.entries()) data[key] = value;
data.dailyMessageLimit = messageLimit.enabled ? messageLimit.limit : null;

const { user, error } = await Admin.newUser(data);
if (!!user) window.location.reload();
setError(error);
Expand Down Expand Up @@ -58,13 +64,13 @@ export default function NewUserModal({ closeModal }) {
pattern="^[a-z0-9_-]+$"
onInvalid={(e) =>
e.target.setCustomValidity(
"Username must be only contain lowercase letters, numbers, underscores, and hyphens with no spaces"
"Username must only contain lowercase letters, numbers, underscores, and hyphens with no spaces"
)
}
onChange={(e) => e.target.setCustomValidity("")}
/>
<p className="mt-2 text-xs text-white/60">
Username must be only contain lowercase letters, numbers,
Username must only contain lowercase letters, numbers,
underscores, and hyphens with no spaces
</p>
</div>
Expand Down Expand Up @@ -110,6 +116,12 @@ export default function NewUserModal({ closeModal }) {
</select>
<RoleHintDisplay role={role} />
</div>
<MessageLimitInput
role={role}
enabled={messageLimit.enabled}
limit={messageLimit.limit}
updateState={setMessageLimit}
/>
{error && <p className="text-red-400 text-sm">Error: {error}</p>}
<p className="text-white text-xs md:text-sm">
After creating a user they will need to login with their initial
Expand Down
20 changes: 18 additions & 2 deletions frontend/src/pages/Admin/Users/UserRow/EditUserModal/index.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import React, { useState } from "react";
import { X } from "@phosphor-icons/react";
import Admin from "@/models/admin";
import { RoleHintDisplay } from "../..";
import { MessageLimitInput, RoleHintDisplay } from "../..";

export default function EditUserModal({ currentUser, user, closeModal }) {
const [role, setRole] = useState(user.role);
const [error, setError] = useState(null);
const [messageLimit, setMessageLimit] = useState({
enabled: user.dailyMessageLimit !== null,
limit: user.dailyMessageLimit || 10,
});

const handleUpdate = async (e) => {
setError(null);
Expand All @@ -16,6 +20,12 @@ export default function EditUserModal({ currentUser, user, closeModal }) {
if (!value || value === null) continue;
data[key] = value;
}
if (messageLimit.enabled) {
data.dailyMessageLimit = messageLimit.limit;
} else {
data.dailyMessageLimit = null;
}

const { success, error } = await Admin.updateUser(user.id, data);
if (success) window.location.reload();
setError(error);
Expand Down Expand Up @@ -58,7 +68,7 @@ export default function EditUserModal({ currentUser, user, closeModal }) {
autoComplete="off"
/>
<p className="mt-2 text-xs text-white/60">
Username must be only contain lowercase letters, numbers,
Username must only contain lowercase letters, numbers,
underscores, and hyphens with no spaces
</p>
</div>
Expand Down Expand Up @@ -103,6 +113,12 @@ export default function EditUserModal({ currentUser, user, closeModal }) {
</select>
<RoleHintDisplay role={role} />
</div>
<MessageLimitInput
role={role}
enabled={messageLimit.enabled}
limit={messageLimit.limit}
updateState={setMessageLimit}
/>
{error && <p className="text-red-400 text-sm">Error: {error}</p>}
</div>
</div>
Expand Down
55 changes: 55 additions & 0 deletions frontend/src/pages/Admin/Users/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,58 @@ export function RoleHintDisplay({ role }) {
</div>
);
}

export function MessageLimitInput({ enabled, limit, updateState, role }) {
if (role === "admin") return null;
return (
<div className="mt-4 mb-8">
<div className="flex flex-col gap-y-1">
<div className="flex items-center gap-x-2">
<h2 className="text-base leading-6 font-bold text-white">
Limit messages per day
</h2>
<label className="relative inline-flex cursor-pointer items-center">
<input
type="checkbox"
checked={enabled}
onChange={(e) => {
updateState((prev) => ({
...prev,
enabled: e.target.checked,
}));
}}
className="peer sr-only"
/>
<div className="pointer-events-none peer h-6 w-11 rounded-full bg-stone-400 after:absolute after:left-[2px] after:top-[2px] after:h-5 after:w-5 after:rounded-full after:shadow-xl after:border after:border-gray-600 after:bg-white after:box-shadow-md after:transition-all after:content-[''] peer-checked:bg-lime-300 peer-checked:after:translate-x-full peer-checked:after:border-white peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-800"></div>
</label>
</div>
<p className="text-xs leading-[18px] font-base text-white/60">
Restrict this user to a number of successful queries or chats within a
24 hour window.
</p>
</div>
{enabled && (
<div className="mt-4">
<label className="text-white text-sm font-semibold block mb-4">
Message limit per day
</label>
<div className="relative mt-2">
<input
type="number"
onScroll={(e) => e.target.blur()}
onChange={(e) => {
updateState({
enabled: true,
limit: Number(e?.target?.value || 0),
});
}}
value={limit}
min={1}
className="bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:border-white block w-60 p-2.5"
/>
</div>
</div>
)}
</div>
);
}
3 changes: 0 additions & 3 deletions frontend/src/utils/paths.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,6 @@ export default {
return `/fine-tuning`;
},
settings: {
system: () => {
return `/settings/system-preferences`;
},
users: () => {
return `/settings/users`;
},
Expand Down
15 changes: 0 additions & 15 deletions server/endpoints/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -347,14 +347,6 @@ function adminEndpoints(app) {
: await SystemSettings.get({ label });

switch (label) {
case "limit_user_messages":
requestedSettings[label] = setting?.value === "true";
break;
case "message_limit":
requestedSettings[label] = setting?.value
? Number(setting.value)
: 10;
break;
case "footer_data":
requestedSettings[label] = setting?.value ?? JSON.stringify([]);
break;
Expand Down Expand Up @@ -422,13 +414,6 @@ function adminEndpoints(app) {
try {
const embedder = getEmbeddingEngineSelection();
const settings = {
limit_user_messages:
(await SystemSettings.get({ label: "limit_user_messages" }))
?.value === "true",
message_limit:
Number(
(await SystemSettings.get({ label: "message_limit" }))?.value
) || 10,
footer_data:
(await SystemSettings.get({ label: "footer_data" }))?.value ||
JSON.stringify([]),
Expand Down
Loading

0 comments on commit be6289d

Please sign in to comment.