mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-01-22 18:30:09 +00:00
docs: add comprehensive guide for creating new issue tracker integrations
This commit is contained in:
parent
1ce40a334f
commit
f711176731
1 changed files with 303 additions and 0 deletions
303
docs/add-new-integration.md
Normal file
303
docs/add-new-integration.md
Normal 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!
|
||||
Loading…
Add table
Add a link
Reference in a new issue