-
Notifications
You must be signed in to change notification settings - Fork 12
chore: added copilot instructions #169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
mwkyuen
wants to merge
1
commit into
BioAnalyticResource:staging
Choose a base branch
from
mwkyuen:mike/copilot_01
base: staging
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| # ePlant AI Agent Instructions | ||
|
|
||
| ePlant is a gene-centric visualization tool for plant genomes built with React, TypeScript, and Vite. | ||
|
|
||
| ## Core Architecture | ||
|
|
||
| ### View System | ||
| - **Views** are the central abstraction - data visualization components that implement the `View<Data, State, Action>` interface | ||
| - Each View defines: `component`, `getInitialData`, `getInitialState`, `reducer`, `actions`, `icon`, and `citation` | ||
| - Views are configured in `Eplant/config.ts` as `genericViews` (non-gene-specific) and `userViews` (gene-specific) | ||
| - View components receive props: `{ activeData, state, dispatch, geneticElement }` | ||
|
|
||
| #### View Interface Pattern | ||
| Views implement `View<Data, State, Action>` with these required/optional properties: | ||
|
|
||
| **Required:** | ||
| - `component`: React component receiving `ViewProps<Data, State, Action>` | ||
| - `getInitialData`: Async function that loads view data for a gene | ||
| - `name`: Display name for the view | ||
| - `id`: Unique identifier used in routing and storage | ||
|
|
||
| **Optional:** | ||
| - `getInitialState()`: Returns initial state (defaults to `null`) | ||
| - `reducer(state, action)`: Handles state updates via actions | ||
| - `actions[]`: Menu items with `{action, render()}` for view options | ||
| - `icon()`: JSX icon component for view selector | ||
| - `citation()`: JSX component for data attribution | ||
|
|
||
| **Two Implementation Patterns:** | ||
| 1. **Object views** (simple): `const MyView: View = { name, id, component, ... }` | ||
| 2. **Class views** (complex): `class MyView implements View { constructor(...) { this.component = this.component.bind(this) } }` | ||
|
|
||
| **Routing & View Registration:** | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Yukthiw can you review this section? |
||
| 1. **Add to config**: Register view in `Eplant/config.ts` in `userViews` or `genericViews` array | ||
| 2. **View ID routing**: The `id` property automatically becomes the URL route (e.g., `id: 'my-view'` → `/my-view`) | ||
| 3. **Default view**: Set `defaultView: 'view-id'` in config to control initial view | ||
| 4. **View switching**: Use `useSetActiveViewId()` to programmatically change views | ||
|
|
||
| Example view registration: | ||
| ```typescript | ||
| // In Eplant/config.ts | ||
| import MyNewView from './views/MyNewView' | ||
|
|
||
| const userViews = [ | ||
| GeneInfoView, | ||
| MyNewView, // Add your view here | ||
| // ... other views | ||
| ] | ||
| ``` | ||
|
|
||
| Example minimal view: | ||
| ```typescript | ||
| const SimpleView: View<string> = { | ||
| name: 'Simple View', | ||
| id: 'simple', // This becomes the route | ||
| component: ({ activeData }) => <div>{activeData}</div>, | ||
| async getInitialData(gene) { | ||
| return gene ? `Data for ${gene.id}` : 'No gene' | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### State Management | ||
| - Uses **Jotai** atoms for global state, not Redux/Context extensively | ||
| - Custom `atomWithStorage` pattern persists state to IndexedDB via `Storage` utility class | ||
| - Key atoms: `genesAtom`, `activeViewIdAtom`, `activeGeneIdAtom`, `darkModeAtom` | ||
| - State persistence can be disabled with `persistAtom` | ||
|
|
||
| ### Data Loading Pattern | ||
| - Views load data via `getInitialData(gene, loadEvent)` with progress callbacks | ||
| - `useViewData` hook manages loading states and caches data in `viewDataStorage` | ||
| - Species-specific loaders in `Species/arabidopsis/loaders/` handle API calls to BAR (Bio-Analytic Resource) | ||
|
|
||
| ## File Organization Conventions | ||
|
|
||
| ### View Structure | ||
| ``` | ||
| views/ | ||
| ViewName/ | ||
| index.tsx # View configuration object | ||
| component.tsx # React component implementation | ||
| types.tsx # TypeScript interfaces | ||
| icon.tsx # Icon component | ||
| ``` | ||
|
|
||
| ### Import Aliases | ||
| - Use `@eplant/*` imports via TypeScript path mapping | ||
| - Example: `import { View } from '@eplant/View'` | ||
|
|
||
| ### Component Patterns | ||
| - Views can be classes (`EFP`) or objects (`GeneInfoView`) | ||
| - Use `ViewProps<Data, State, Action>` for component props | ||
| - Actions rendered via `view.actions[].render()` for view options menu | ||
|
|
||
| #### Data Loading & Error Handling | ||
| Views must handle three scenarios in `getInitialData`: | ||
| 1. **Success**: Return the loaded data | ||
| 2. **Unsupported gene**: `throw ViewDataError.UNSUPPORTED_GENE` | ||
| 3. **Loading failure**: `throw ViewDataError.FAILED_TO_LOAD` | ||
|
|
||
| The `loadEvent` callback reports progress (0-1 float): | ||
| ```typescript | ||
| async getInitialData(gene, loadEvent) { | ||
| loadEvent(0.0) // Starting | ||
| const data = await api.fetchData(gene.id) | ||
| loadEvent(0.5) // Halfway | ||
| const processed = await processData(data) | ||
| loadEvent(1.0) // Complete | ||
| return processed | ||
| } | ||
| ``` | ||
|
|
||
| Species-specific loaders live in `Species/arabidopsis/loaders/` and are referenced by view ID: | ||
| ```typescript | ||
| // In Species definition | ||
| loaders: { | ||
| 'gene-info': GeneInfoViewLoader, | ||
| 'publication-viewer': PublicationViewerLoader | ||
| } | ||
| ``` | ||
|
|
||
| ## Development Workflow | ||
|
|
||
| ### Key Commands | ||
| ```bash | ||
| npm run dev # Vite dev server | ||
| npm run build # Production build for GitHub Pages | ||
| npm run lint # ESLint + Prettier check | ||
| npm run lint:fix # Auto-fix linting issues | ||
| ``` | ||
|
|
||
| ### Build Configuration | ||
| - Vite with React, TypeScript paths, and ESLint plugins | ||
| - GitHub Pages deployment via `.github/workflows/deploy.yml` | ||
| - Environment variables: `BASE_URL='/ePlant'`, `VITE_MAPS_API_KEY` | ||
|
|
||
| ## Unique Patterns | ||
|
|
||
| ### GeneticElement & Species | ||
| - `GeneticElement` represents genes with species-specific APIs | ||
| - `Species` class provides `searchGene`, `autocomplete`, and `loaders` | ||
| - Currently only supports Arabidopsis via BAR API at `bar.utoronto.ca` | ||
|
|
||
| ### ViewContainer Architecture | ||
| - `ViewContainer` wraps views with toolbar, loading states, and error handling | ||
| - Renders `<view.component />` with standardized props structure | ||
| - Handles view switching, gene selection, and print functionality | ||
|
|
||
| ### Storage & Persistence | ||
| - Custom `Storage` class wraps IndexedDB with key-value persistence | ||
| - View data cached by `${viewId}-${geneId}` keys | ||
| - Loading progress tracked globally via `pageLoad` singleton | ||
|
|
||
| ## Common Pitfalls | ||
|
|
||
| - Views must handle both loading and error states in `getInitialData` | ||
| - Use `ViewDataError.UNSUPPORTED_GENE` for genes that don't support a view | ||
| - State updates should go through `dispatch` actions, not direct state mutation | ||
| - SVG manipulation in eFP views requires careful DOM querying with view-specific IDs | ||
|
|
||
| ## Integration Points | ||
|
|
||
| - **BAR API**: External service for gene data, expression data, and annotations | ||
| - **Jotai DevTools**: Available in development for state debugging | ||
| - **Material-UI**: Consistent theming via `css/theme.tsx` with dark/light modes | ||
| - **FlexLayout**: For complex layouts (currently commented out but present) | ||
|
|
||
| When implementing new views, follow the View interface pattern and ensure proper error handling for unsupported genes. | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bdls-jamal can you review this section? Which pattern do you usually use? I don't want there to be 2 patterns, so I'll keep only the pattern that you are using
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is an example of the configuration for the heatmap(same as navigator and other views)
I don't think it matches either of the two options generated by copilot but correct me if I am not understanding correctly.
Also, an actual object must also be created in a separate file like so:
export const viewObject = () => {}and then inside it will have constants for initializing the state, theme, outlet context, useQuery, etc. Should all be outlined in the eplant/Eplant/tutorial.md of staging.