Sunil Katkar
07/01/2025, 11:12 AMJulius Kos
07/01/2025, 1:27 PMSunil Katkar
07/01/2025, 2:26 PMJulius Kos
07/01/2025, 6:39 PMJulius Kos
07/01/2025, 6:41 PMSunil Katkar
07/01/2025, 7:45 PMJulius Kos
07/02/2025, 12:26 PMSunil Katkar
07/08/2025, 6:41 AMJulius Kos
07/08/2025, 7:59 AMSunil Katkar
07/09/2025, 11:33 AM@gooddata/sdk-ui-dashboardimport React, { useState } from 'react';
import { Dashboard } from "@gooddata/sdk-ui-dashboard";
import tigerBackendFactory, { TigerTokenAuthProvider } from "@gooddata/sdk-backend-tiger";
import { BackendProvider, WorkspaceProvider } from "@gooddata/sdk-ui";
function Report() {
  const [dashboardId] = useState('dummy_dashboard_id'); // example: "ad56b32abc1243d78e2aa03e905c70e7"
  const [workspaceId] = useState('dummy_workspace_id'); // example: "acme_workspace_123"
  const personalToken = process.env.REACT_APP_PERSONAL_TOKEN;  
  const goodDataUrl = process.env.REACT_APP_GOOD_DATA;
  const backend = tigerBackendFactory({
    hostname: goodDataUrl
  }).withAuthentication(new TigerTokenAuthProvider(personalToken));
  return (
    <BackendProvider backend={backend}>
      <WorkspaceProvider workspace={workspaceId}>
        <Dashboard dashboard={dashboardId} />
      </WorkspaceProvider>
    </BackendProvider>
  );
}
export default Report;DashboardViewDashboardRadek Novacek
07/10/2025, 9:13 AMimport React, { useEffect, useState } from "react";
import {
  changeAttributeFilterSelection,
  CustomDashboardWidgetComponent,
  DashboardConfig,
  DashboardContext,
  DashboardPluginV1,
  IDashboardCustomizer,
  IDashboardEventHandling,
  newCustomWidget,
  newDashboardItem,
  newDashboardSection,
  resetAttributeFilterSelection,
  selectFilterContextAttributeFilterByDisplayForm,
  useDashboardSelector,
  useDispatchDashboardCommand,
} from "@gooddata/sdk-ui-dashboard";
import { idRef } from "@gooddata/sdk-model";
import { useDashboardLoader } from "@gooddata/sdk-ui-loaders";
import { LoadingComponent } from "@gooddata/sdk-ui";
const dashboardRef = import.meta.env.VITE_GD_DASHBOARD;
const config: DashboardConfig = { isReadOnly: true };
// Custom widget with default filter applied on mount
const MyCustomWidget: CustomDashboardWidgetComponent = () => {
  const changeAttributeFilterSelectionCmd = useDispatchDashboardCommand(
    changeAttributeFilterSelection
  );
  const resetAttributeFilter = useDispatchDashboardCommand(
    resetAttributeFilterSelection
  );
  const filterLocalId = useDashboardSelector(
    selectFilterContextAttributeFilterByDisplayForm(idRef("customer_country"))
  )?.attributeFilter.localIdentifier;
  // Avoid infinite loops by only running once
  const [initialized, setInitialized] = useState(false);
  useEffect(() => {
    if (!initialized && filterLocalId) {
      changeAttributeFilterSelectionCmd(
        filterLocalId,
        { values: ["Canada"] },
        "IN"
      );
      setInitialized(true);
    }
  }, [filterLocalId, initialized, changeAttributeFilterSelectionCmd]);
  // Helper function to apply filter values
  const applyFilter = (values: string[]) => {
    if (!filterLocalId) return;
    changeAttributeFilterSelectionCmd(filterLocalId, { values }, "IN");
  };
  const resetFilterSelection = () => {
    if (filterLocalId) {
      resetAttributeFilter(filterLocalId);
    }
  };
  return (
    <div>
      <button onClick={() => applyFilter(["United States"])}>
        Filter: United States
      </button>
      <button onClick={() => applyFilter(["Canada"])}>Filter: Canada</button>
      <button onClick={() => applyFilter(["United States", "Canada"])}>
        Filter: Both
      </button>
      <button onClick={resetFilterSelection}>Reset Filter</button>
    </div>
  );
};
// Dashboard plugin registering the widget and layout
class LocalPlugin extends DashboardPluginV1 {
  public readonly author = "GD Support";
  public readonly displayName = "Sample filter plugin";
  public readonly version = "1.0";
  public register(
    _ctx: DashboardContext,
    customize: IDashboardCustomizer,
    _handlers: IDashboardEventHandling
  ): void {
    customize.customWidgets().addCustomWidget("myCustomWidget", MyCustomWidget);
    customize.layout().customizeFluidLayout((_layout, customizer) => {
      customizer.addSection(
        0,
        newDashboardSection(
          "Buttons to dispatch filter commands",
          newDashboardItem(newCustomWidget("myWidget1", "myCustomWidget"), {
            xl: {
              gridWidth: 12,
              gridHeight: 3,
            },
          })
        )
      );
    });
  }
}
const LocalExtraPlugin = {
  factory: () => new LocalPlugin(),
};
const App: React.FC = () => {
  const { status, result, error } = useDashboardLoader({
    dashboard: dashboardRef,
    loadingMode: "staticOnly",
    extraPlugins: LocalExtraPlugin,
  });
  if (status === "loading" || status === "pending") {
    return <LoadingComponent />;
  }
  if (error) {
    return <div>Error loading dashboard...</div>;
  }
  const { DashboardComponent, props: dashboardProps } = result!;
  return (
    <div>
      <DashboardComponent {...dashboardProps} config={config} />
    </div>
  );
};
export default App;idRef("customer_country")filterLocalIdRadek Novacek
07/15/2025, 6:15 AMSunil Katkar
07/15/2025, 1:41 PMRadek Novacek
07/15/2025, 1:43 PMSunil Katkar
07/15/2025, 3:47 PMSunil Katkar
07/16/2025, 2:25 PMRadek Novacek
07/17/2025, 6:39 AMSunil Katkar
07/21/2025, 11:50 AMRadek Novacek
07/21/2025, 12:14 PMconst dashboardRef = import.meta.env.VITE_GD_DASHBOARD;
const config: DashboardConfig = { isReadOnly: true };
// Custom widget with default filter applied on mount
const MyCustomWidget: CustomDashboardWidgetComponent = () => {
  const changeAttributeFilterSelectionCmd = useDispatchDashboardCommand(
    changeAttributeFilterSelection
  );
  const resetAttributeFilter = useDispatchDashboardCommand(
    resetAttributeFilterSelection
  );
  const filterLocalId = useDashboardSelector(
    selectFilterContextAttributeFilterByDisplayForm(idRef("customer_country"))
  )?.attributeFilter.localIdentifier;
  // Avoid infinite loops by only running once
  const [initialized, setInitialized] = useState(false);
  useEffect(() => {
    if (!initialized && filterLocalId) {
      changeAttributeFilterSelectionCmd(
        filterLocalId,
        { values: ["Canada"] },
        "IN"
      );
      setInitialized(true);
    }
  }, [filterLocalId, initialized, changeAttributeFilterSelectionCmd]);
  // Helper function to apply filter values
  const applyFilter = (values: string[]) => {
    if (!filterLocalId) return;
    changeAttributeFilterSelectionCmd(filterLocalId, { values }, "IN");
  };
  const resetFilterSelection = () => {
    if (filterLocalId) {
      resetAttributeFilter(filterLocalId);
    }
  };
  return (
    <div>
      <button onClick={() => applyFilter(["United States"])}>
        Filter: United States
      </button>
      <button onClick={() => applyFilter(["Canada"])}>Filter: Canada</button>
      <button onClick={() => applyFilter(["United States", "Canada"])}>
        Filter: Both
      </button>
      <button onClick={resetFilterSelection}>Reset Filter</button>
    </div>
  );
};// Dashboard plugin registering the widget and layout
class LocalPlugin extends DashboardPluginV1 {
  public readonly author = "GD Support";
  public readonly displayName = "Sample filter plugin";
  public readonly version = "1.0";
  public register(
    _ctx: DashboardContext,
    customize: IDashboardCustomizer,
    _handlers: IDashboardEventHandling
  ): void {
    customize.customWidgets().addCustomWidget("myCustomWidget", MyCustomWidget);
    customize.layout().customizeFluidLayout((_layout, customizer) => {
      customizer.addSection(
        0,
        newDashboardSection(
          "Buttons to dispatch filter commands",
          newDashboardItem(newCustomWidget("myWidget1", "myCustomWidget"), {
            xl: {
              gridWidth: 12,
              gridHeight: 3,
            },
          })
        )
      );
    });
  }
}
const LocalExtraPlugin = {
  factory: () => new LocalPlugin(),
};const App: React.FC = () => {
  const { status, result, error } = useDashboardLoader({
    dashboard: dashboardRef,
    loadingMode: "staticOnly",
    extraPlugins: LocalExtraPlugin,
  });
  if (status === "loading" || status === "pending") {
    return <LoadingComponent />;
  }
  if (error) {
    return <div>Error loading dashboard...</div>;
  }
  const { DashboardComponent, props: dashboardProps } = result!;
  return (
    <div>
      <DashboardComponent {...dashboardProps} config={config} />
    </div>
  );
};Sunil Katkar
07/22/2025, 6:11 PMimport React from "react";
import GoodDataDashboard from "./GoodDataDashboard";
import tigerBackendFactory, {
  TigerTokenAuthProvider
} from "@gooddata/sdk-backend-tiger";
import { BackendProvider, WorkspaceProvider } from "@gooddata/sdk-ui";
const personalToken = 'cmFtX3ZpZ25lc2g6cmFtc190b2tlbjpwYVE1czBQU241L3QxcjdsSG80aThqR2lNU20r======';
const goodDataUrl = '<https://sustain360-dev.cloud.gooddata.com>';
const backend = tigerBackendFactory({
    hostname: goodDataUrl
}).withAuthentication(
    new TigerTokenAuthProvider(personalToken)
);
const workspace = "your_workspace_id";
const App: React.FC = () => {
  return (
    <BackendProvider backend={backend}>
      <WorkspaceProvider workspace={workspace}>
        <h1>Custom Dashboard</h1>
        <GoodDataDashboard />
      </WorkspaceProvider>
    </BackendProvider>
  );
};
export default App;Type 'import("c:/Users/DELL/Downloads/gooddata-dashboard-webpack/gooddata-dashboard-webpack/node_modules/@gooddata/sdk-backend-base/node_modules/@gooddata/sdk-backend-spi/esm/backend/index").IAnalyticalBackend' is not assignable to type 'import("c:/Users/DELL/Downloads/gooddata-dashboard-webpack/gooddata-dashboard-webpack/node_modules/@gooddata/sdk-ui-loaders/node_modules/@gooddata/sdk-backend-spi/esm/backend/index").IAnalyticalBackend'.
  Types of property 'withAuthentication' are incompatible.
    Type '(provider: import("c:/Users/DELL/Downloads/gooddata-dashboard-webpack/gooddata-dashboard-webpack/node_modules/@gooddata/sdk-backend-base/node_modules/@gooddata/sdk-backend-spi/esm/backend/index").IAuthenticationProvider) => import("c:/Users/DELL/Downloads/gooddata-dashboard-webpack/gooddata-dashboard-webpack/node_mo...' is not assignable to type '(provider: import("c:/Users/DELL/Downloads/gooddata-dashboard-webpack/gooddata-dashboard-webpack/node_modules/@gooddata/sdk-ui-loaders/node_modules/@gooddata/sdk-backend-spi/esm/backend/index").IAuthenticationProvider) => import("c:/Users/DELL/Downloads/gooddata-dashboard-webpack/gooddata-dashboard-webpack/node_modu...'.
      Types of parameters 'provider' and 'provider' are incompatible.
        Property 'disablePrincipalCache' is missing in type 'import("c:/Users/DELL/Downloads/gooddata-dashboard-webpack/gooddata-dashboard-webpack/node_modules/@gooddata/sdk-ui-loaders/node_modules/@gooddata/sdk-backend-spi/esm/backend/index").IAuthenticationProvider' but required in type 'import("c:/Users/DELL/Downloads/gooddata-dashboard-webpack/gooddata-dashboard-webpack/node_modules/@gooddata/sdk-backend-base/node_modules/@gooddata/sdk-backend-spi/esm/backend/index").IAuthenticationProvider'.ts(2322)
