Skip to content

Commit

Permalink
Merge pull request #110 from Gurubase/task/guru-edit-speedup
Browse files Browse the repository at this point in the history
Refactor guru detail fetching to support single guru retrieval
  • Loading branch information
aralyekta authored Feb 17, 2025
2 parents b255867 + ae445ca commit 8402f75
Show file tree
Hide file tree
Showing 16 changed files with 81 additions and 106 deletions.
1 change: 1 addition & 0 deletions src/gurubase-backend/backend/backend/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
path('guru_types/delete/<str:guru_type>/', core_views.delete_guru_type, name='delete_guru_type'),
path('<str:guru_type>/resources/detailed/', core_views.get_data_sources_detailed, name='get_data_sources_detailed'),
path('my_gurus/', core_views.my_gurus, name='my_gurus'),
path('my_gurus/<str:guru_slug>/', core_views.my_gurus, name='my_gurus_slug'),
path('<str:guru_type>/follow_up/examples/', core_views.follow_up_examples, name='follow_up_examples'),
path('<str:guru_type>/follow_up/graph/', core_views.follow_up_graph, name='follow_up_graph'),
path('<str:guru_type>/follow_up/binge/', core_views.create_binge, name='create_binge'),
Expand Down
17 changes: 12 additions & 5 deletions src/gurubase-backend/backend/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,18 +469,22 @@ def guru_type(request, slug):

@api_view(['GET'])
@jwt_auth
def my_gurus(request):
def my_gurus(request, guru_slug=None):
try:
if settings.ENV == 'selfhosted':
user = None
else:
user = User.objects.get(auth0_id=request.auth0_id)

if guru_slug:
sub_query = GuruType.objects.filter(slug=guru_slug)
else:
sub_query = GuruType.objects.all()

if settings.ENV == 'selfhosted' or user.is_admin:
user_gurus = GuruType.objects.filter(active=True).order_by('-date_created')

user_gurus = sub_query.filter(active=True).order_by('-date_created')
else:
user_gurus = GuruType.objects.filter(maintainers=user, active=True).order_by('-date_created')
user_gurus = sub_query.filter(maintainers=user, active=True).order_by('-date_created')

gurus_data = []
for guru in user_gurus:
Expand All @@ -507,7 +511,10 @@ def my_gurus(request):
'widget_ids': WidgetIdSerializer(widget_ids, many=True).data
})

return Response(gurus_data)
if guru_slug:
return Response(gurus_data[0], status=status.HTTP_200_OK)
else:
return Response(gurus_data, status=status.HTTP_200_OK)
except Exception as e:
logger.error(f'Error while fetching user gurus: {e}', exc_info=True)
return Response({'msg': str(e)}, status=500)
Expand Down
17 changes: 17 additions & 0 deletions src/gurubase-frontend/src/app/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,23 @@ export async function getMyGurus() {
}
}

export async function getMyGuru(guruSlug) {
try {
const response = await makeAuthenticatedRequest(
`${process.env.NEXT_PUBLIC_BACKEND_FETCH_URL}/my_gurus/${guruSlug}/`
);

if (!response) return null;
const data = await response.json();

return data;
} catch (error) {
return handleRequestError(error, {
url: `${process.env.NEXT_PUBLIC_BACKEND_FETCH_URL}/my_gurus/${guruSlug}/`
});
}
}

