docs: add comprehensive guide for creating new issue tracker integrations

This commit is contained in:
Mike P. Sinn 2025-03-02 00:03:09 -06:00 committed by Johannes Millan
parent 1ce40a334f
commit f711176731

303
docs/add-new-integration.md Normal file
View file

@ -0,0 +1,303 @@
# Adding a New Integration to Super Productivity
This guide explains how to add a new issue tracker integration to Super Productivity.
## Overview
Super Productivity supports multiple issue tracker integrations (called "Issue Providers" in the codebase), including GitHub, GitLab, Jira, and others. Adding a new integration requires implementing specific interfaces and services to communicate with the external service.
## Integration Architecture
Each integration follows a consistent pattern:
1. **Interface**: All integrations implement the `IssueServiceInterface`, which defines the required methods for communicating with external services.
2. **Provider-specific Models**: Each integration defines its own data structures.
3. **API Services**: Each integration has an API service that handles HTTP requests.
4. **Common Interfaces Service**: Each integration has a service that implements `IssueServiceInterface`.
5. **Configuration**: Each integration defines its configuration options.
## Step-by-Step Guide
### 1. Create the Provider Directory Structure
Create a new directory under `src/app/features/issue/providers/` for your integration, for example `my-provider/`.
### 2. Create Required Files
Based on existing integrations, you'll need to create:
#### Model Files
- `my-provider.model.ts` - Define your provider's configuration and data structures
- `my-provider-issue.model.ts` - Define issue-specific data structures
Example from GitHub:
```typescript
// github.model.ts
import { BaseIssueProviderCfg } from '../../issue.model';
export interface GithubCfg extends BaseIssueProviderCfg {
repo: string;
token?: string;
}
```
#### Service Files
- `my-provider-api.service.ts` - Handle API communication
- `my-provider-common-interfaces.service.ts` - Implement the `IssueServiceInterface`
Example API service structure:
```typescript
@Injectable({
providedIn: 'root',
})
export class MyProviderApiService {
// HTTP communication methods
getById$(issueId: string, cfg: MyProviderCfg): Observable<MyProviderIssue> {
// Implementation
}
searchIssues$(searchTerm: string, cfg: MyProviderCfg): Observable<MyProviderIssue[]> {
// Implementation
}
}
```
Example Common Interfaces Service structure:
```typescript
@Injectable({
providedIn: 'root',
})
export class MyProviderCommonInterfacesService implements IssueServiceInterface {
// Implement all required methods from IssueServiceInterface
isEnabled(cfg: MyProviderCfg): boolean {
// Implementation
}
// Other required methods...
}
```
#### Constants File
- `my-provider.const.ts` - Define constants and default configurations
Example:
```typescript
import { ConfigFormSection } from '../../../config/global-config.model';
export const MY_PROVIDER_INITIAL_POLL_DELAY = 5000;
export const MY_PROVIDER_POLL_INTERVAL = 5 * 60 * 1000;
export const DEFAULT_MY_PROVIDER_CFG: MyProviderCfg = {
isEnabled: false,
// Other default values
};
export const MY_PROVIDER_CONFIG_FORM_SECTION: ConfigFormSection = {
// Form configuration
};
```
#### Utility Files
- `is-my-provider-enabled.util.ts` - Helper for checking if the provider is enabled
Example:
```typescript
import { MyProviderCfg } from './my-provider.model';
export const isMyProviderEnabled = (cfg: MyProviderCfg): boolean => {
return cfg && cfg.isEnabled && // other conditions;
};
```
### 3. Implement the IssueServiceInterface
The key interface methods that must be implemented include:
```typescript
// MANDATORY
isEnabled(cfg: IssueIntegrationCfg): boolean;
testConnection$(cfg: IssueIntegrationCfg): Observable<boolean>;
pollTimer$: Observable<number>;
issueLink$(issueId: string | number, issueProviderId: string): Observable<string>;
getById$(id: string | number, issueProviderId: string): Observable<IssueData | null>;
getAddTaskData(issueData: IssueDataReduced): Partial<Task> & { title: string };
searchIssues$(searchTerm: string, issueProviderId: string): Observable<SearchResultItem[]>;
getFreshDataForIssueTask(task: Task): Promise<{ taskChanges: Partial<Task>; issue: IssueData; issueTitle: string; } | null>;
getFreshDataForIssueTasks(tasks: Task[]): Promise<{ task: Task; taskChanges: Partial<Task>; issue: IssueData; }[]>;
// OPTIONAL
getMappedAttachments?(issueData: IssueData): TaskAttachment[];
getNewIssuesToAddToBacklog?(issueProviderId: string, allExistingIssueIds: number[] | string[]): Promise<IssueDataReduced[]>;
```
### 4. Update Core Files
You'll need to update several core files to register your new integration:
#### 1. Update `issue.model.ts`
Add your provider to the `IssueProviderKey` type:
```typescript
export type IssueProviderKey =
| 'JIRA'
| 'GITHUB'
| 'GITLAB'
| 'CALDAV'
| 'ICAL'
| 'OPEN_PROJECT'
| 'GITEA'
| 'REDMINE'
| 'MY_PROVIDER'; // Add your provider here
```
Add your provider configuration to `IssueIntegrationCfg`:
```typescript
export type IssueIntegrationCfg =
| JiraCfg
| GithubCfg
| GitlabCfg
| CaldavCfg
| CalendarProviderCfg
| OpenProjectCfg
| GiteaCfg
| RedmineCfg
| MyProviderCfg; // Add your provider here
```
Update `IssueIntegrationCfgs` interface:
```typescript
export interface IssueIntegrationCfgs {
// should be the same as key IssueProviderKey
JIRA?: JiraCfg;
GITHUB?: GithubCfg;
GITLAB?: GitlabCfg;
CALDAV?: CaldavCfg;
CALENDAR?: CalendarProviderCfg;
OPEN_PROJECT?: OpenProjectCfg;
GITEA?: GiteaCfg;
REDMINE?: RedmineCfg;
MY_PROVIDER?: MyProviderCfg; // Add your provider here
}
```
Update `IssueProvider` type:
```typescript
export type IssueProvider =
| IssueProviderJira
| IssueProviderGithub
| IssueProviderGitlab
| IssueProviderCaldav
| IssueProviderCalendar
| IssueProviderOpenProject
| IssueProviderGitea
| IssueProviderRedmine
| IssueProviderMyProvider; // Add your provider here
```
#### 2. Update `issue.const.ts`
Add your provider type constant:
```typescript
export const MY_PROVIDER_TYPE: IssueProviderKey = 'MY_PROVIDER';
```
Add your provider to `ISSUE_PROVIDER_TYPES`:
```typescript
export const ISSUE_PROVIDER_TYPES: IssueProviderKey[] = [
GITLAB_TYPE,
GITHUB_TYPE,
JIRA_TYPE,
CALDAV_TYPE,
ICAL_TYPE,
OPEN_PROJECT_TYPE,
GITEA_TYPE,
REDMINE_TYPE,
MY_PROVIDER_TYPE, // Add your provider here
];
```
Update `DEFAULT_ISSUE_PROVIDER_CFGS`:
```typescript
export const DEFAULT_ISSUE_PROVIDER_CFGS: IssueIntegrationCfgs = {
JIRA: DEFAULT_JIRA_CFG,
GITHUB: DEFAULT_GITHUB_CFG,
GITLAB: DEFAULT_GITLAB_CFG,
CALDAV: DEFAULT_CALDAV_CFG,
CALENDAR: DEFAULT_CALENDAR_CFG,
OPEN_PROJECT: DEFAULT_OPEN_PROJECT_CFG,
GITEA: DEFAULT_GITEA_CFG,
REDMINE: DEFAULT_REDMINE_CFG,
MY_PROVIDER: DEFAULT_MY_PROVIDER_CFG, // Add your provider here
};
```
Update `ISSUE_PROVIDER_FORM_CFGS_MAP`:
```typescript
export const ISSUE_PROVIDER_FORM_CFGS_MAP: Record<IssueProviderKey, ConfigFormSection> = {
JIRA: JIRA_CONFIG_FORM_SECTION,
GITHUB: GITHUB_CONFIG_FORM_SECTION,
GITLAB: GITLAB_CONFIG_FORM_SECTION,
CALDAV: CALDAV_CONFIG_FORM_SECTION,
CALENDAR: CALENDAR_FORM_CFG_NEW,
OPEN_PROJECT: OPEN_PROJECT_CONFIG_FORM_SECTION,
GITEA: GITEA_CONFIG_FORM_SECTION,
REDMINE: REDMINE_CONFIG_FORM_SECTION,
MY_PROVIDER: MY_PROVIDER_CONFIG_FORM_SECTION, // Add your provider here
};
```
### 5. Create UI Components (Optional)
Depending on your integration, you may need to create UI components:
- Issue display and content components in `my-provider/my-provider-issue-content/` directory
- Header components in `my-provider/my-provider-issue-header/` directory
- Configuration components if needed
### 6. Register the Provider in the Issue Service
The `IssueService` uses a provider factory pattern. Ensure your provider service is properly injected and registered.
## Testing Your Integration
1. Run the app with `npm run startFrontend`
2. Navigate to the settings page
3. Add a new integration of your provider type
4. Test the connection and functionality
## Tips and Best Practices
1. **Study Existing Integrations**: Use GitHub or GitLab integrations as reference implementations
2. **Error Handling**: Implement robust error handling for API failures
3. **Polling**: Consider rate limits when implementing polling
4. **Authentication**: Securely handle authentication tokens
5. **User Experience**: Make configuration and usage as simple as possible
## Troubleshooting
- Check browser console for errors
- Verify correct implementation of the `IssueServiceInterface`
- Ensure all model types are correctly defined
- Verify correct registration in all required files
## Contributing Back
Once your integration is working, please consider submitting it back to the Super Productivity project as a pull request!