diff --git a/README.md b/README.md index e53a59b..8b5c06b 100644 --- a/README.md +++ b/README.md @@ -86,18 +86,19 @@ metadata: name: my-service annotations: flagsmith.com/project-id: '12345' - flagsmith.com/org-id: '67890' # Optional - defaults to first organization spec: type: service owner: team-a ``` +> **Note:** The organization ID is automatically derived from the project data. + ## Getting your Flagsmith credentials 1. Log in to your [Flagsmith dashboard](https://app.flagsmith.com) 2. Go to **Organisation Settings** > **API Keys** 3. Create or copy your **Admin API Key** -4. Find your **Project ID** and **Organisation ID** in the URL or project settings +4. Find your **Project ID** in the URL or project settings ## Development diff --git a/dev/index.tsx b/dev/index.tsx index ba4ef60..5643089 100644 --- a/dev/index.tsx +++ b/dev/index.tsx @@ -2,6 +2,7 @@ import { PropsWithChildren } from 'react'; import { createDevApp } from '@backstage/dev-utils'; import { EntityProvider } from '@backstage/plugin-catalog-react'; import { Entity } from '@backstage/catalog-model'; +import { Box, Grid } from '@material-ui/core'; import { setupWorker } from 'msw'; import { FlagsTab } from '../src/components/FlagsTab'; import { FlagsmithOverviewCard } from '../src/components/FlagsmithOverviewCard'; @@ -23,7 +24,6 @@ const mockEntity: Entity = { description: 'A demo service with Flagsmith feature flags integration', annotations: { 'flagsmith.com/project-id': '31465', - 'flagsmith.com/org-id': '24242', }, }, spec: { @@ -64,4 +64,25 @@ createDevApp() title: 'Overview Cards', path: '/flagsmith-cards', }) + .addPage({ + element: ( + + + + + + + + + + + + + + + + ), + title: 'Complete View', + path: '/flagsmith-complete', + }) .render(); diff --git a/src/components/FlagsmithUsageCard/index.tsx b/src/components/FlagsmithUsageCard/index.tsx index 7cef679..23e3415 100644 --- a/src/components/FlagsmithUsageCard/index.tsx +++ b/src/components/FlagsmithUsageCard/index.tsx @@ -20,14 +20,12 @@ export const FlagsmithUsageCard = () => { const { entity } = useEntity(); const projectId = entity.metadata.annotations?.['flagsmith.com/project-id']; - const orgId = entity.metadata.annotations?.['flagsmith.com/org-id']; - const { project, usageData, totalFlags, loading, error } = useFlagsmithUsage( - projectId, - orgId, - ); + const { project, usageData, totalFlags, loading, error } = useFlagsmithUsage(projectId); - const usageUrl = `${FLAGSMITH_DASHBOARD_URL}/organisation/${orgId}/usage`; + // Derive organization ID from project data for the dashboard link + const orgId = project?.organisation; + const usageUrl = orgId ? `${FLAGSMITH_DASHBOARD_URL}/organisation/${orgId}/usage` : undefined; if (loading) { return ( @@ -40,10 +38,7 @@ export const FlagsmithUsageCard = () => { if (error) { return ( - + ); } @@ -57,7 +52,7 @@ export const FlagsmithUsageCard = () => { title="Flags Usage Data (30 Days)" subheader={subheader} action={ - orgId && ( + usageUrl && ( diff --git a/src/hooks/useFlagsmithUsage.test.tsx b/src/hooks/useFlagsmithUsage.test.tsx index b60b289..4f09a9d 100644 --- a/src/hooks/useFlagsmithUsage.test.tsx +++ b/src/hooks/useFlagsmithUsage.test.tsx @@ -25,28 +25,29 @@ describe('useFlagsmithUsage', () => { jest.clearAllMocks(); }); - it('returns error when projectId or orgId is missing', async () => { - const { result } = renderHook(() => useFlagsmithUsage(undefined, '1'), { wrapper }); + it('returns error when projectId is missing', async () => { + const { result } = renderHook(() => useFlagsmithUsage(undefined), { wrapper }); await waitFor(() => expect(result.current.loading).toBe(false)); expect(result.current.error).toContain('Missing Flagsmith project ID'); }); - it('fetches usage data and calculates totalFlags', async () => { - const mockProject = { id: 123, name: 'Test', organisation: 1 }; + it('fetches usage data and derives orgId from project', async () => { + const mockProject = { id: 123, name: 'Test', organisation: 456 }; const mockUsage = [{ flags: 100, day: '2024-01-01' }, { flags: 200, day: '2024-01-02' }]; mockFetch .mockResolvedValueOnce({ ok: true, json: async () => mockProject }) .mockResolvedValueOnce({ ok: true, json: async () => mockUsage }); - const { result } = renderHook(() => useFlagsmithUsage('123', '1'), { wrapper }); + const { result } = renderHook(() => useFlagsmithUsage('123'), { wrapper }); await waitFor(() => expect(result.current.loading).toBe(false)); expect(result.current.project).toEqual(mockProject); expect(result.current.usageData).toEqual(mockUsage); expect(result.current.totalFlags).toBe(300); + expect(result.current.error).toBeNull(); }); }); diff --git a/src/hooks/useFlagsmithUsage.ts b/src/hooks/useFlagsmithUsage.ts index 95ccaee..085928a 100644 --- a/src/hooks/useFlagsmithUsage.ts +++ b/src/hooks/useFlagsmithUsage.ts @@ -16,7 +16,6 @@ export interface UseFlagsmithUsageResult { export function useFlagsmithUsage( projectId: string | undefined, - orgId: string | undefined, ): UseFlagsmithUsageResult { const discoveryApi = useApi(discoveryApiRef); const fetchApi = useApi(fetchApiRef); @@ -33,19 +32,21 @@ export function useFlagsmithUsage( const [error, setError] = useState(null); useEffect(() => { - if (!projectId || !orgId) { - setError('Missing Flagsmith project ID or organization ID in entity annotations'); + if (!projectId) { + setError('Missing Flagsmith project ID in entity annotations'); setLoading(false); return; } const fetchData = async () => { try { + // Fetch project data to get the organization ID const projectData = await client.getProject(parseInt(projectId, 10)); setProject(projectData); + // Derive organization ID from project data const usage = await client.getUsageData( - parseInt(orgId, 10), + projectData.organisation, parseInt(projectId, 10), ); setUsageData(usage); @@ -57,7 +58,7 @@ export function useFlagsmithUsage( }; fetchData(); - }, [projectId, orgId, client]); + }, [projectId, client]); const totalFlags = usageData.reduce((sum, day) => sum + (day.flags ?? 0), 0);