Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow manager to view roles (workspace) #3284

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { X, Gear } from "@phosphor-icons/react";
import System from "@/models/system";
import showToast from "@/utils/toast";
import { useEffect, useState } from "react";
import { userFromStorage } from "@/utils/request";

const NO_SETTINGS_NEEDED = ["default"];
export default function WorkspaceLLM({
Expand All @@ -20,6 +21,9 @@ export default function WorkspaceLLM({
const { isOpen, openModal, closeModal } = useModal();
const { name, value, logo, description } = llm;
const [currentSettings, setCurrentSettings] = useState(settings);
const [isConfigured, setIsConfigured] = useState(false);
const user = userFromStorage();
const isManager = user?.role === "manager";

useEffect(() => {
async function getSettings() {
Expand All @@ -31,14 +35,35 @@ export default function WorkspaceLLM({
getSettings();
}, [isOpen]);

useEffect(() => {
// Check if provider is configured by verifying all required config is set
const requiresAdditionalSetup = (llm.requiredConfig || []).some(
(key) => !currentSettings[key]
);
setIsConfigured(!requiresAdditionalSetup);
}, [currentSettings, llm]);

function handleProviderSelection() {
// If user is a manager, they can only select configured providers
if (isManager && !isConfigured && !NO_SETTINGS_NEEDED.includes(value)) {
showToast("This provider needs to be configured by an admin.", "error");
return;
}

// Determine if provider needs additional setup because its minimum required keys are
// not yet set in settings.
if (!checked) {
const requiresAdditionalSetup = (llm.requiredConfig || []).some(
(key) => !currentSettings[key]
);
if (requiresAdditionalSetup) {
if (isManager) {
showToast(
"This provider needs to be configured by an admin.",
"error"
);
return;
}
openModal();
return;
}
Expand Down Expand Up @@ -74,7 +99,7 @@ export default function WorkspaceLLM({
<div className="mt-1 text-xs text-white/60">{description}</div>
</div>
</div>
{checked && !NO_SETTINGS_NEEDED.includes(value) && (
{checked && !NO_SETTINGS_NEEDED.includes(value) && !isManager && (
<button
onClick={(e) => {
e.preventDefault();
Expand All @@ -88,14 +113,16 @@ export default function WorkspaceLLM({
)}
</div>
</div>
<SetupProvider
availableLLMs={availableLLMs}
isOpen={isOpen}
provider={value}
closeModal={closeModal}
postSubmit={onClick}
settings={currentSettings}
/>
{!isManager && (
<SetupProvider
availableLLMs={availableLLMs}
isOpen={isOpen}
provider={value}
closeModal={closeModal}
postSubmit={onClick}
settings={currentSettings}
/>
)}
</>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ChatModelSelection from "./ChatModelSelection";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import paths from "@/utils/paths";
import { userFromStorage } from "@/utils/request";

// Some providers do not support model selection via /models.
// In that case we allow the user to enter the model name manually and hope they
Expand All @@ -29,23 +30,37 @@ const LLM_DEFAULT = {
requiredConfig: [],
};

const LLMS = [LLM_DEFAULT, ...AVAILABLE_LLM_PROVIDERS].filter(
(llm) => !DISABLED_PROVIDERS.includes(llm.value)
);

export default function WorkspaceLLMSelection({
settings,
workspace,
setHasChanges,
}) {
const [searchQuery, setSearchQuery] = useState("");
const [filteredLLMs, setFilteredLLMs] = useState([]);
const [selectedLLM, setSelectedLLM] = useState(
workspace?.chatProvider ?? "default"
);
const [searchQuery, setSearchQuery] = useState("");
const [searchMenuOpen, setSearchMenuOpen] = useState(false);
const searchInputRef = useRef(null);
const { t } = useTranslation();
const user = userFromStorage();
const isManager = user?.role === "manager";

// Filter out disabled providers and for managers, only show configured providers
const LLMS = React.useMemo(() => {
const allLLMs = [LLM_DEFAULT, ...AVAILABLE_LLM_PROVIDERS].filter(
(llm) => !DISABLED_PROVIDERS.includes(llm.value)
);

if (!isManager) return allLLMs;

// For managers, only show providers that are fully configured
return allLLMs.filter((llm) => {
if (llm.value === "default") return true;
return !(llm.requiredConfig || []).some((key) => !settings?.[key]);
});
}, [settings, isManager]);

function updateLLMChoice(selection) {
setSearchQuery("");
setSelectedLLM(selection);
Expand All @@ -68,7 +83,9 @@ export default function WorkspaceLLMSelection({
);
setFilteredLLMs(filtered);
}, [LLMS, searchQuery, selectedLLM]);
const selectedLLMObject = LLMS.find((llm) => llm.value === selectedLLM);

const selectedLLMObject =
LLMS.find((llm) => llm.value === selectedLLM) || LLM_DEFAULT;

return (
<div className="border-b border-white/40 pb-8">
Expand Down
5 changes: 3 additions & 2 deletions server/endpoints/system.js
Original file line number Diff line number Diff line change
Expand Up @@ -953,14 +953,15 @@ function systemEndpoints(app) {

app.post(
"/system/custom-models",
[validatedRequest, flexUserRoleValid([ROLES.admin])],
[validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
async (request, response) => {
try {
const { provider, apiKey = null, basePath = null } = reqBody(request);
const { models, error } = await getCustomModels(
provider,
apiKey,
basePath
basePath,
response.locals?.user?.role
);
return response.status(200).json({
models,
Expand Down
Loading