mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-01-23 02:36:05 +00:00
docs: add cool new plans
This commit is contained in:
parent
e8258940cb
commit
648ce47249
2 changed files with 490 additions and 0 deletions
295
docs/ai/issue-providers-to-plugins-evaluation.md
Normal file
295
docs/ai/issue-providers-to-plugins-evaluation.md
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
# Evaluation: Migrating Issue Providers to Plugin System
|
||||
|
||||
## Summary
|
||||
|
||||
**Goals**: Enable community providers, reduce core bundle size, hybrid UI (app controls standard UI, plugins can extend), full feature parity including Jira worklogs/transitions.
|
||||
|
||||
**Verdict**: Feasible but significant effort. The hybrid approach is the right strategy - it preserves native UX while allowing plugin flexibility.
|
||||
|
||||
---
|
||||
|
||||
## Complexity Assessment
|
||||
|
||||
| Aspect | Complexity | Notes |
|
||||
| ----------------------------- | ---------- | ------------------------------------ |
|
||||
| Plugin API extension | Medium | ~8 new methods needed |
|
||||
| State management | Low | Extend existing IssueProvider model |
|
||||
| Config UI | Medium | JSON Schema to Formly conversion |
|
||||
| Issue content display | Low | Plugin provides config, app renders |
|
||||
| Add-task bar search | Medium | Route searches to plugin providers |
|
||||
| Polling infrastructure | Low | App already handles timers/batching |
|
||||
| Custom actions (worklogs etc) | High | New UI integration points needed |
|
||||
| Bundle size reduction | Medium | Requires lazy loading infrastructure |
|
||||
| Migration (9 providers) | High | Each ~1-2 weeks to convert |
|
||||
|
||||
**Overall: Medium-High complexity**
|
||||
|
||||
---
|
||||
|
||||
## Architecture: Hybrid Plugin Issue Provider
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ APP (Angular Core) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ • IssueProviderRegistry - tracks plugin providers │
|
||||
│ • Config UI - renders JSON Schema as native forms │
|
||||
│ • Add-task bar - searches plugin providers │
|
||||
│ • Issue content display - renders from plugin config │
|
||||
│ • Polling - app-controlled timers, dispatches to plugins │
|
||||
│ • NgRx state - stores provider configs (built-in + plugin) │
|
||||
│ • Custom action menu - shows plugin-registered actions │
|
||||
└────────────────────────┬────────────────────────────────────┘
|
||||
│ PluginAPI.issueProvider.*
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ PLUGIN (JavaScript) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ • Register provider manifest (capabilities, config schema) │
|
||||
│ • Handle requests (search, getById, refresh, testConnection)│
|
||||
│ • Define issue field display configuration │
|
||||
│ • Register custom actions (worklogs, transitions) │
|
||||
│ • Open custom dialogs for advanced workflows │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## New PluginAPI Methods Required
|
||||
|
||||
```typescript
|
||||
// Registration
|
||||
registerIssueProvider(manifest: IssueProviderManifest): void;
|
||||
|
||||
// Request handling (plugin implements this)
|
||||
onIssueProviderRequest(
|
||||
handler: (request: IssueProviderRequest) => Promise<IssueProviderResponse>
|
||||
): void;
|
||||
|
||||
// Custom actions for advanced features
|
||||
registerIssueAction(action: IssueCustomAction): void;
|
||||
onIssueAction(actionId: string, handler: (ctx: ActionContext) => Promise<void>): void;
|
||||
|
||||
// Custom dialogs (iFrame-based for complex UI like worklogs)
|
||||
openIssueDialog(config: IssueDialogConfig): Promise<unknown>;
|
||||
|
||||
// Config access
|
||||
getIssueProviderConfig(providerId: string): Promise<Record<string, unknown>>;
|
||||
```
|
||||
|
||||
### IssueProviderManifest Structure
|
||||
|
||||
```typescript
|
||||
interface IssueProviderManifest {
|
||||
providerKey: string; // e.g., 'PLUGIN_LINEAR'
|
||||
displayName: string;
|
||||
icon: string; // SVG or Material icon
|
||||
|
||||
capabilities: {
|
||||
search: boolean;
|
||||
polling: boolean;
|
||||
backlogImport: boolean;
|
||||
updateFromTask: boolean; // sync task changes back
|
||||
};
|
||||
|
||||
configSchema: JSONSchema7; // App renders as native form
|
||||
pollInterval?: number; // ms, 0 = no polling
|
||||
|
||||
issueContentConfig: {
|
||||
// How to display issue details
|
||||
fields: IssueFieldConfig[];
|
||||
comments?: CommentConfig;
|
||||
};
|
||||
|
||||
customActions?: IssueCustomAction[]; // Worklogs, transitions, etc.
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## How Advanced Features Work
|
||||
|
||||
### Example: Jira Worklog
|
||||
|
||||
1. **Plugin registers action:**
|
||||
|
||||
```javascript
|
||||
api.registerIssueProvider({
|
||||
providerKey: 'PLUGIN_JIRA',
|
||||
customActions: [
|
||||
{
|
||||
id: 'jira-worklog',
|
||||
label: 'Log Work',
|
||||
icon: 'schedule',
|
||||
placement: ['taskMenu', 'issuePanel'],
|
||||
},
|
||||
],
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
2. **User clicks "Log Work" in task menu**
|
||||
|
||||
3. **App calls plugin's action handler:**
|
||||
|
||||
```javascript
|
||||
api.onIssueAction('jira-worklog', async (ctx) => {
|
||||
// Open iFrame dialog with worklog form
|
||||
const result = await api.openIssueDialog({
|
||||
title: `Log Work - ${ctx.issue.key}`,
|
||||
iframeUrl: 'worklog.html',
|
||||
data: { task: ctx.task, issue: ctx.issue },
|
||||
});
|
||||
|
||||
if (result?.submitted) {
|
||||
// Submit to Jira API, then refresh
|
||||
await submitWorklog(result.data);
|
||||
api.dispatchAction({ type: '[Task] Refresh Issue', taskId: ctx.task.id });
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
4. **Plugin's `worklog.html` renders the form in iFrame**
|
||||
|
||||
---
|
||||
|
||||
## What App Controls vs What Plugin Controls
|
||||
|
||||
| Responsibility | App | Plugin |
|
||||
| --------------------- | -------------------------- | ----------------------------- |
|
||||
| Config form UI | JSON Schema -> native form | Provides schema |
|
||||
| Issue list/search UI | Renders search results | Returns data |
|
||||
| Issue content display | Renders fields | Provides field config |
|
||||
| Polling timing | Manages timers | Handles refresh requests |
|
||||
| State persistence | NgRx store + sync | Provider config stored by app |
|
||||
| Custom action menu | Shows action buttons | Registers actions + handlers |
|
||||
| Custom dialogs | Hosts iFrame | Provides iFrame content |
|
||||
|
||||
---
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 1: Plugin API Foundation
|
||||
|
||||
- Add `registerIssueProvider()` and `onIssueProviderRequest()` to PluginAPI
|
||||
- Create `PluginIssueProviderRegistry` service
|
||||
- Create `PluginIssueProviderProxy` implementing `IssueServiceInterface`
|
||||
- Modify `IssueService` to route to plugin providers
|
||||
- Extend `IssueProvider` model with `pluginConfig` field
|
||||
|
||||
**Files to modify:**
|
||||
|
||||
- `src/app/plugins/plugin-api.ts`
|
||||
- `src/app/plugins/plugin-bridge.service.ts`
|
||||
- `src/app/features/issue/issue.service.ts`
|
||||
- `src/app/features/issue/issue.model.ts`
|
||||
|
||||
**Files to create:**
|
||||
|
||||
- `src/app/plugins/issue-provider/plugin-issue-provider.registry.ts`
|
||||
- `src/app/plugins/issue-provider/plugin-issue-provider.proxy.ts`
|
||||
- `packages/plugin-api/src/issue-provider.ts` (types)
|
||||
|
||||
### Phase 2: Core Integration
|
||||
|
||||
- Add plugin provider search to add-task bar
|
||||
- Support plugin `issueContentConfig` in issue display component
|
||||
- Create config dialog that renders JSON Schema
|
||||
- Integrate plugin providers into polling effects
|
||||
|
||||
**Files to modify:**
|
||||
|
||||
- `src/app/features/tasks/add-task-bar/add-task-bar-issue-search.service.ts`
|
||||
- `src/app/features/issue/issue-content/issue-content.component.ts`
|
||||
- `src/app/features/issue/store/poll-issue-updates.effects.ts`
|
||||
|
||||
### Phase 3: Custom Actions
|
||||
|
||||
- Add `registerIssueAction()` and `onIssueAction()` to PluginAPI
|
||||
- Create UI for showing plugin actions in task context menu
|
||||
- Implement `openIssueDialog()` for iFrame-based custom dialogs
|
||||
|
||||
**Files to modify:**
|
||||
|
||||
- `src/app/features/tasks/task-context-menu/task-context-menu.component.ts`
|
||||
- `src/app/features/issue/issue-content/issue-content.component.ts`
|
||||
|
||||
**Files to create:**
|
||||
|
||||
- `src/app/plugins/ui/plugin-issue-dialog/plugin-issue-dialog.component.ts`
|
||||
|
||||
### Phase 4: Sample Plugin + Documentation
|
||||
|
||||
- Create sample plugin (e.g., Linear or simple GitHub clone)
|
||||
- Write plugin development guide
|
||||
- Test full workflow
|
||||
|
||||
### Phase 5: Migrate Built-in Providers (optional, per-provider)
|
||||
|
||||
- Convert providers to plugin format
|
||||
- Add lazy loading for bundle reduction
|
||||
- Keep built-in as fallback during transition
|
||||
|
||||
---
|
||||
|
||||
## Advantages
|
||||
|
||||
1. **Community providers**: Anyone can create a provider without forking the app
|
||||
2. **Decoupled releases**: Provider updates independent of app releases
|
||||
3. **Reduced bundle** (Phase 5): ~1.2MB of provider code can be lazy-loaded
|
||||
4. **Consistent architecture**: Single plugin system for all extensions
|
||||
5. **User choice**: Install only providers you need
|
||||
|
||||
## Disadvantages
|
||||
|
||||
1. **Development effort**: Significant upfront work
|
||||
2. **Dual maintenance**: During transition, maintain both systems
|
||||
3. **Plugin dialog UX**: iFrame dialogs won't match app styling perfectly
|
||||
4. **Type safety**: Plugin code is JavaScript, loses TypeScript benefits
|
||||
5. **Performance**: Small overhead from plugin communication
|
||||
|
||||
---
|
||||
|
||||
## Risks & Mitigations
|
||||
|
||||
| Risk | Mitigation |
|
||||
| -------------------------------- | -------------------------------------------- |
|
||||
| Plugin dialogs feel disconnected | Pass theme CSS vars, provide styling guide |
|
||||
| Breaking existing configs | Keep built-in providers, migration tool |
|
||||
| Plugin security (credentials) | Configs stored in app, passed per-request |
|
||||
| Performance overhead | Batch requests, cache in registry |
|
||||
| Complex provider migration | Start with simple providers (Gitea, Redmine) |
|
||||
|
||||
---
|
||||
|
||||
## Effort Estimate
|
||||
|
||||
| Phase | Scope | Effort |
|
||||
| ------- | ---------------------- | -------------- |
|
||||
| Phase 1 | Plugin API foundation | 1-2 weeks |
|
||||
| Phase 2 | Core integration | 1-2 weeks |
|
||||
| Phase 3 | Custom actions | 1 week |
|
||||
| Phase 4 | Sample plugin + docs | 1 week |
|
||||
| Phase 5 | Per-provider migration | 1-2 weeks each |
|
||||
|
||||
**Total for enabling plugin providers**: ~4-6 weeks
|
||||
**Per built-in provider migration**: ~1-2 weeks each (9 providers = 9-18 weeks if all migrated)
|
||||
|
||||
---
|
||||
|
||||
## Recommendation
|
||||
|
||||
**Start with Phases 1-4** to enable community providers. This gives you:
|
||||
|
||||
- Community can create new providers
|
||||
- Proves the architecture works
|
||||
- ~4-6 weeks of work
|
||||
|
||||
**Phase 5 (migration)** can be done incrementally or skipped:
|
||||
|
||||
- Built-in providers continue working
|
||||
- Migrate only if bundle size becomes critical
|
||||
- Start with simple providers (Gitea, Redmine)
|
||||
- Keep Jira built-in longest (most complex)
|
||||
|
||||
This approach gets value quickly while keeping risk low.
|
||||
195
docs/ai/plugin-ui-consistency-plan.md
Normal file
195
docs/ai/plugin-ui-consistency-plan.md
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
# Plan: Plugin UI Consistency via CSS Library + Reactive Theme
|
||||
|
||||
## Goal
|
||||
|
||||
Make iframe plugin UI more consistent with the main app by:
|
||||
|
||||
1. Providing a shared CSS component library
|
||||
2. Adding reactive theme updates when user switches dark/light mode
|
||||
|
||||
## Approach
|
||||
|
||||
CSS-only component library (minimal: 5-7 components) + reactive theme hook
|
||||
|
||||
---
|
||||
|
||||
## Part 1: Reactive Theme Updates
|
||||
|
||||
### Changes Required
|
||||
|
||||
**1. Add `THEME_CHANGE` hook**
|
||||
|
||||
- File: `src/app/plugins/plugin-api.model.ts`
|
||||
- Add `THEME_CHANGE = 'themeChange'` to `PluginHooks` enum
|
||||
|
||||
**2. Emit theme change events to plugins**
|
||||
|
||||
- File: `src/app/plugins/plugin-bridge.service.ts`
|
||||
- Subscribe to `GlobalThemeService.darkMode()` signal
|
||||
- When theme changes, call all registered `themeChange` hook handlers
|
||||
- Also post `THEME_UPDATE` message to all active plugin iframes with new CSS variables
|
||||
|
||||
**3. Add message handler in iframe for CSS variable updates**
|
||||
|
||||
- File: `src/app/plugins/util/plugin-iframe.util.ts`
|
||||
- Add new message type `THEME_UPDATE` to handle dynamic CSS variable injection
|
||||
- In `createPluginApiScript()`, add listener that updates `:root` CSS variables
|
||||
|
||||
**4. Update plugin API types**
|
||||
|
||||
- File: `packages/plugin-api/src/index.ts`
|
||||
- Add `THEME_UPDATE` to `PluginIframeMessageType`
|
||||
- Export `THEME_CHANGE` hook type
|
||||
|
||||
---
|
||||
|
||||
## Part 2: CSS Component Library
|
||||
|
||||
### Components to Include (Minimal Set)
|
||||
|
||||
1. **Buttons** - `.btn`, `.btn-primary`, `.btn-outline`, `.btn-icon`
|
||||
2. **Cards** - `.card`, `.card-header`, `.card-content`
|
||||
3. **Inputs** - `.input`, `.textarea`, `.select`
|
||||
4. **Checkbox/Toggle** - `.checkbox`, `.toggle`
|
||||
5. **Text utilities** - `.text-muted`, `.text-primary`, `.text-sm`
|
||||
6. **Layout helpers** - `.flex`, `.gap`, `.stack` (vertical stack)
|
||||
7. **Lists** - `.list`, `.list-item`
|
||||
|
||||
> **No prefix** - keeps classes simple. Plugins are isolated in iframes so no conflict risk.
|
||||
|
||||
### Implementation
|
||||
|
||||
**1. Create CSS library file**
|
||||
|
||||
- File: `src/assets/plugin-components.css`
|
||||
- Define all component classes using existing CSS variables
|
||||
- Match Angular Material visual style (border-radius, shadows, colors, etc.)
|
||||
|
||||
**2. Inject CSS library into plugin iframes**
|
||||
|
||||
- File: `src/app/plugins/util/plugin-iframe.util.ts`
|
||||
- Modify `createPluginCssInjection()` to include the component library CSS
|
||||
- Alternatively, inline the CSS directly (avoids external fetch issues in blob URLs)
|
||||
|
||||
**3. Document for plugin developers**
|
||||
|
||||
- Add documentation/examples in `packages/plugin-dev/`
|
||||
- Update one example plugin to demonstrate usage
|
||||
|
||||
---
|
||||
|
||||
## Files to Modify
|
||||
|
||||
| File | Changes |
|
||||
| -------------------------------------------- | ----------------------------------------- |
|
||||
| `src/app/plugins/plugin-api.model.ts` | Add `THEME_CHANGE` hook |
|
||||
| `packages/plugin-api/src/index.ts` | Add `THEME_UPDATE` message type |
|
||||
| `src/app/plugins/plugin-bridge.service.ts` | Emit theme change events |
|
||||
| `src/app/plugins/util/plugin-iframe.util.ts` | Handle `THEME_UPDATE`, inject CSS library |
|
||||
| `src/assets/plugin-components.css` | **New file** - CSS component library |
|
||||
|
||||
---
|
||||
|
||||
## Implementation Order
|
||||
|
||||
1. Add `THEME_UPDATE` message type to plugin API package
|
||||
2. Create `plugin-components.css` with minimal components
|
||||
3. Update `createPluginCssInjection()` to inject the CSS library
|
||||
4. Add `THEME_CHANGE` hook type
|
||||
5. Implement theme change detection and broadcasting in `plugin-bridge.service.ts`
|
||||
6. Add message handler in iframe script for updating CSS variables
|
||||
7. Test with existing plugin (e.g., procrastination-buster)
|
||||
|
||||
---
|
||||
|
||||
## CSS Component Library Design
|
||||
|
||||
```css
|
||||
/* Example structure for plugin-components.css */
|
||||
|
||||
/* Buttons */
|
||||
.btn {
|
||||
padding: var(--s-half) var(--s);
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--extra-border-color);
|
||||
background: transparent;
|
||||
color: var(--text-color);
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
transition: var(--transition-standard);
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
border-color: var(--c-primary);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--c-primary);
|
||||
border-color: var(--c-primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
|
||||
/* Cards */
|
||||
.card {
|
||||
background: var(--card-bg);
|
||||
border-radius: var(--card-border-radius);
|
||||
box-shadow: var(--card-shadow);
|
||||
padding: var(--s2);
|
||||
}
|
||||
|
||||
/* Inputs */
|
||||
.input,
|
||||
.textarea,
|
||||
.select {
|
||||
padding: var(--s-half) var(--s);
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--extra-border-color);
|
||||
background: var(--bg);
|
||||
color: var(--text-color);
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.input:focus,
|
||||
.textarea:focus,
|
||||
.select:focus {
|
||||
outline: none;
|
||||
border-color: var(--c-primary);
|
||||
}
|
||||
|
||||
/* Text utilities */
|
||||
.text-muted {
|
||||
color: var(--text-color-muted);
|
||||
}
|
||||
.text-primary {
|
||||
color: var(--c-primary);
|
||||
}
|
||||
.text-sm {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
/* Layout */
|
||||
.stack {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--s);
|
||||
}
|
||||
.flex {
|
||||
display: flex;
|
||||
gap: var(--s);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- CSS library is opt-in (plugins can use it or ignore it)
|
||||
- Existing plugins continue to work (backward compatible)
|
||||
- Theme updates happen automatically via postMessage
|
||||
- Plugins can also manually listen to `THEME_CHANGE` hook for custom handling
|
||||
Loading…
Add table
Add a link
Reference in a new issue