diff --git a/apps/cyberstorm-remix/app/settings/teams/team/tabs/Members/Members.tsx b/apps/cyberstorm-remix/app/settings/teams/team/tabs/Members/Members.tsx index 477c406eb..2b544061b 100644 --- a/apps/cyberstorm-remix/app/settings/teams/team/tabs/Members/Members.tsx +++ b/apps/cyberstorm-remix/app/settings/teams/team/tabs/Members/Members.tsx @@ -1,6 +1,8 @@ -import "./Members.css"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faPlus, faTrashCan } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { useReducer, useState } from "react"; +import { useLoaderData, useOutletContext, useRevalidator } from "react-router"; + import { Modal, NewAvatar, @@ -13,50 +15,26 @@ import { type SelectOption, useToast, } from "@thunderstore/cyberstorm"; -import { type LoaderFunctionArgs } from "react-router"; -import { useLoaderData, useOutletContext, useRevalidator } from "react-router"; +import { TableSort } from "@thunderstore/cyberstorm/src/newComponents/Table/Table"; import { - ApiError, type RequestConfig, teamAddMember, type TeamAddMemberRequestData, teamEditMember, teamRemoveMember, } from "@thunderstore/thunderstore-api"; -import { type OutletContextShape } from "../../../../../root"; -import { TableSort } from "@thunderstore/cyberstorm/src/newComponents/Table/Table"; import { ApiAction } from "@thunderstore/ts-api-react-actions"; -import { DapperTs } from "@thunderstore/dapper-ts"; -import { getSessionTools } from "cyberstorm/security/publicEnvVariables"; + +import { type OutletContextShape } from "app/root"; +import { makeTeamSettingsTabLoader } from "cyberstorm/utils/dapperClientLoaders"; import { useStrongForm } from "cyberstorm/utils/StrongForm/useStrongForm"; -import { useReducer, useState } from "react"; +import "./Members.css"; -// REMIX TODO: Add check for "user has permission to see this page" -export async function clientLoader({ params }: LoaderFunctionArgs) { - if (params.namespaceId) { - try { - const tools = getSessionTools(); - const config = tools?.getConfig(); - const dapper = new DapperTs(() => { - return { - apiHost: config.apiHost, - sessionId: config.sessionId, - }; - }); - return { - teamName: params.namespaceId, - members: await dapper.getTeamMembers(params.namespaceId), - }; - } catch (error) { - if (error instanceof ApiError) { - throw new Response("Team members not found", { status: 404 }); - } else { - throw error; - } - } - } - throw new Response("Team not found", { status: 404 }); -} +export const clientLoader = makeTeamSettingsTabLoader( + async (dapper, teamName) => ({ + members: await dapper.getTeamMembers(teamName), + }) +); export function HydrateFallback() { return
Loading...
; diff --git a/apps/cyberstorm-remix/app/settings/teams/team/tabs/Profile/Profile.tsx b/apps/cyberstorm-remix/app/settings/teams/team/tabs/Profile/Profile.tsx index 18252986b..ef26cd41e 100644 --- a/apps/cyberstorm-remix/app/settings/teams/team/tabs/Profile/Profile.tsx +++ b/apps/cyberstorm-remix/app/settings/teams/team/tabs/Profile/Profile.tsx @@ -1,42 +1,25 @@ -import { type LoaderFunctionArgs } from "react-router"; +import { useReducer } from "react"; import { useLoaderData, useOutletContext, useRevalidator } from "react-router"; + +import { NewButton, NewTextInput, useToast } from "@thunderstore/cyberstorm"; import { - ApiError, teamDetailsEdit, type TeamDetailsEditRequestData, } from "@thunderstore/thunderstore-api"; -import { type OutletContextShape } from "~/root"; -import "./Profile.css"; -import { DapperTs } from "@thunderstore/dapper-ts"; -import { getSessionTools } from "cyberstorm/security/publicEnvVariables"; + +import { type OutletContextShape } from "app/root"; +import { makeTeamSettingsTabLoader } from "cyberstorm/utils/dapperClientLoaders"; import { useStrongForm } from "cyberstorm/utils/StrongForm/useStrongForm"; -import { useReducer } from "react"; -import { NewButton, NewTextInput, useToast } from "@thunderstore/cyberstorm"; +import "./Profile.css"; -export async function clientLoader({ params }: LoaderFunctionArgs) { - if (params.namespaceId) { - try { - const tools = getSessionTools(); - const dapper = new DapperTs(() => { - return { - apiHost: tools?.getConfig().apiHost, - sessionId: tools?.getConfig().sessionId, - }; - }); - return { - team: await dapper.getTeamDetails(params.namespaceId), - }; - } catch (error) { - if (error instanceof ApiError) { - throw new Response("Team not found", { status: 404 }); - } else { - // REMIX TODO: Add sentry - throw error; - } - } - } - throw new Response("Team not found", { status: 404 }); -} +export const clientLoader = makeTeamSettingsTabLoader( + async (dapper, teamName) => ({ + // TODO: for hygienie we shouldn't use this public endpoint but + // have an endpoint that confirms user permissions and returns + // possibly sensitive information. + team: await dapper.getTeamDetails(teamName), + }) +); export function HydrateFallback() { return
Loading...
; diff --git a/apps/cyberstorm-remix/app/settings/teams/team/tabs/ServiceAccounts/ServiceAccounts.tsx b/apps/cyberstorm-remix/app/settings/teams/team/tabs/ServiceAccounts/ServiceAccounts.tsx index fa5467811..81c822ab4 100644 --- a/apps/cyberstorm-remix/app/settings/teams/team/tabs/ServiceAccounts/ServiceAccounts.tsx +++ b/apps/cyberstorm-remix/app/settings/teams/team/tabs/ServiceAccounts/ServiceAccounts.tsx @@ -1,4 +1,8 @@ -import "./ServiceAccounts.css"; +import { faPlus } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { useReducer, useState } from "react"; +import { useLoaderData, useOutletContext, useRevalidator } from "react-router"; + import { NewAlert, NewButton, @@ -9,52 +13,24 @@ import { Heading, CodeBox, } from "@thunderstore/cyberstorm"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faPlus } from "@fortawesome/free-solid-svg-icons"; -import { type LoaderFunctionArgs } from "react-router"; -import { useLoaderData, useOutletContext, useRevalidator } from "react-router"; +import { TableSort } from "@thunderstore/cyberstorm/src/newComponents/Table/Table"; import { - ApiError, type RequestConfig, teamAddServiceAccount, type TeamServiceAccountAddRequestData, } from "@thunderstore/thunderstore-api"; -import { TableSort } from "@thunderstore/cyberstorm/src/newComponents/Table/Table"; -import { type OutletContextShape } from "../../../../../root"; -import { useReducer, useState } from "react"; -import { DapperTs } from "@thunderstore/dapper-ts"; -import { getSessionTools } from "cyberstorm/security/publicEnvVariables"; + +import { type OutletContextShape } from "app/root"; +import { makeTeamSettingsTabLoader } from "cyberstorm/utils/dapperClientLoaders"; import { useStrongForm } from "cyberstorm/utils/StrongForm/useStrongForm"; import { ServiceAccountRemoveModal } from "./ServiceAccountRemoveModal"; +import "./ServiceAccounts.css"; -// REMIX TODO: Add check for "user has permission to see this page" -export async function clientLoader({ params }: LoaderFunctionArgs) { - if (params.namespaceId) { - try { - const tools = getSessionTools(); - const config = tools?.getConfig(); - const dapper = new DapperTs(() => { - return { - apiHost: config?.apiHost, - sessionId: config?.sessionId, - }; - }); - return { - teamName: params.namespaceId, - serviceAccounts: await dapper.getTeamServiceAccounts( - params.namespaceId - ), - }; - } catch (error) { - if (error instanceof ApiError) { - throw new Response("Team not found", { status: 404 }); - } else { - throw error; - } - } - } - throw new Response("Team not found", { status: 404 }); -} +export const clientLoader = makeTeamSettingsTabLoader( + async (dapper, teamName) => ({ + serviceAccounts: await dapper.getTeamServiceAccounts(teamName), + }) +); export function HydrateFallback() { return
Loading...
; diff --git a/apps/cyberstorm-remix/app/settings/teams/team/tabs/Settings/Settings.tsx b/apps/cyberstorm-remix/app/settings/teams/team/tabs/Settings/Settings.tsx index bd1cb6879..c43c1ec15 100644 --- a/apps/cyberstorm-remix/app/settings/teams/team/tabs/Settings/Settings.tsx +++ b/apps/cyberstorm-remix/app/settings/teams/team/tabs/Settings/Settings.tsx @@ -1,3 +1,8 @@ +import { faTrashCan } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { useReducer, useState } from "react"; +import { useLoaderData, useNavigate, useOutletContext } from "react-router"; + import "./Settings.css"; import { NewAlert, @@ -8,11 +13,6 @@ import { NewTextInput, useToast, } from "@thunderstore/cyberstorm"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faTrashCan } from "@fortawesome/free-solid-svg-icons"; -import { useNavigate, useOutletContext, useParams } from "react-router"; - -import { type OutletContextShape } from "~/root"; import { type RequestConfig, teamDisband, @@ -20,24 +20,24 @@ import { teamRemoveMember, } from "@thunderstore/thunderstore-api"; import { ApiAction } from "@thunderstore/ts-api-react-actions"; -import { NotLoggedIn } from "~/commonComponents/NotLoggedIn/NotLoggedIn"; + +import { NotLoggedIn } from "app/commonComponents/NotLoggedIn/NotLoggedIn"; +import { type OutletContextShape } from "app/root"; +import { makeTeamSettingsTabLoader } from "cyberstorm/utils/dapperClientLoaders"; import { useStrongForm } from "cyberstorm/utils/StrongForm/useStrongForm"; -import { useReducer, useState } from "react"; -// REMIX TODO: Make sure user is redirected of this page, if the user is not logged in +export const clientLoader = makeTeamSettingsTabLoader( + // TODO: add end point for checking can leave/disband status. + async (dapper, teamName) => ({}) +); + export default function Settings() { - const params = useParams(); + const { teamName } = useLoaderData(); const outletContext = useOutletContext() as OutletContextShape; - if ( - !outletContext.currentUser || - !outletContext.currentUser.username || - !params.namespaceId - ) + if (!outletContext.currentUser || !outletContext.currentUser.username) return ; - if (!params.namespaceId) return

Team not found

; - const toast = useToast(); const navigate = useNavigate(); @@ -69,7 +69,7 @@ export default function Settings() {

You cannot currently disband this team as it has packages. -

You are about to disband the team {params.namespaceId}.

+

You are about to disband the team {teamName}.

Be aware you can currently only disband teams with no packages. If you need to archive a team with existing pages, contact Mythic#0001 on the Thunderstore Discord.

( + dataFetcher: (dapper: DapperTs, teamName: string) => Promise +) { + return async function clientLoader({ params }: LoaderFunctionArgs) { + const teamName = params.namespaceId!; + + try { + const dapper = setupDapper(); + const data = await dataFetcher(dapper, teamName); + return { teamName, ...data }; + } catch (error) { + if (error instanceof ApiError) { + const status = error.response.status; + const statusText = + (error.responseJson as GenericApiError)?.detail ?? + error.response.statusText; + throw new Response(statusText, { status, statusText }); + } + throw error; + } + }; +} + +const setupDapper = () => { + const tools = getSessionTools(); + const config = tools?.getConfig(); + return new DapperTs(() => ({ + apiHost: config?.apiHost, + sessionId: config?.sessionId, + })); +};