export async function createWidgetId(guruSlug, domainUrl) {
try {
const response = await makeAuthenticatedRequest(
Expand Down
14 changes: 3 additions & 11 deletions src/gurubase-frontend/src/app/guru/[customGuru]/analytics/page.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
import { redirect } from "next/navigation";

import { getMyGurus } from "@/app/actions";
import { getMyGuru } from "@/app/actions";
import AnalyticsPageLayout from "@/components/Analytics/AnalyticsPageLayout";

export default async function AnalyticsPage({ params, searchParams }) {
const { customGuru } = params;
const interval = searchParams.interval || "30d";

const guruTypes = await getMyGurus();
const guruData = await getMyGuru(customGuru);

return (
<AnalyticsPageLayout
customGuru={customGuru}
guruTypes={guruTypes}
initialInterval={interval}
/>
);
return <AnalyticsPageLayout guruData={guruData} initialInterval={interval} />;
}
Original file line number Diff line number Diff line change
@@ -1,35 +1,27 @@
import { redirect } from "next/navigation";

import { getGuruTypes, getMyGurus } from "@/app/actions";
import { getMyGuru } from "@/app/actions";
import IntegrationContent from "@/components/Integrations/IntegrationContent";
import IntegrationPayeLayout from "@/components/Integrations/IntegrationPayeLayout";
import WebWidgetIntegrationContent from "@/components/Integrations/WebWidgetIntegrationContent";

export default async function IntegrationsPage({ params, searchParams }) {
const { customGuru, integrationType } = params;
const type =
integrationType.charAt(0).toUpperCase() + integrationType.slice(1);

const guruTypes = await getMyGurus();
const currentGuru = guruTypes.find((guru) => guru.slug === customGuru);
const guruData = await getMyGuru(customGuru);

const selfhosted = process.env.NEXT_PUBLIC_NODE_ENV === "selfhosted";

// Determine which content component to use based on integration type
const getIntegrationContent = (selfhosted) => {
switch (integrationType) {
case "web_widget":
return (
<WebWidgetIntegrationContent
customGuru={customGuru}
guruData={currentGuru}
/>
);
return <WebWidgetIntegrationContent guruData={guruData} />;
case "slack":
case "discord":
return (
<IntegrationContent
customGuru={customGuru}
guruData={guruData}
error={searchParams?.error}
selfhosted={selfhosted}
type={integrationType}
Expand All @@ -46,11 +38,5 @@ export default async function IntegrationsPage({ params, searchParams }) {
redirect("/not-found");
}

return (
<IntegrationPayeLayout
content={content}
customGuru={customGuru}
guruTypes={guruTypes}
/>
);
return <IntegrationPayeLayout content={content} guruData={guruData} />;
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { getMyGurus } from "@/app/actions";
import { getMyGuru } from "@/app/actions";
import IntegrationPayeLayout from "@/components/Integrations/IntegrationPayeLayout";
import IntegrationTypesList from "@/components/Integrations/IntegrationTypesList";

export default async function IntegrationsPage({ params }) {
const { customGuru } = params;
const guruTypes = await getMyGurus();
const customGuruData = await getMyGuru(customGuru);

return (
<IntegrationPayeLayout
content={<IntegrationTypesList customGuru={customGuru} />}
customGuru={customGuru}
guruTypes={guruTypes}
content={<IntegrationTypesList guruData={customGuruData} />}
guruData={customGuruData}
/>
);
}
17 changes: 5 additions & 12 deletions src/gurubase-frontend/src/app/guru/[customGuru]/page.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { revalidateTag } from "next/cache";
import { notFound, redirect } from "next/navigation";

import { getGuruDataSources, getMyGurus } from "@/app/actions";
import { getGuruDataSources, getMyGuru } from "@/app/actions";
import { NewGuruClient } from "@/components/NewGuruClient";

export const viewport = {
Expand All @@ -25,19 +25,13 @@ const CustomGuru = async ({ params }) => {
revalidateTag("my-guru-types");

// Fetch guru types and data sources
const guruTypes = await getMyGurus();
const guruData = await getMyGuru(customGuru);

// Add null check for guruTypes
if (guruTypes.error) {
if (guruData.error) {
notFound();
}
const guru = guruTypes?.find(
(guru) => guru.slug.toLowerCase() === customGuru.toLowerCase()
);

if (!guru) {
notFound();
}
const dataSources = await getGuruDataSources(customGuru);

// Redirect if unauthorized (dataSources is null)
Expand All @@ -46,13 +40,12 @@ const CustomGuru = async ({ params }) => {
}

// Determine if the guru is still processing
const isProcessing = guru.ready === false;
const isProcessing = guruData.ready === false;

return (
<NewGuruClient
customGuru={customGuru}
guruData={guruData}
dataSources={dataSources}
guruTypes={guruTypes}
isProcessing={isProcessing}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,11 @@ const MetricSection = ({
);
};

const AnalyticsContent = ({ customGuru, initialInterval }) => {
const AnalyticsContent = ({ guruData, initialInterval }) => {
const router = useRouter();
const searchParams = useSearchParams();
const [interval, setInterval] = useState(initialInterval);
const guruType = customGuru;
const guruType = guruData?.slug;
const [searchQuery, setSearchQuery] = useState("");

const handleIntervalChange = (newInterval) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,16 @@ import AnalyticsContent from "./AnalyticsContent";

// TODO: This can be merged with IntegrationPageLayout

export const AnalyticsPageLayout = ({
customGuru,
guruTypes,
initialInterval
}) => {
export const AnalyticsPageLayout = ({ guruData, initialInterval }) => {
return (
<div className={`flex flex-col bg-white h-screen`}>
<Header sidebarExists={true} />
<CommonContentLayout
sidebar={
<GuruEditPageSidebar guruSlug={customGuru} guruTypes={guruTypes} />
}>
sidebar={<GuruEditPageSidebar guruData={guruData} />}>
<div className="flex gap-6">
<div className="flex-1">
<AnalyticsContent
customGuru={customGuru}
guruData={guruData}
initialInterval={initialInterval}
/>
</div>
Expand Down
9 changes: 5 additions & 4 deletions src/gurubase-frontend/src/components/GuruEditPageSidebar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,15 @@ const SidebarOption = ({ icon, label, isActive, onClick }) => (
</Button>
);

export default function GuruEditPageSidebar({ guruSlug, guruTypes }) {
export default function GuruEditPageSidebar({ guruData }) {
const router = useRouter();
const pathname = usePathname();
const navigation = useAppNavigation();

let guruSlug = guruData?.slug;
let guruName = guruData?.name;
let guruLogo = guruData?.icon_url;

const isSettingsActive = pathname === `/guru/${guruSlug}`;
const isIntegrationsActive = pathname.includes(
`/guru/${guruSlug}/integrations`
Expand All @@ -41,9 +45,6 @@ export default function GuruEditPageSidebar({ guruSlug, guruTypes }) {
navigation.push(path);
};

let guruName = guruTypes?.find((type) => type.slug === guruSlug)?.name;
let guruLogo = guruTypes?.find((type) => type.slug === guruSlug)?.icon_url;

if (!guruName) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import {
} from "@/components/ui/popover";
import Link from "next/link";

const IntegrationContent = ({ type, customGuru, error, selfhosted }) => {
const IntegrationContent = ({ type, guruData, error, selfhosted }) => {
const [integrationData, setIntegrationData] = useState(null);
const [channels, setChannels] = useState([]);
const [originalChannels, setOriginalChannels] = useState([]);
Expand Down Expand Up @@ -148,7 +148,7 @@ const IntegrationContent = ({ type, customGuru, error, selfhosted }) => {
try {
// Fetch integration details
const data = await getIntegrationDetails(
customGuru,
guruData?.slug,
type.toUpperCase()
);

Expand Down Expand Up @@ -181,7 +181,7 @@ const IntegrationContent = ({ type, customGuru, error, selfhosted }) => {
const fetchChannels = async () => {
try {
const channelsData = await getIntegrationChannels(
customGuru,
guruData?.slug,
type.toUpperCase()
);
if (channelsData?.error) {
Expand All @@ -205,7 +205,7 @@ const IntegrationContent = ({ type, customGuru, error, selfhosted }) => {
if (loading) {
fetchData();
}
}, [customGuru, type, loading]);
}, [guruData?.slug, type, loading]);

const Icon = config.icon;
const name = config.name;
Expand Down Expand Up @@ -477,7 +477,7 @@ const IntegrationContent = ({ type, customGuru, error, selfhosted }) => {
setIsSaving(true);
try {
const response = await saveIntegrationChannels(
customGuru,
guruData?.slug,
type.toUpperCase(),
channels.filter((c) => c.allowed)
);
Expand Down Expand Up @@ -527,7 +527,7 @@ const IntegrationContent = ({ type, customGuru, error, selfhosted }) => {
setIsDisconnecting(true);
try {
const response = await deleteIntegration(
customGuru,
guruData?.slug,
type.toUpperCase()
);
if (!response?.error) {
Expand Down Expand Up @@ -642,7 +642,7 @@ const IntegrationContent = ({ type, customGuru, error, selfhosted }) => {
setIsConnecting(true);
try {
const response = await createSelfhostedIntegration(
customGuru,
guruData?.slug,
type.toUpperCase(),
{
workspaceName,
Expand All @@ -669,7 +669,7 @@ const IntegrationContent = ({ type, customGuru, error, selfhosted }) => {
window.open(
`${integrationUrl}&state=${JSON.stringify({
type: type,
guru_type: customGuru,
guru_type: guruData?.slug,
encoded_guru_slug: integrationData?.encoded_guru_slug
})}`,
"_blank"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ import GuruEditPageSidebar from "@/components/GuruEditPageSidebar";
import Header from "@/components/Header";
import IntegrationContent from "@/components/Integrations/IntegrationContent";

export const IntegrationPayeLayout = ({ customGuru, guruTypes, content }) => {
export const IntegrationPayeLayout = ({ guruData, content }) => {
return (
<div className={`flex flex-col bg-white h-screen`}>
<Header sidebarExists={true} />
<CommonContentLayout
sidebar={
<GuruEditPageSidebar guruSlug={customGuru} guruTypes={guruTypes} />
}>
sidebar={<GuruEditPageSidebar guruData={guruData} />}>
<div className="flex gap-6">
<div className="flex-1">{content}</div>
</div>
Expand Down
Loading

0 comments on commit 8402f75

Please sign in to comment.