Building Dashboard Components#

Warning

Project Neo is currently in Technical Preview. Features described in this section may change before general availability.

Every dashboard in your bundle is a standard React component. This page covers the component contract, available libraries, navigation, and TypeScript usage.

Component Signature#

Every dashboard component must accept a projectId prop. The host injects it automatically when rendering your dashboard.

interface Props {
  projectId: string;
}

export default function Analytics({ projectId }: Props) {
  return (
    <div className="p-6">
      <h1 className="text-xl font-semibold">Analytics</h1>
      <p className="text-sm text-muted-foreground">
        Showing data for project: {projectId}
      </p>
    </div>
  );
}

projectId is the identifier of the active Squirro project. Use it to scope API calls, display project-specific data, and construct URLs.

Project and User Context#

projectId is the only prop injected by the host. Project metadata such as the title, the workspace, or your role in the project is not passed directly. Fetch it from the Squirro API using the shared @tanstack/react-query library. The identity of the signed-in user is available from a hook, described further below.

Fetching Project Metadata#

A single API call to GET /v0/projects/{projectId} returns the most commonly needed project fields:

Field

Description

title

Human-readable project name.

description

Project description, if set.

workspace

Workspace domain (used to construct API URLs).

workspace_title

Human-readable workspace name.

project_role

Role of the current user in this project (for example, admin, editor, viewer).

permissions

List of permission strings granted to the current user for this project.

Example using useQuery:

import { useQuery } from '@tanstack/react-query';

interface Project {
  id: string;
  title: string;
  description?: string;
  workspace?: string;
  workspace_title?: string;
  project_role?: string;
  permissions?: string[];
}

function Analytics({ projectId }: { projectId: string }) {
  const { data: project, isPending, isError } = useQuery<Project>({
    queryKey: ['project', projectId],
    queryFn: async () => {
      const response = await fetch(`/v0/projects/${projectId}`);
      if (!response.ok) throw new Error('Failed to fetch project');
      return response.json();
    },
  });

  if (isPending) return <p>Loading...</p>;
  if (isError) return <p>Failed to load project.</p>;

  return (
    <div>
      <h1>{project.title}</h1>
      <p>Workspace: {project.workspace_title}</p>
      <p>Your role: {project.project_role}</p>
    </div>
  );
}

Reading the Current User#

Call the useCurrentUser() hook from @squirro/nextgen-core/api to read the signed-in user. The hook returns null until authentication resolves, and it re-renders the component when the user changes:

import { useCurrentUser } from '@squirro/nextgen-core/api';

export default function Analytics() {
  const user = useCurrentUser();

  if (!user) return <p>Loading...</p>;

  return (
    <p>
      Signed in as {user.full_name ?? user.email} ({user.role})
    </p>
  );
}

The hook returns the following fields:

Field

Description

id

Identifier of the user.

tenant

Tenant the user belongs to.

email

Email address of the user.

role

Role of the user, for example admin.

role_permissions

List of permission strings granted by that role.

full_name

Display name. Optional, because the backend omits it when it is not set.

groups

Groups the user belongs to, each with an id and a name.

The groups field is undefined when the membership is unknown, which is not the same as an empty array. An empty array means the user is known to belong to no group. Treat the unknown case as undecided rather than as an absence of membership.

Those fields are a deliberately narrow view of the user profile. For anything outside them, call the endpoint directly with the fetch escape hatch of useSquirroApi(), described on the Squirro API page. For the available user fields, see the Microservices APIs page.

Note

The hook needs a host that reports the user identity. On an older host, it raises an error naming the missing support instead of returning a user.

Restricting a Dashboard to Specific Groups#

A user group is defined once for the whole Squirro instance, not per project. An administrator creates groups in the Server space under Groups, then gives a group a role in a project under Setup → Settings → Project Members. Where single sign-on is used, membership can be mapped from the groups of the identity provider. For more information about groups, roles, and permissions, see the Squirro Roles & Permissions page.

Project roles are a separate concept. allowedGroups matches the name or the ID of a group, so a role such as Administrator, Member, or Reader in that list matches nothing and leaves the dashboard hidden from everyone.

Add the allowedGroups field to the manifest entry of a dashboard to show it only to members of specific user groups:

{
  id: 'exec-summary',
  title: 'Executive Summary',
  icon: 'chart-line',
  route: 'exec-summary',
  component: () => import('./dashboards/ExecSummary'),
  allowedGroups: ['Executives'],
}
  • Each entry matches either the name or the ID of a group. To list the groups of your instance with both values, run neo-ui groups.

  • The dashboard is shown to viewers who belong to at least one of the listed groups.

  • Omit the field, or leave the array empty, to show the dashboard to everyone.

  • If the group membership of the viewer cannot be determined, because the identity has not resolved yet or the host does not report it, the dashboard stays hidden.

neo-ui create dashboard offers a group picker when it creates the dashboard, and --groups sets the same field without prompting. Both are described on the CLI Reference page. The restriction can be changed at any time by editing the manifest entry.

To remove an item from the sidebar for every viewer, including a core item of the host application, use the nav field of the manifest instead. The two fields compose, so an item appears only when it passes both. For more information, see the The Bundle Manifest page.

A restricted dashboard is left out of the sidebar, and it cannot be opened by URL either. A viewer who tries is redirected to the first dashboard available to them, or to the project home page when no dashboard is available.

Warning

allowedGroups tailors the interface to the viewer. It is not a security boundary. The field removes an entry point from the sidebar and blocks a route in the browser, but it does not restrict the underlying data. Data access is enforced by the Squirro platform, so a dashboard that presents sensitive content still requires the matching project and item permissions.

Available Shared Libraries#

The following libraries are provided by the host application at runtime. You do not need to install them in your project.

Installed by the Scaffold (Do Not Bump These)#

These packages are included in the scaffolded package.json so that TypeScript can resolve their types during development. Do not change their versions independently. They must match the versions bundled into @squirro/nextgen-core.

Package

Description

react

JSX, hooks, and components.

react-dom

DOM rendering.

react-router-dom

useNavigate, Link, useParams, and other routing hooks.

Provided Only at Runtime (Do Not Add at All)#

These packages are not in the scaffolded package.json. The host supplies them exclusively at runtime via Module Federation. Do not add them to your package.json. Adding them causes duplicate versions and runtime errors.

Package

Description

zustand

Lightweight global state.

@tanstack/react-query

Data fetching, caching, and loading and error states.

i18next and react-i18next

Translations. For more information, see the Translations page.

Those libraries run as singletons shared with the host. Your dashboards share the same router context, query cache, and i18n instance as the host application, giving them full access to standard navigation and any cached data.

TypeScript#

TypeScript is fully configured in the generated project. TypeScript type-checks dashboard components against the shared library types automatically.

To check types manually:

npx tsc --noEmit

Avoid as for type casting. Use type guards or proper type narrowing instead:

// Avoid
const item = data as SearchResult;

// Prefer
function isSearchResult(value: unknown): value is SearchResult {
  return typeof value === 'object' && value !== null && 'id' in value;
}

Browser Support#

Project Neo targets the same browsers as the classic Squirro interface: the latest versions of Chrome, Edge, Firefox, and Safari. When choosing JavaScript or Web APIs for your dashboard components, you can rely on anything supported across those four browsers at their current release.

For the full client requirements, see the System Requirements page.

Runtime Environment#

Bundles run directly inside the host application’s JavaScript context via Module Federation. There is no iframe or Worker-based sandbox between bundle code and the host: dashboards share the host’s React instance, router, query cache, and origin. Plan for the implications below before writing code that crosses a trust boundary.

Browser Storage#

Bundles share the same origin as the host and have full read and write access to localStorage and sessionStorage. Use a namespaced key prefix to avoid collisions with host data or other bundles:

localStorage.setItem('my-bundle:user-preference', value);
const pref = localStorage.getItem('my-bundle:user-preference');

Warning

Because all bundles share the same origin, any code running on the page can read any key in localStorage and sessionStorage. Do not store tokens, credentials, or other sensitive data there.

External APIs#

The Squirro instance is the only origin a dashboard can reach without additional setup. To call a third-party service, route the request through a server-side proxy you control rather than calling the external API directly from the browser. There is no built-in pass-through proxy for bundle use.

Browser Permissions#

The host denies access to geolocation, microphone, and camera via the Permissions-Policy header. Bundles cannot request those browser APIs regardless of user consent.