API Reference

Table of Contents

Plugin API

GitHubProjectsPlugin

Main plugin class extending Obsidian's Plugin.

#### Properties

class GitHubProjectsPlugin extends Plugin {
  settings: PluginSettings;
  projectState: ProjectState;
}

#### Methods

##### onload(): Promise

Called when the plugin is loaded.

Returns: Promise

Example:

async onload() {
  await this.loadSettings();
  this.registerView(VIEW_TYPE_PROJECT_BOARD, (leaf) => new ProjectBoardView(leaf, this));
  this.addRibbonIcon('layout-dashboard', 'Open GitHub Project', () => this.activateView());
}

##### onunload(): void

Called when the plugin is unloaded.

Returns: void

##### loadSettings(): Promise

Load plugin settings from storage.

Returns: Promise

##### saveSettings(): Promise

Save plugin settings to storage.

Returns: Promise

##### activateView(): Promise

Open or focus the project board view.

Returns: Promise

Example:

await this.plugin.activateView();

State Management

ProjectState

Centralized state management using event-driven pattern.

#### Constructor

constructor(plugin: GitHubProjectsPlugin)

Parameters:

#### Properties

class ProjectState {
  private project: Project | null;
  private loading: boolean;
  private error: string | null;
  private events: Events;
}

#### Methods

##### loadProject(): Promise

Fetch project data from GitHub.

Returns: Promise

Emits: project-loading, project-loaded, project-error

Example:

await projectState.loadProject();

##### refresh(): Promise

Refresh project data from GitHub.

Returns: Promise

Emits: project-refreshing, project-loaded, project-error

##### moveItem(itemId: string, statusId: string): Promise

Move an item to a different status (optimistic update).

Parameters:

Returns: Promise

Emits: item-moved, item-move-error

Example:

await projectState.moveItem('ITEM_123', 'STATUS_456');

##### getProject(): Project | null

Get the current project data.

Returns: Project | null

##### getColumns(): Column[]

Get project columns based on status field.

Returns: Column[]

##### getItemsByColumn(columnId: string): ProjectItem[]

Get all items in a specific column.

Parameters:

Returns: ProjectItem[]

##### on(event: string, callback: Function): void

Subscribe to state events.

Parameters:

Example:

projectState.on('project-loaded', (project) => {
  console.log('Project loaded:', project.title);
});

##### off(event: string, callback: Function): void

Unsubscribe from state events.

Parameters:

GitHub API Client

GitHubAPIClient

GraphQL client for GitHub Projects V2 API.

#### Constructor

constructor(token: string)

Parameters:

#### Methods

##### fetchProject(organization: string, projectNumber: number): Promise

Fetch project data from GitHub.

Parameters:

Returns: Promise

Throws:

Example:

const client = new GitHubAPIClient(token);
const project = await client.fetchProject('my-org', 5);

##### updateItemStatus(projectId: string, itemId: string, fieldId: string, statusId: string): Promise

Update an item's status field.

Parameters:

Returns: Promise

Throws: Error if update fails

Example:

await client.updateItemStatus(
  'PROJECT_ID',
  'ITEM_ID',
  'FIELD_ID',
  'STATUS_ID'
);

##### testConnection(organization: string, projectNumber: number): Promise

Test if the API connection works.

Parameters:

Returns: Promise - true if connection successful

Example:

const isValid = await client.testConnection('my-org', 5);

Type Definitions

PluginSettings

interface PluginSettings {
  githubToken: string;        // GitHub PAT (stored in localStorage)
  organization: string;       // GitHub organization name
  projectNumber: number;      // Project number from URL
  autoRefreshInterval: number; // Auto-refresh interval in minutes
}

Project

interface Project {
  id: string;              // Project V2 ID
  title: string;           // Project title
  description?: string;    // Project description
  fields: ProjectField[];  // All project fields
  items: ProjectItem[];    // All project items
  statusField?: StatusField; // The "Status" field used for columns
}

ProjectField

interface ProjectField {
  id: string;          // Field ID
  name: string;        // Field name
  type: FieldType;     // Field type
  options?: FieldOption[]; // Options for select fields
}

type FieldType = | 'TEXT' | 'NUMBER' | 'DATE' | 'SINGLE_SELECT' | 'ITERATION';

StatusField

interface StatusField extends ProjectField {
  type: 'SINGLE_SELECT';
  options: StatusOption[];
}

