# Workspace Config

> Create or edit workspace configuration for CC apps (workspace.tsx, frameworkConfig.ts). USE FOR: wiring Fusion workspace modules (grid, garden, Power BI, sidesheet, filter, status bar), configuring httpClient, enabling context/bookmarks/AG Grid, useContextId, useCCApiAccessCheck, useHttpClient, useFilterConfig, WorkspaceWrapper component. DO NOT USE FOR: column definitions (use table-config skill), sidesheet UI (use sidesheet skill).

- Skill: `equinor/workspace-config` (Agent Skill)
- Install (CLI): `npx skillmds@latest add equinor/workspace-config`
- Raw SKILL.md: https://api.skillmd.com/api/skills/equinor/workspace-config/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: equinor (https://skillmd.com/u/equinor)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/equinor/workspace-config

---


# Workspace Configuration

Every CC app follows the same workspace wiring pattern. This skill covers `workspace.tsx` and `frameworkConfig.ts`.

## Workspace Component Pattern (`workspace.tsx`)

Every `WorkspaceWrapper` follows this structure:

```tsx
import {
  useCCApiAccessCheck,
  useContextId,
  useHttpClient,
  usePBIOptions,
  useWorkspaceBookmarks,
  useCloseSidesheetOnContextChange,
  isAffiliateUser,
} from '@cc-components/shared';
import { useFilterConfig } from '@cc-components/shared/workspace-config';
import Workspace from '@equinor/workspace-fusion';
import { CCApiAccessLoading } from '@cc-components/sharedcomponents';
import { useModuleCurrentContext } from '@equinor/fusion-framework-react-module-context';

// Module imports
import { gridModule } from '@equinor/workspace-fusion/grid-module';
import { gardenModule } from '@equinor/workspace-fusion/garden-module';
import { powerBiModule } from '@equinor/workspace-fusion/power-bi-module';

// Local config imports
import { sidesheetConfig } from './sidesheetConfig';
import { useTableConfig } from './tableConfig';
import { useStatusBarConfig } from './statusBarConfig';
import { useGardenConfig } from './gardenConfig';

const appName = '<api-name>'; // e.g. 'work-orders', 'swcr'

const pbi_context_mapping = {
  Facility: { column: 'Facility', table: 'Dim_Facility' },
  ProjectMaster: { column: 'ProjectMaster GUID', table: 'Dim_ProjectMaster' },
} as const;

export const WorkspaceWrapper = () => {
  const contextId = useContextId();
  useCloseSidesheetOnContextChange();
  const client = useHttpClient();
  const { bookmarkKey, currentBookmark, onBookmarkChange } = useWorkspaceBookmarks();
  const { isLoading } = useCCApiAccessCheck(contextId, client, appName);
  const { currentContext } = useModuleCurrentContext();

  const pbi = usePBIOptions(
    '<app>-analytics',
    pbi_context_mapping[currentContext?.type.id as 'ProjectMaster' | 'Facility']
  );

  const filterConfig = useFilterConfig((req) =>
    client.fetch(`/api/contexts/${contextId}/${appName}/filter-model`, req)
  );
  const tableConfig = useTableConfig(contextId);
  const statusBarConfig = useStatusBarConfig(contextId);
  const gardenConfig = useGardenConfig(contextId);

  if (isLoading) return <CCApiAccessLoading />;

  return (
    <Workspace
      appName={appName}
      key={contextId + bookmarkKey}
      currentBookmark={currentBookmark}
      onBookmarkChange={onBookmarkChange}
      workspaceOptions={{
        getIdentifier: (item: any) => item.<entityId>,
        defaultTab: 'grid',
        information: {
          title: '<AppName> Workspace',
          dataSource: 'ProCoSys / Alpha',
          dataRefreshRate: 'Hourly',
          access: 'Internal',
          isAffiliate: isAffiliateUser(),
        },
      }}
      powerBiOptions={pbi}
      filterOptions={filterConfig}
      gardenOptions={gardenConfig}
      gridOptions={tableConfig}
      statusBarOptions={statusBarConfig}
      sidesheetOptions={sidesheetConfig}
      modules={[gridModule, gardenModule, powerBiModule]}
    />
  );
};
```

### Key conventions

- `appName` must match the CC API route segment (e.g. `'work-orders'`, not `'workorder'`)
- All config hooks receive `contextId` as parameter
- `useFilterConfig` takes a fetch callback, not a URL
- Modules are passed as array: `[gridModule, gardenModule, powerBiModule]`
- Always include `isAffiliate: isAffiliateUser()` in workspace information

## Framework Config Pattern (`frameworkConfig.ts`)

```tsx
import { enableAgGrid } from '@equinor/fusion-framework-module-ag-grid';
import { ComponentRenderArgs, IAppConfigurator } from '@equinor/fusion-framework-react-app';
import { enableContext } from '@equinor/fusion-framework-react-module-context';
import { enableBookmark } from '@equinor/fusion-framework-react-app/bookmark';
import { enableNavigation } from '@equinor/fusion-framework-module-navigation';
import { enableModelViewer, ModelViewerEnvConfig } from '@cc-components/modelviewer';
import { defaultModules } from '@cc-components/shared';
import { themeQuartz } from '@equinor/workspace-fusion/grid';
import buildQuery from 'odata-query';

export const configure = async (config: IAppConfigurator, c: ComponentRenderArgs) => {
  enableNavigation(config, c.env.basename);
  enableBookmark(config);
  enableContext(config, async (builder) => {
    builder.setContextType(['ProjectMaster', 'Facility']);
    builder.setContextParameterFn(({ search, type }) =>
      buildQuery({ search, filter: { type: { in: type } } })
    );
  });

  const envConfig = c.env.config?.environment as AppEnvConfig & ModelViewerEnvConfig;
  if (!envConfig) throw new Error('Failed to load environment config');

  config.configureHttpClient('cc-app', {
    baseUri: envConfig.uri,
    defaultScopes: envConfig.defaultScopes,
  });

  enableAgGrid(config, (b) => {
    b.setModules(defaultModules);
    b.setTheme(themeQuartz.withParams({}));
  });

  enableModelViewer(config, envConfig);
};
```

### Key conventions

- HTTP client key is always `'cc-app'`
- Context types are `['ProjectMaster', 'Facility']`
- AG Grid uses `defaultModules` from `@cc-components/shared` and `themeQuartz`
- Model viewer is enabled from `@cc-components/modelviewer`

## Config Index (`index.ts`)

```ts
export { useTableConfig } from './tableConfig';
export { WorkspaceWrapper } from './workspace';
export { configure } from './frameworkConfig';
```

## Checklist

- [ ] `appName` matches CC API route segment
- [ ] `getIdentifier` returns correct entity ID field
- [ ] All 5 config hooks wired: filter, table, garden, status bar, sidesheet
- [ ] Power BI report name matches backend configuration
- [ ] Framework config enables: navigation, bookmark, context, AG Grid, model viewer
- [ ] HTTP client configured as `'cc-app'`