index.d.ts(235, 5): 'disablePrincipalCache' is declared here.
BackendContext.d.ts(11, 5): The expected type comes from property 'backend' which is declared here on type 'IntrinsicAttributes & IBackendProviderProps'"@gooddata/api-client-bear": "^9.9.0",
    "@gooddata/api-client-tiger": "^10.4.0",
    "@gooddata/sdk-backend-tiger": "^10.4.0",
    "@gooddata/sdk-ui": "^10.4.0",
    "@gooddata/sdk-ui-charts": "^10.4.0",
    "@gooddata/sdk-ui-dashboard": "^10.4.0",
    "@gooddata/sdk-ui-kit": "^10.4.0",
    "@gooddata/sdk-ui-loaders": "^10.34.0",
    "@gooddata/sdk-ui-theme-provider": "^10.4.0",Radek Novacek
07/23/2025, 6:13 AMRadek Novacek
07/23/2025, 6:22 AMsdk-backend-spiapi-client-bearRadek Novacek
07/23/2025, 6:29 AMSunil Katkar
07/23/2025, 9:16 AMSunil Katkar
07/23/2025, 9:20 AMimport React, { useState, useEffect, useCallback } from 'react';
import { Dashboard } from '@gooddata/sdk-ui-dashboard';
import tigerBackendFactory, {
    TigerTokenAuthProvider
} from '@gooddata/sdk-backend-tiger';
import { BackendProvider, WorkspaceProvider } from '@gooddata/sdk-ui';
// --- CORRECTED IMPORT FOR FILTERS ---
import { newPositiveAttributeFilter, uriRef } from '@gooddata/sdk-model'; // Use newPositiveAttributeFilter
// --- END CORRECTED IMPORT ---
const GOODDATA_HOST = '<https://test-dev.cloud.gooddata.com/>';
const GOODDATA_WORKSPACE_ID = '62dd165920bd44feb45fb89def254196';
const GOODDATA_DASHBOARD_ID = '2a6e103a-6b29-483d-9e0c-95651d24ca12';
const GOODDATA_PAT = 'bmF2ZWVuX2NoYXVyYXNpYToxMjM0OjRUOTBKWm===========EZWNWtzNTNHN3BzRlls';
// Define the identifiers for your Organization and Sub-organization attributes/labels
const ORGANIZATION_ATTRIBUTE_IDENTIFIER = 'label.organization_id';
const SUB_ORGANIZATION_ATTRIBUTE_IDENTIFIER = 'label.sub_organization_id'; // <-- VERIFY THIS AGAINST YOUR GOODDATA LDM
const GoodDataDashboardEmbed = ({ selectedOrganization, selectedSubOrganization }) => {
    const [backend, setBackend] = useState(null);
    const [isLoadingBackend, setIsLoadingBackend] = useState(true);
    const [backendError, setBackendError] = useState(null);
    
    useEffect(() => {
        const initializeBackend = async () => {
            try {
                const authProvider = new TigerTokenAuthProvider(GOODDATA_PAT);
                const newBackend =  tigerBackendFactory({
                        hostname: GOODDATA_HOST
                    }).withAuthentication(
                        new TigerTokenAuthProvider(GOODDATA_PAT)
                    );
                setBackend(newBackend);
                setIsLoadingBackend(false);
            } catch (error) {
                console.error("Failed to initialize GoodData backend:", error);
                setBackendError("Failed to initialize dashboard. Check console for details.");
                setIsLoadingBackend(false);
            }
        };
        initializeBackend();
    }, []);
    const dashboardFilters = useCallback(() => {
        const filters = [];
        if (selectedOrganization) {
            const values = selectedOrganization.split(',').map(item => item.trim()).filter(Boolean);
            if (values.length > 0) {
                // --- CORRECTED FILTER CREATION ---
                filters.push(
                    newPositiveAttributeFilter(
                        uriRef(ORGANIZATION_ATTRIBUTE_IDENTIFIER), // Attribute ObjRef
                        values,                                   // Array of selected values
                        true                                      // 'in' operator (include)
                    )
                );
                // --- END CORRECTED FILTER CREATION ---
            }
        }
        if (selectedSubOrganization) {
            const values = selectedSubOrganization.split(',').map(item => item.trim()).filter(Boolean);
            if (values.length > 0) {
                // --- CORRECTED FILTER CREATION ---
                filters.push(
                    newPositiveAttributeFilter(
                        uriRef(SUB_ORGANIZATION_ATTRIBUTE_IDENTIFIER), // Attribute ObjRef
                        values,                                        // Array of selected values
                        true                                           // 'in' operator (include)
                    )
                );
                // --- END CORRECTED FILTER CREATION ---
            }
        }
        return filters;
    }, [selectedOrganization, selectedSubOrganization]);
    if (isLoadingBackend) {
        return <div style={{ textAlign: 'center', padding: '20px' }}>Loading GoodData services...</div>;
    }
    if (backendError) {
        return <div style={{ color: 'red', textAlign: 'center', padding: '20px' }}>Error: {backendError}</div>;
    }
    if (!backend) {
        return <div style={{ textAlign: 'center', padding: '20px' }}>Backend not available.</div>;
    }
    return (
        <div style={{ height: '800px', width: '100%', border: '1px solid #ddd', borderRadius: '8px', overflow: 'hidden' }}>
            <BackendProvider backend={backend}>
                <WorkspaceProvider workspace={GOODDATA_WORKSPACE_ID}>
                    <Dashboard
                        dashboard={GOODDATA_DASHBOARD_ID}
                        filters={dashboardFilters()}
                        config={{
                            menuVisible: false,
                        }}
                        onLoadingChanged={(loading) => console.log('Dashboard loading:', loading)}
                        onError={(error) => console.error('Dashboard error:', error)}
                    />
                </WorkspaceProvider>
            </BackendProvider>
        </div>
    );
};
export default GoodDataDashboardEmbed;CorrelationContext.tsx:94  Uncaught TypeError: effectiveBackend.withCorrelation is not a function
    at CorrelationContext.tsx:94:1
    at mountMemo (react-dom.development.js:17225:1)
    at Object.useMemo (react-dom.development.js:17670:1)
    at useMemo (react.development.js:1650:1)
    at useBackendWithCorrelation (CorrelationContext.tsx:90:1)
    at useBackendWithDashboardCorrelation (Dashboard.tsx:59:1)
    at Dashboard (Dashboard.tsx:22:1)
    at renderWithHooks (react-dom.development.js:16305:1)
    at mountIndeterminateComponent (react-dom.development.js:20074:1)
    at beginWork (react-dom.development.js:21587:1)Radek Novacek