interface StatusOption { id: string; // Option ID name: string; // Display name color?: string; // Optional color }

ProjectItem

interface ProjectItem {
  id: string;              // Item ID
  type: ItemType;          // Item type
  content: ItemContent;    // Issue or PR content
  fieldValues: FieldValue[]; // All field values
  statusId?: string;       // Current status option ID
}

type ItemType = 'ISSUE' | 'PULL_REQUEST' | 'DRAFT_ISSUE';

ItemContent

interface ItemContent {
  number?: number;         // Issue/PR number
  title: string;           // Title
  body?: string;           // Description
  state: ItemState;        // Open/Closed/Merged
  url: string;             // GitHub URL
  assignees: Assignee[];   // Assigned users
  labels: Label[];         // Labels
  createdAt: string;       // Creation timestamp
  updatedAt: string;       // Last update timestamp
}

type ItemState = 'OPEN' | 'CLOSED' | 'MERGED';

Assignee

interface Assignee {
  id: string;       // User ID
  login: string;    // GitHub username
  name?: string;    // Display name
  avatarUrl: string; // Avatar image URL
}

Label

interface Label {
  id: string;       // Label ID
  name: string;     // Label name
  color: string;    // Hex color code
  description?: string; // Label description
}

Column

interface Column {
  id: string;            // Status option ID
  name: string;          // Column name
  items: ProjectItem[];  // Items in this column
}

Events

State Events

The ProjectState class emits the following events:

#### project-loading

Emitted when project data fetch starts.

Payload: None

Example:

projectState.on('project-loading', () => {
  console.log('Loading project...');
});

#### project-loaded

Emitted when project data is successfully loaded.

Payload: Project

Example:

projectState.on('project-loaded', (project: Project) => {
  console.log('Project loaded:', project.title);
});

#### project-error

Emitted when project fetch fails.

Payload: Error

Example:

projectState.on('project-error', (error: Error) => {
  console.error('Failed to load project:', error.message);
});

#### project-refreshing

Emitted when project refresh starts.

Payload: None

#### item-moved

Emitted when an item is moved (optimistically).

Payload: { itemId: string, statusId: string }

Example:

projectState.on('item-moved', ({ itemId, statusId }) => {
  console.log(Item ${itemId} moved to ${statusId});
});

#### item-move-error

Emitted when item move fails.

Payload: { itemId: string, error: Error }

Utility Functions

Storage Utilities

Located in src/utils/storage.ts:

#### getToken(): string | null

Get GitHub token from localStorage.

Returns: string | null

Example:

const token = getToken();

#### setToken(token: string): void

Save GitHub token to localStorage.

Parameters:

Example:

setToken('ghp_...');

#### clearToken(): void

Remove GitHub token from localStorage.

Example:

clearToken();

GitHub Utilities

Located in src/utils/github.ts:

#### parseProjectUrl(url: string): { org: string, number: number } | null

Parse organization and project number from GitHub URL.

Parameters:

Returns: { org: string, number: number } | null

Example:

const parsed = parseProjectUrl('https://github.com/orgs/my-org/projects/5');
// Returns: { org: 'my-org', number: 5 }

#### formatItemNumber(item: ProjectItem): string

Format item number for display (e.g., "#123").

Parameters:

Returns: string

Example:

const formatted = formatItemNumber(item);
// Returns: "#123"

#### getItemStateColor(state: ItemState): string

Get CSS color for item state.

Parameters:

Returns: string (CSS color value)

Example:

const color = getItemStateColor('OPEN');
// Returns: 'var(--color-green)'

Date Utilities

#### formatRelativeTime(timestamp: string): string

Format timestamp as relative time (e.g., "2 hours ago").

Parameters:

Returns: string

Example:

const relative = formatRelativeTime('2024-01-15T10:00:00Z');
// Returns: "2 hours ago"

Extension Points

Custom Views

Register custom views that integrate with the plugin:

this.registerView(
  'custom-view-type',
  (leaf) => new CustomView(leaf, this.plugin.projectState)
);

Custom Commands

Add commands that interact with project state:

this.addCommand({
  id: 'custom-command',
  name: 'Custom Command',
  callback: async () => {
    const project = this.plugin.projectState.getProject();
    // Do something with project data
  }
});

Event Subscriptions

Subscribe to plugin events in other plugins or scripts:

// Access plugin instance
const plugin = app.plugins.plugins['github-projects'];

// Subscribe to events plugin.projectState.on('project-loaded', (project) => { // React to project updates });

Error Handling

Error Types

#### AuthenticationError

Thrown when GitHub authentication fails.

catch (error) {
  if (error.message.includes('authentication')) {
    // Handle authentication error
  }
}

#### NotFoundError

Thrown when project is not found.

catch (error) {
  if (error.message.includes('not found')) {
    // Handle not found error
  }
}

#### NetworkError

Thrown when network request fails.

catch (error) {
  if (error.message.includes('network')) {
    // Handle network error
  }
}

#### RateLimitError

Thrown when GitHub API rate limit is exceeded.

catch (error) {
  if (error.message.includes('rate limit')) {
    // Handle rate limit error
  }
}

Best Practices

Performance

   const debouncedRefresh = debounce(() => state.refresh(), 1000);
   
   const columns = useMemo(() => groupByStatus(items), [items]);
   

Security

   // Bad
   console.log('Token:', token);

// Good console.log('Token:', token ? '[REDACTED]' : 'None');

Error Handling

   try {
     await state.loadProject();
   } catch (error) {
     new Notice('Failed to load project: ' + error.message);
   }
   

TypeScript Support

All APIs are fully typed. Import types:

import type {
  Project,
  ProjectItem,
  PluginSettings,
  Column
} from 'obsidian-github-projects';

Enable strict TypeScript for best experience:

{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true
  }
}