07/23/2025, 9:26 AMSunil Katkar
07/24/2025, 10:55 AMRadek Novacek
07/24/2025, 10:57 AMSunil Katkar
07/24/2025, 11:32 AMimport React, { useState, useEffect, useCallback } from 'react';
import { Dashboard } from '@gooddata/sdk-ui-dashboard';
import tigerBackendFactory, { // Default export for the backend factory
    TigerTokenAuthProvider      // Named export for PAT authentication
} from '@gooddata/sdk-backend-tiger';
import { BackendProvider, WorkspaceProvider } from '@gooddata/sdk-ui';
// Import newPositiveAttributeFilter as it was found in your possible exports list
import { newPositiveAttributeFilter, uriRef } from '@gooddata/sdk-model'; 
const GOODDATA_HOST = '<https://test-dev.cloud.gooddata.com>';
const GOODDATA_WORKSPACE_ID = 'WorkspaceId';
const GOODDATA_DASHBOARD_ID = 'Dashboard ID';
const GOODDATA_PAT = 'TOken';
// --- Attribute Identifiers for Filtering ---
// Based on your previous JSON, 'label.organization_id' is correct for Organization.
// !!! VERIFY 'label.sub_organization_id' against your GoodData Logical Data Model !!!
// You can find these in GoodData UI (e.g., Analytical Designer) or API Explorer.
const ORGANIZATION_ATTRIBUTE_IDENTIFIER = 'label.organization_id'; 
const SUB_ORGANIZATION_ATTRIBUTE_IDENTIFIER = 'label.suborganization_id'; // Example, please verify!
const GoodDataDashboardEmbed = ({ selectedOrganization, selectedSubOrganization }) => {
    const [backend, setBackend] = useState(null);
    const [isLoadingBackend, setIsLoadingBackend] = useState(true);
    const [backendError, setBackendError] = useState(null);
    useEffect(() => {
        const initializeGoodDataBackend = async () => {
            try {
                const goodDataBackendInstance = tigerBackendFactory({
                        hostname: GOODDATA_HOST
                    }).withAuthentication(
                        new TigerTokenAuthProvider(GOODDATA_PAT)
                    );
                setBackend(goodDataBackendInstance);
                setIsLoadingBackend(false);
            } catch (error) {
                console.error("GoodData Backend Initialization Error:", error);
                setBackendError("Failed to initialize GoodData dashboard. Please check console for details and ensure configuration (host, PAT) is correct.");
                setIsLoadingBackend(false);
            }
        };
        initializeGoodDataBackend();
    }, []); // Empty dependency array ensures this runs only once on component mount
    // Memoize the filters to avoid unnecessary re-renders of the dashboard.
    // This function will re-run only when selectedOrganization or selectedSubOrganization props change.
    const getDashboardFilters = useCallback(() => {
        const filters = [];
        // Apply Organization filter if a value is provided
        if (selectedOrganization) {
            // Split comma-separated values, trim whitespace, and filter out empty strings
            const orgValues = selectedOrganization.split(',').map(item => item.trim()).filter(Boolean);
            if (orgValues.length > 0) {
                filters.push(
                    // Use newPositiveAttributeFilter with uriRef for the attribute and the array of values
                    newPositiveAttributeFilter(
                        uriRef(ORGANIZATION_ATTRIBUTE_IDENTIFIER), // Convert string identifier to ObjRef
                        orgValues,                                 // Array of values to filter by
                        true                                       // 'true' for 'in' (include) operator
                    )
                );
            }
        }
        // Apply Sub-organization filter if a value is provided
        if (selectedSubOrganization) {
            const subOrgValues = selectedSubOrganization.split(',').map(item => item.trim()).filter(Boolean);
            if (subOrgValues.length > 0) {
                filters.push(
                    newPositiveAttributeFilter(
                        uriRef(SUB_ORGANIZATION_ATTRIBUTE_IDENTIFIER), // Convert string identifier to ObjRef
                        subOrgValues,                                  // Array of values to filter by
                        true                                           // 'true' for 'in' (include) operator
                    )
                );
            }
        }
        return filters;
    }, [selectedOrganization, selectedSubOrganization]);
    // --- Loading and Error Handling UI ---
    if (isLoadingBackend) {
        return <div style={{ textAlign: 'center', padding: '20px', fontSize: '1.2em' }}>Loading GoodData services...</div>;
    }
    if (backendError) {
        return <div style={{ color: 'red', textAlign: 'center', padding: '20px', border: '1px solid red', borderRadius: '5px' }}>
            <strong>Error:</strong> {backendError}
        </div>;
    }
    if (!backend) {
        // This case should ideally be caught by isLoadingBackend and backendError, but serves as a final fallback.
        return <div style={{ textAlign: 'center', padding: '20px' }}>GoodData backend could not be initialized.</div>;
    }
    // --- Render the GoodData Dashboard ---
    return (
        <>
        <BackendProvider backend={backend}>
            <WorkspaceProvider workspace={GOODDATA_WORKSPACE_ID}>
                <Dashboard dashboard={GOODDATA_DASHBOARD_ID} />
            </WorkspaceProvider>
        </BackendProvider>
        </>
    );
};
export default GoodDataDashboardEmbed;Radek Novacek
07/24/2025, 12:07 PMSunil Katkar
07/24/2025, 12:32 PMimport React, { useState, useEffect, useCallback } from 'react';
import { Dashboard } from '@gooddata/sdk-ui-dashboard';
import tigerBackendFactory, {
    TigerTokenAuthProvider
} from '@gooddata/sdk-backend-tiger';
import { BackendProvider, WorkspaceProvider } from '@gooddata/sdk-ui';
import { newPositiveAttributeFilter, uriRef } from '@gooddata/sdk-model';
const GOODDATA_HOST = '<https://test-dev.cloud.gooddata.com>';
const GOODDATA_WORKSPACE_ID = '=======workspace id========';
const GOODDATA_DASHBOARD_ID = '=======dashboard id========';
const GOODDATA_PAT = '========personal access token==========';
const ORGANIZATION_ATTRIBUTE_IDENTIFIER = 'label.organization_id'; 
const SUB_ORGANIZATION_ATTRIBUTE_IDENTIFIER = 'label.suborganization_id'; // Example, please verify!
const GoodDataDashboardEmbed = ({ selectedOrganization, selectedSubOrganization }) => {
    const [backend, setBackend] = useState(null);
    const [isLoadingBackend, setIsLoadingBackend] = useState(true);
    const [backendError, setBackendError] = useState(null);
    useEffect(() => {
        const initializeGoodDataBackend = async () => {
            try {
                const goodDataBackendInstance = tigerBackendFactory({
                        hostname: GOODDATA_HOST
                    }).withAuthentication(
                        new TigerTokenAuthProvider(GOODDATA_PAT)
                    );
                setBackend(goodDataBackendInstance);
                setIsLoadingBackend(false);
            } catch (error) {
                console.error("GoodData Backend Initialization Error:", error);
                setBackendError("Failed to initialize GoodData dashboard. Please check console for details and ensure configuration (host, PAT) is correct.");
                setIsLoadingBackend(false);
            }
        };
        initializeGoodDataBackend();
    }, []); // Empty dependency array ensures this runs only once on component mount
    // Memoize the filters to avoid unnecessary re-renders of the dashboard.
    // This function will re-run only when selectedOrganization or selectedSubOrganization props change.
    const getDashboardFilters = useCallback(() => {
        const filters = [];
        // Apply Organization filter if a value is provided
        if (selectedOrganization) {
            // Split comma-separated values, trim whitespace, and filter out empty strings
            const orgValues = selectedOrganization.split(',').map(item => item.trim()).filter(Boolean);
            if (orgValues.length > 0) {
                filters.push(
                    // Use newPositiveAttributeFilter with uriRef for the attribute and the array of values
                    newPositiveAttributeFilter(
                        uriRef(ORGANIZATION_ATTRIBUTE_IDENTIFIER), // Convert string identifier to ObjRef
                        orgValues,                                 // Array of values to filter by
                        true                                       // 'true' for 'in' (include) operator
                    )
                );
            }
        }
        // Apply Sub-organization filter if a value is provided
        if (selectedSubOrganization) {
            const subOrgValues = selectedSubOrganization.split(',').map(item => item.trim()).filter(Boolean);
            if (subOrgValues.length > 0) {
                filters.push(
                    newPositiveAttributeFilter(
                        uriRef(SUB_ORGANIZATION_ATTRIBUTE_IDENTIFIER), // Convert string identifier to ObjRef
                        subOrgValues,                                  // Array of values to filter by
                        true                                           // 'true' for 'in' (include) operator
                    )
                );
            }
        }
        return filters;
    }, [selectedOrganization, selectedSubOrganization]);
    // --- Loading and Error Handling UI ---
    if (isLoadingBackend) {
        return <div style={{ textAlign: 'center', padding: '20px', fontSize: '1.2em' }}>Loading GoodData services...</div>;
    }
    if (backendError) {
        return <div style={{ color: 'red', textAlign: 'center', padding: '20px', border: '1px solid red', borderRadius: '5px' }}>
            <strong>Error:</strong> {backendError}
        </div>;
    }
    if (!backend) {
        // This case should ideally be caught by isLoadingBackend and backendError, but serves as a final fallback.
        return <div style={{ textAlign: 'center', padding: '20px' }}>GoodData backend could not be initialized.</div>;
    }
    // --- Render the GoodData Dashboard ---
    return (
        <>
        {/* <BackendProvider backend={backend}>
            <WorkspaceProvider workspace={'62dd165920bd44feb45fb89def254196'}>
                <Dashboard dashboard={'2a6e103a-6b29-483d-9e0c-95651d24ca12'} />
            </WorkspaceProvider>
        </BackendProvider> */}
        <BackendProvider backend={backend}>
                <WorkspaceProvider workspace={GOODDATA_WORKSPACE_ID}>
                    <Dashboard
                        dashboard={GOODDATA_DASHBOARD_ID}
                        filters={getDashboardFilters()}
                        onLoadingChanged={(loading) => console.log('Dashboard loading:', loading)}
                        onError={(error) => console.error('Dashboard error:', error)}
                    />
                </WorkspaceProvider>
            </BackendProvider>
        </>
    );
};
export default GoodDataDashboardEmbed;import React, { useState } from 'react';
import GoodDataDashboardEmbed from './GoodDataDashboardEmbed';
import "@gooddata/sdk-ui-filters/styles/css/main.css";
import "@gooddata/sdk-ui-charts/styles/css/main.css";
import "@gooddata/sdk-ui-geo/styles/css/main.css";
import "@gooddata/sdk-ui-pivot/styles/css/main.css";
import "@gooddata/sdk-ui-kit/styles/css/main.css";
import "@gooddata/sdk-ui-ext/styles/css/main.css";
function App() {
    // State to hold the dynamic filter values entered by the user
    // You can set default values here, or leave them empty ('')
    const [organizationValue, setOrganizationValue] = useState('ifc'); // Example default: starts with 'ifc'
    const [subOrganizationValue, setSubOrganizationValue] = useState(''); // Example default: empty
    // Handlers to update state when input fields change
    const handleOrgChange = (e) => {
        setOrganizationValue(e.target.value);
    };
    const handleSubOrgChange = (e) => {
        setSubOrganizationValue(e.target.value);
    };
    return (
        <div className="App" style={{ fontFamily: 'Arial, sans-serif', padding: '20px', maxWidth: '1200px', margin: '0 auto' }}>
            <h1 style={{ textAlign: 'center', color: '#2c3e50', marginBottom: '30px' }}>
                GoodData Dashboard with Dynamic React Filters
            </h1>
            {/* The GoodData Dashboard Embed Component */}
            <GoodDataDashboardEmbed
                selectedOrganization='ifc'
                selectedSubOrganization='ifc_boston-metal'
            />
        </div>
    );
}
export default App;{
  "name": "gooddata-dashboard-webpack",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    "@gooddata/sdk-backend-tiger": "~10.4.0",
    "@gooddata/sdk-model": "~10.4.0",
    "@gooddata/sdk-ui": "~10.4.0",
    "@gooddata/sdk-ui-dashboard": "~10.4.0",
    "@reduxjs/toolkit": "^2.8.2",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "typescript": "^4.9.5"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "@types/react-dom": "^19.1.6"
  }
}