mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-18 00:46:45 +00:00
897 lines
34 KiB
HTML
897 lines
34 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta
|
|
name="viewport"
|
|
content="width=device-width, initial-scale=1.0"
|
|
/>
|
|
<title>API Test Plugin Dashboard</title>
|
|
<style>
|
|
/* Theme vars + UI Kit are injected automatically.
|
|
Only layout rules that the UI Kit can't provide. */
|
|
|
|
body {
|
|
padding: var(--s3);
|
|
}
|
|
|
|
.button-grid {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: var(--s);
|
|
}
|
|
|
|
.api-list {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: var(--s-half);
|
|
}
|
|
|
|
.console {
|
|
max-height: 200px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.console-entry.success {
|
|
color: var(--color-success);
|
|
}
|
|
|
|
.console-entry.error {
|
|
color: var(--color-danger);
|
|
}
|
|
|
|
.console-entry.info {
|
|
color: var(--text-color-muted);
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>API Test Plugin</h1>
|
|
|
|
<h3>Available API Methods</h3>
|
|
<p class="api-list">
|
|
<code>getTasks()</code>
|
|
<code>getArchivedTasks()</code>
|
|
<code>getCurrentContextTasks()</code>
|
|
<code>addTask(data)</code>
|
|
<code>updateTask(id, data)</code>
|
|
<code>getAllProjects()</code>
|
|
<code>addProject(data)</code>
|
|
<code>updateProject(id, data)</code>
|
|
<code>getAllTags()</code>
|
|
<code>addTag(data)</code>
|
|
<code>updateTag(id, data)</code>
|
|
<code>showSnack(config)</code>
|
|
<code>notify(config)</code>
|
|
<code>openDialog(config)</code>
|
|
<code>persistDataSynced(data)</code>
|
|
<code>loadSyncedData()</code>
|
|
<code>registerHook(hook, handler)</code>
|
|
<code>registerHeaderButton(config)</code>
|
|
<code>registerMenuEntry(config)</code>
|
|
<code>registerShortcut(config)</code>
|
|
<code>setCounter(key, value)</code>
|
|
<code>getCounter(key)</code>
|
|
<code>incrementCounter(key, amount)</code>
|
|
<code>decrementCounter(key, amount)</code>
|
|
<code>deleteCounter(key)</code>
|
|
<code>getAllCounters()</code>
|
|
</p>
|
|
<hr />
|
|
|
|
<button onclick="runAllTests()">Run All API Tests</button>
|
|
|
|
<hr />
|
|
|
|
<h2>Data Persistence Tests</h2>
|
|
<div class="button-grid">
|
|
<button onclick="testPersistData()">Test Save Data</button>
|
|
<button onclick="testLoadData()">Test Load Data</button>
|
|
</div>
|
|
|
|
<h2>Task Operations</h2>
|
|
<div class="button-grid">
|
|
<button onclick="testGetTasks()">Get All Tasks</button>
|
|
<button onclick="testGetArchivedTasks()">Get Archived Tasks</button>
|
|
<button onclick="testGetContextTasks()">Get Context Tasks</button>
|
|
<button onclick="testCreateTask()">Create Test Task</button>
|
|
<button onclick="testUpdateTask()">Update Last Task</button>
|
|
</div>
|
|
|
|
<h2>Project & Tag Operations</h2>
|
|
<div class="button-grid">
|
|
<button onclick="testGetProjects()">Get All Projects</button>
|
|
<button onclick="testCreateProject()">Create Test Project</button>
|
|
<button onclick="testGetTags()">Get All Tags</button>
|
|
<button onclick="testCreateTag()">Create Test Tag</button>
|
|
</div>
|
|
|
|
<h2>UI Operations</h2>
|
|
<div class="button-grid">
|
|
<button onclick="testSnackSuccess()">Success Snack</button>
|
|
<button onclick="testSnackError()">Error Snack</button>
|
|
<button onclick="testSnackCustom()">Info Snack</button>
|
|
<button onclick="testNotification()">Show Notification</button>
|
|
<button onclick="testDialog()">Open Dialog</button>
|
|
</div>
|
|
|
|
<h2>Advanced Dialog Examples</h2>
|
|
<div class="button-grid">
|
|
<button onclick="showTaskPlannerDialog()">Task Planner</button>
|
|
<button onclick="showAnalyticsDialog()">Analytics Dashboard</button>
|
|
</div>
|
|
|
|
<pre
|
|
class="console"
|
|
id="console"
|
|
><span class="console-entry info">Console output will appear here...</span></pre>
|
|
|
|
<hr />
|
|
|
|
<h2>UI Kit Component Showcase</h2>
|
|
|
|
<h3>Headings</h3>
|
|
<h1>Heading 1</h1>
|
|
<h2>Heading 2</h2>
|
|
<h3>Heading 3</h3>
|
|
<h4>Heading 4</h4>
|
|
<h5>Heading 5</h5>
|
|
<h6>Heading 6</h6>
|
|
|
|
<h3>Text</h3>
|
|
<p>
|
|
This is a paragraph with <strong>bold</strong>, <em>italic</em>, and
|
|
<a href="#">link</a> styles.
|
|
</p>
|
|
<p>Inline <code>code</code> is styled automatically.</p>
|
|
|
|
<h3>Buttons</h3>
|
|
<div class="button-grid">
|
|
<button>Default</button>
|
|
<button class="btn-primary">Primary</button>
|
|
<button class="btn-outline">Outline</button>
|
|
<button disabled>Disabled</button>
|
|
<button
|
|
class="btn-primary"
|
|
disabled
|
|
>
|
|
Primary Disabled
|
|
</button>
|
|
<button
|
|
class="btn-outline"
|
|
disabled
|
|
>
|
|
Outline Disabled
|
|
</button>
|
|
</div>
|
|
|
|
<h3>Inputs</h3>
|
|
<input
|
|
type="text"
|
|
placeholder="Text input"
|
|
/>
|
|
<textarea placeholder="Textarea"></textarea>
|
|
<select>
|
|
<option>Select option 1</option>
|
|
<option>Select option 2</option>
|
|
<option>Select option 3</option>
|
|
</select>
|
|
<label><input type="checkbox" /> Checkbox label</label>
|
|
|
|
<h3>Code Block</h3>
|
|
<pre><code>const tasks = await PluginAPI.getTasks();
|
|
console.log(tasks.length);</code></pre>
|
|
|
|
<h3>Table</h3>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Method</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>getTasks()</code></td>
|
|
<td>Get all active tasks</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>addTask(data)</code></td>
|
|
<td>Create a new task</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>showSnack(cfg)</code></td>
|
|
<td>Show a notification</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
<h3>Lists</h3>
|
|
<ul>
|
|
<li>Unordered list item 1</li>
|
|
<li>Unordered list item 2</li>
|
|
<li>Unordered list item 3</li>
|
|
</ul>
|
|
<ol>
|
|
<li>Ordered list item 1</li>
|
|
<li>Ordered list item 2</li>
|
|
<li>Ordered list item 3</li>
|
|
</ol>
|
|
|
|
<h3>Cards</h3>
|
|
<div class="card">
|
|
<h4>Default Card</h4>
|
|
<p>A static card with background, shadow, and border.</p>
|
|
</div>
|
|
<br />
|
|
<div class="card card-clickable">
|
|
<h4>Clickable Card</h4>
|
|
<p>Hover to see the lift effect and primary border highlight.</p>
|
|
</div>
|
|
|
|
<h3>Horizontal Rule</h3>
|
|
<hr />
|
|
|
|
<script>
|
|
let lastTaskId = null;
|
|
let lastProjectId = null;
|
|
let lastTagId = null;
|
|
|
|
// Console logging
|
|
function log(message, type = 'info') {
|
|
const con = document.getElementById('console');
|
|
const entry = document.createElement('span');
|
|
entry.className = `console-entry ${type}`;
|
|
entry.textContent = `[${new Date().toLocaleTimeString()}] ${message}\n`;
|
|
con.appendChild(entry);
|
|
con.scrollTop = con.scrollHeight;
|
|
}
|
|
|
|
// Clear console
|
|
function clearConsole() {
|
|
document.getElementById('console').innerHTML =
|
|
'<span class="console-entry info">Console cleared. Starting new test run...\n</span>';
|
|
}
|
|
|
|
// Test functions
|
|
async function testPersistData() {
|
|
try {
|
|
const testData = {
|
|
timestamp: new Date().toISOString(),
|
|
randomValue: Math.floor(Math.random() * 1000),
|
|
message: 'Test data from iframe',
|
|
};
|
|
await PluginAPI.persistDataSynced(JSON.stringify(testData));
|
|
log('Data saved successfully: ' + JSON.stringify(testData), 'success');
|
|
} catch (error) {
|
|
log('Failed to save data: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function testLoadData() {
|
|
try {
|
|
const data = await PluginAPI.loadSyncedData();
|
|
if (data) {
|
|
const parsed = JSON.parse(data);
|
|
log('Data loaded successfully: ' + JSON.stringify(parsed), 'success');
|
|
} else {
|
|
log('No saved data found', 'info');
|
|
}
|
|
} catch (error) {
|
|
log('Failed to load data: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function testGetTasks() {
|
|
try {
|
|
const tasks = await PluginAPI.getTasks();
|
|
log(`Found ${tasks.length} tasks`, 'success');
|
|
if (tasks.length > 0) {
|
|
lastTaskId = tasks[0].id;
|
|
log(`Sample task: "${tasks[0].title}"`, 'info');
|
|
}
|
|
} catch (error) {
|
|
log('Failed to get tasks: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function testGetArchivedTasks() {
|
|
try {
|
|
const tasks = await PluginAPI.getArchivedTasks();
|
|
log(`Found ${tasks.length} archived tasks`, 'success');
|
|
} catch (error) {
|
|
log('Failed to get archived tasks: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function testGetContextTasks() {
|
|
try {
|
|
const tasks = await PluginAPI.getCurrentContextTasks();
|
|
log(`Found ${tasks.length} tasks in current context`, 'success');
|
|
} catch (error) {
|
|
log('Failed to get context tasks: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function testCreateTask() {
|
|
try {
|
|
const taskData = {
|
|
title: 'Test Task from iFrame - ' + new Date().toLocaleTimeString(),
|
|
notes: 'Created from the API Test Plugin dashboard',
|
|
timeEstimate: 1800000, // 30 minutes
|
|
};
|
|
lastTaskId = await PluginAPI.addTask(taskData);
|
|
log(`Task created with ID: ${lastTaskId}`, 'success');
|
|
} catch (error) {
|
|
log('Failed to create task: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function testUpdateTask() {
|
|
if (!lastTaskId) {
|
|
log('No task ID available. Create a task first!', 'error');
|
|
return;
|
|
}
|
|
try {
|
|
await PluginAPI.updateTask(lastTaskId, {
|
|
notes: 'Updated from dashboard at ' + new Date().toLocaleTimeString(),
|
|
});
|
|
log(`Task ${lastTaskId} updated successfully`, 'success');
|
|
} catch (error) {
|
|
log('Failed to update task: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function testGetProjects() {
|
|
try {
|
|
const projects = await PluginAPI.getAllProjects();
|
|
log(`Found ${projects.length} projects`, 'success');
|
|
if (projects.length > 0) {
|
|
lastProjectId = projects[0].id;
|
|
log(`Sample project: "${projects[0].title}"`, 'info');
|
|
}
|
|
} catch (error) {
|
|
log('Failed to get projects: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function testCreateProject() {
|
|
try {
|
|
const project = await PluginAPI.addProject({
|
|
title: 'Test Project - ' + new Date().toLocaleDateString(),
|
|
themeColor: '#' + Math.floor(Math.random() * 16777215).toString(16),
|
|
});
|
|
lastProjectId = project.id;
|
|
log(`Project created: "${project.title}"`, 'success');
|
|
} catch (error) {
|
|
log('Failed to create project: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
// Counter test functions
|
|
async function testSetCounter() {
|
|
try {
|
|
const value = Math.floor(Math.random() * 100);
|
|
await PluginAPI.setCounter('testCounter', value);
|
|
log(`Counter 'testCounter' set to ${value}`, 'success');
|
|
} catch (error) {
|
|
log('Failed to set counter: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function testGetCounter() {
|
|
try {
|
|
const value = await PluginAPI.getCounter('testCounter');
|
|
if (value !== null) {
|
|
log(`Counter 'testCounter' value: ${value}`, 'success');
|
|
} else {
|
|
log("Counter 'testCounter' not found", 'info');
|
|
}
|
|
} catch (error) {
|
|
log('Failed to get counter: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function testIncrementCounter() {
|
|
try {
|
|
const newValue = await PluginAPI.incrementCounter('testCounter', 5);
|
|
log(
|
|
`Counter 'testCounter' incremented by 5, new value: ${newValue}`,
|
|
'success',
|
|
);
|
|
} catch (error) {
|
|
log('Failed to increment counter: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function testDecrementCounter() {
|
|
try {
|
|
const newValue = await PluginAPI.decrementCounter('testCounter', 3);
|
|
log(
|
|
`Counter 'testCounter' decremented by 3, new value: ${newValue}`,
|
|
'success',
|
|
);
|
|
} catch (error) {
|
|
log('Failed to decrement counter: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function testDeleteCounter() {
|
|
try {
|
|
await PluginAPI.deleteCounter('testCounter');
|
|
log("Counter 'testCounter' deleted", 'success');
|
|
} catch (error) {
|
|
log('Failed to delete counter: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function testGetAllCounters() {
|
|
try {
|
|
// Create some test counters first
|
|
await PluginAPI.setCounter('counter1', 10);
|
|
await PluginAPI.setCounter('counter2', 20);
|
|
await PluginAPI.setCounter('counter3', 30);
|
|
|
|
const counters = await PluginAPI.getAllCounters();
|
|
log('All counters: ' + JSON.stringify(counters), 'success');
|
|
} catch (error) {
|
|
log('Failed to get all counters: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function testGetTags() {
|
|
try {
|
|
const tags = await PluginAPI.getAllTags();
|
|
log(`Found ${tags.length} tags`, 'success');
|
|
if (tags.length > 0) {
|
|
lastTagId = tags[0].id;
|
|
log(`Sample tag: "${tags[0].title}"`, 'info');
|
|
}
|
|
} catch (error) {
|
|
log('Failed to get tags: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function testCreateTag() {
|
|
try {
|
|
const tag = await PluginAPI.addTag({
|
|
title: 'Test Tag - ' + Date.now(),
|
|
color: '#' + Math.floor(Math.random() * 16777215).toString(16),
|
|
});
|
|
lastTagId = tag.id;
|
|
log(`Tag created: "${tag.title}"`, 'success');
|
|
} catch (error) {
|
|
log('Failed to create tag: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
function testSnackSuccess() {
|
|
PluginAPI.showSnack({
|
|
msg: 'This is a success message',
|
|
type: 'SUCCESS',
|
|
ico: 'check_circle',
|
|
});
|
|
log('Success snack shown', 'success');
|
|
}
|
|
|
|
function testSnackError() {
|
|
PluginAPI.showSnack({
|
|
msg: 'This is an error message',
|
|
type: 'ERROR',
|
|
ico: 'error',
|
|
});
|
|
log('Error snack shown', 'success');
|
|
}
|
|
|
|
function testSnackCustom() {
|
|
PluginAPI.showSnack({
|
|
msg: 'This is an info message',
|
|
type: 'INFO',
|
|
ico: 'info',
|
|
});
|
|
log('Info snack shown', 'success');
|
|
}
|
|
|
|
function testNotification() {
|
|
PluginAPI.notify({
|
|
title: 'API Test Notification',
|
|
body: 'This notification was triggered from the plugin dashboard!',
|
|
});
|
|
log('Notification sent', 'success');
|
|
}
|
|
|
|
async function testDialog() {
|
|
const result = await PluginAPI.openDialog({
|
|
title: 'Test Dialog from iFrame',
|
|
htmlContent: `
|
|
<div style="padding: 20px; color: #ccc; font-family: monospace;">
|
|
<h3 style="margin: 0 0 10px 0; font-size: 14px;">Test Dialog</h3>
|
|
<p style="margin: 5px 0; font-size: 12px;">Dialog opened from plugin dashboard</p>
|
|
<p style="margin: 5px 0; font-size: 12px; color: #999;">${new Date().toLocaleString()}</p>
|
|
</div>
|
|
`,
|
|
buttons: [
|
|
{
|
|
label: 'Awesome',
|
|
icon: 'thumb_up',
|
|
color: 'primary',
|
|
onClick: () => {
|
|
log('Dialog button clicked', 'success');
|
|
},
|
|
},
|
|
],
|
|
});
|
|
log('Dialog closed with result: ' + result, 'success');
|
|
}
|
|
|
|
function testThemeInfo() {
|
|
try {
|
|
const themeInfo = PluginAPI.getThemeInfo();
|
|
log('Theme Info:', 'info');
|
|
log(' Dark Theme: ' + themeInfo.isDarkTheme, 'info');
|
|
log(' Primary Color: ' + themeInfo.primaryColor, 'info');
|
|
log(' Accent Color: ' + themeInfo.accentColor, 'info');
|
|
log(' Warn Color: ' + themeInfo.warnColor, 'info');
|
|
log(' Background: ' + themeInfo.backgroundColor, 'info');
|
|
log(' Text Color: ' + themeInfo.textColor, 'info');
|
|
|
|
// Also show in a dialog
|
|
PluginAPI.openDialog({
|
|
title: 'Current Theme Information',
|
|
htmlContent: `
|
|
<div style="padding: 20px; font-family: monospace;">
|
|
<h3 style="margin: 0 0 15px 0;">Theme Variables</h3>
|
|
<table style="width: 100%; border-collapse: collapse;">
|
|
<tr style="border-bottom: 1px solid var(--divider-color, #333);">
|
|
<td style="padding: 8px;">Dark Theme</td>
|
|
<td style="padding: 8px; text-align: right;">${themeInfo.isDarkTheme ? 'Yes' : 'No'}</td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid var(--divider-color, #333);">
|
|
<td style="padding: 8px;">Primary Color</td>
|
|
<td style="padding: 8px; text-align: right;">
|
|
<span style="display: inline-block; width: 20px; height: 20px; background: ${themeInfo.primaryColor}; vertical-align: middle; margin-right: 8px; border: 1px solid var(--divider-color, #333);"></span>
|
|
${themeInfo.primaryColor}
|
|
</td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid var(--divider-color, #333);">
|
|
<td style="padding: 8px;">Accent Color</td>
|
|
<td style="padding: 8px; text-align: right;">
|
|
<span style="display: inline-block; width: 20px; height: 20px; background: ${themeInfo.accentColor}; vertical-align: middle; margin-right: 8px; border: 1px solid var(--divider-color, #333);"></span>
|
|
${themeInfo.accentColor}
|
|
</td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid var(--divider-color, #333);">
|
|
<td style="padding: 8px;">Warn Color</td>
|
|
<td style="padding: 8px; text-align: right;">
|
|
<span style="display: inline-block; width: 20px; height: 20px; background: ${themeInfo.warnColor}; vertical-align: middle; margin-right: 8px; border: 1px solid var(--divider-color, #333);"></span>
|
|
${themeInfo.warnColor}
|
|
</td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid var(--divider-color, #333);">
|
|
<td style="padding: 8px;">Background</td>
|
|
<td style="padding: 8px; text-align: right;">
|
|
<span style="display: inline-block; width: 20px; height: 20px; background: ${themeInfo.backgroundColor}; vertical-align: middle; margin-right: 8px; border: 1px solid var(--divider-color, #333);"></span>
|
|
${themeInfo.backgroundColor}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding: 8px;">Text Color</td>
|
|
<td style="padding: 8px; text-align: right;">
|
|
<span style="display: inline-block; width: 20px; height: 20px; background: ${themeInfo.textColor}; vertical-align: middle; margin-right: 8px; border: 1px solid var(--divider-color, #333);"></span>
|
|
${themeInfo.textColor}
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<p style="margin-top: 15px; font-size: 12px; color: var(--text-color-muted, #999);">
|
|
Plugins automatically receive all CSS variables from the host application, allowing seamless theme integration.
|
|
</p>
|
|
</div>
|
|
`,
|
|
buttons: [
|
|
{
|
|
label: 'Close',
|
|
color: 'primary',
|
|
},
|
|
],
|
|
});
|
|
} catch (error) {
|
|
log('Failed to get theme info: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function runAllTests() {
|
|
clearConsole();
|
|
log('Starting comprehensive API test suite...', 'info');
|
|
|
|
// Run all tests with delays
|
|
await testPersistData();
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
|
|
await testLoadData();
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
|
|
await testGetTasks();
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
|
|
await testGetArchivedTasks();
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
|
|
await testGetContextTasks();
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
|
|
await testCreateTask();
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
|
|
if (lastTaskId) {
|
|
await testUpdateTask();
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
}
|
|
|
|
await testGetProjects();
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
|
|
await testCreateProject();
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
|
|
await testGetTags();
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
|
|
await testCreateTag();
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
|
|
// Test counter API
|
|
await testSetCounter();
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
|
|
await testGetCounter();
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
|
|
await testIncrementCounter();
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
|
|
await testDecrementCounter();
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
|
|
await testGetAllCounters();
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
|
|
testSnackSuccess();
|
|
await new Promise((r) => setTimeout(r, 1500));
|
|
|
|
testSnackError();
|
|
await new Promise((r) => setTimeout(r, 1500));
|
|
|
|
testSnackCustom();
|
|
await new Promise((r) => setTimeout(r, 1500));
|
|
|
|
testNotification();
|
|
await new Promise((r) => setTimeout(r, 1000));
|
|
|
|
testDialog();
|
|
|
|
log('All tests completed! Check console for detailed results.', 'success');
|
|
}
|
|
|
|
// Advanced Dialog Examples
|
|
function showTaskPlannerDialog() {
|
|
PluginAPI.openDialog({
|
|
title: 'AI Task Planner (Demo)',
|
|
htmlContent: `
|
|
<div style="padding: 20px; max-width: 700px;">
|
|
<div style="display: flex; gap: 20px;">
|
|
<div style="flex: 1;">
|
|
<h4 style="margin-top: 0;">Describe Your Goal</h4>
|
|
<textarea style="width: 100%; min-height: 100px; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-family: inherit;" placeholder="E.g., 'Launch a new mobile app by Q3 2024'">Build a comprehensive plugin system for Super Productivity that allows users to extend functionality</textarea>
|
|
|
|
<h4 style="margin-top: 20px;">Constraints & Preferences</h4>
|
|
<div style="margin-bottom: 10px;">
|
|
<label>
|
|
<input type="checkbox" checked> Break down into weekly milestones
|
|
</label>
|
|
</div>
|
|
<div style="margin-bottom: 10px;">
|
|
<label>
|
|
<input type="checkbox" checked> Include time estimates
|
|
</label>
|
|
</div>
|
|
<div style="margin-bottom: 10px;">
|
|
<label>
|
|
<input type="checkbox"> Add dependencies between tasks
|
|
</label>
|
|
</div>
|
|
<div style="margin-bottom: 10px;">
|
|
<label>
|
|
<input type="checkbox" checked> Prioritize by impact
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="flex: 1; background: #f9f9f9; padding: 15px; border-radius: 8px;">
|
|
<h4 style="margin-top: 0;">Generated Task Breakdown</h4>
|
|
<div style="max-height: 300px; overflow-y: auto;">
|
|
<div style="margin-bottom: 15px; padding: 10px; background: white; border-radius: 4px; border-left: 4px solid #4caf50;">
|
|
<div style="font-weight: bold;">📋 Design Plugin Architecture</div>
|
|
<div style="font-size: 0.9em; color: #666; margin-top: 5px;">Est: 8h | Priority: High</div>
|
|
<div style="font-size: 0.85em; margin-top: 5px;">Define API surface, security model, and manifest structure</div>
|
|
</div>
|
|
<div style="margin-bottom: 15px; padding: 10px; background: white; border-radius: 4px; border-left: 4px solid #ff9800;">
|
|
<div style="font-weight: bold;">🔧 Implement Core Plugin Loader</div>
|
|
<div style="font-size: 0.9em; color: #666; margin-top: 5px;">Est: 16h | Priority: High</div>
|
|
<div style="font-size: 0.85em; margin-top: 5px;">Build sandboxed execution environment and API bridge</div>
|
|
</div>
|
|
<div style="margin-bottom: 15px; padding: 10px; background: white; border-radius: 4px; border-left: 4px solid #2196f3;">
|
|
<div style="font-weight: bold;">🎨 Create Plugin UI Components</div>
|
|
<div style="font-size: 0.9em; color: #666; margin-top: 5px;">Est: 12h | Priority: Medium</div>
|
|
<div style="font-size: 0.85em; margin-top: 5px;">Design settings UI, permission dialogs, and plugin store</div>
|
|
</div>
|
|
<div style="margin-bottom: 15px; padding: 10px; background: white; border-radius: 4px; border-left: 4px solid #9c27b0;">
|
|
<div style="font-weight: bold;">📚 Write Documentation</div>
|
|
<div style="font-size: 0.9em; color: #666; margin-top: 5px;">Est: 6h | Priority: Medium</div>
|
|
<div style="font-size: 0.85em; margin-top: 5px;">Create plugin development guide and API reference</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="margin-top: 20px; padding: 15px; background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 4px;">
|
|
<strong>🤖 AI Analysis:</strong> This project would take approximately 42 hours (5-6 days) with the current breakdown. Consider adding a testing phase and security audit.
|
|
</div>
|
|
</div>
|
|
`,
|
|
buttons: [
|
|
{
|
|
label: 'Regenerate',
|
|
icon: 'refresh',
|
|
onClick: async () => {
|
|
await PluginAPI.showSnack({
|
|
msg: 'Regenerating task breakdown...',
|
|
type: 'INFO',
|
|
ico: 'refresh',
|
|
});
|
|
},
|
|
},
|
|
{
|
|
label: 'Create All Tasks',
|
|
icon: 'add_task',
|
|
color: 'primary',
|
|
onClick: async () => {
|
|
await PluginAPI.showSnack({
|
|
msg: 'Would create 4 tasks in your project',
|
|
type: 'SUCCESS',
|
|
});
|
|
},
|
|
},
|
|
],
|
|
});
|
|
log('Task planner dialog opened', 'success');
|
|
}
|
|
|
|
function showAnalyticsDialog() {
|
|
PluginAPI.openDialog({
|
|
title: 'Productivity Analytics',
|
|
htmlContent: `
|
|
<div style="padding: 20px; max-width: 800px;">
|
|
<div style="display: flex; justify-content: space-between; margin-bottom: 20px;">
|
|
<div>
|
|
<h3 style="margin: 0;">Weekly Performance</h3>
|
|
<p style="margin: 5px 0; color: #666;">Dec 11 - Dec 17, 2023</p>
|
|
</div>
|
|
<div style="display: flex; gap: 10px; align-items: center;">
|
|
<button style="padding: 8px 16px; border: 1px solid #ddd; background: white; border-radius: 4px; cursor: pointer;">Week</button>
|
|
<button style="padding: 8px 16px; border: 1px solid #4caf50; background: #4caf50; color: white; border-radius: 4px; cursor: pointer;">Month</button>
|
|
<button style="padding: 8px 16px; border: 1px solid #ddd; background: white; border-radius: 4px; cursor: pointer;">Year</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 15px; margin-bottom: 30px;">
|
|
<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 8px;">
|
|
<div style="font-size: 2em; font-weight: bold;">147</div>
|
|
<div style="opacity: 0.9;">Tasks Completed</div>
|
|
<div style="font-size: 0.9em; margin-top: 5px; opacity: 0.8;">↑ 23% from last week</div>
|
|
</div>
|
|
<div style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white; padding: 20px; border-radius: 8px;">
|
|
<div style="font-size: 2em; font-weight: bold;">42.5h</div>
|
|
<div style="opacity: 0.9;">Time Tracked</div>
|
|
<div style="font-size: 0.9em; margin-top: 5px; opacity: 0.8;">↑ 5% from last week</div>
|
|
</div>
|
|
<div style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); color: white; padding: 20px; border-radius: 8px;">
|
|
<div style="font-size: 2em; font-weight: bold;">89%</div>
|
|
<div style="opacity: 0.9;">Focus Score</div>
|
|
<div style="font-size: 0.9em; margin-top: 5px; opacity: 0.8;">↓ 2% from last week</div>
|
|
</div>
|
|
<div style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%); color: white; padding: 20px; border-radius: 8px;">
|
|
<div style="font-size: 2em; font-weight: bold;">12</div>
|
|
<div style="opacity: 0.9;">Streaks Active</div>
|
|
<div style="font-size: 0.9em; margin-top: 5px; opacity: 0.8;">Keep it up! 🔥</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="background: #f9f9f9; padding: 20px; border-radius: 8px;">
|
|
<h4 style="margin-top: 0;">Daily Activity Heatmap</h4>
|
|
<div style="display: grid; grid-template-columns: auto repeat(7, 1fr); gap: 10px; font-size: 0.9em;">
|
|
<div></div>
|
|
<div style="text-align: center;">Mon</div>
|
|
<div style="text-align: center;">Tue</div>
|
|
<div style="text-align: center;">Wed</div>
|
|
<div style="text-align: center;">Thu</div>
|
|
<div style="text-align: center;">Fri</div>
|
|
<div style="text-align: center;">Sat</div>
|
|
<div style="text-align: center;">Sun</div>
|
|
|
|
<div>Morning</div>
|
|
<div style="background: #c8e6c9; height: 40px; border-radius: 4px;"></div>
|
|
<div style="background: #4caf50; height: 40px; border-radius: 4px;"></div>
|
|
<div style="background: #81c784; height: 40px; border-radius: 4px;"></div>
|
|
<div style="background: #4caf50; height: 40px; border-radius: 4px;"></div>
|
|
<div style="background: #a5d6a7; height: 40px; border-radius: 4px;"></div>
|
|
<div style="background: #e8f5e9; height: 40px; border-radius: 4px;"></div>
|
|
<div style="background: #e8f5e9; height: 40px; border-radius: 4px;"></div>
|
|
|
|
<div>Afternoon</div>
|
|
<div style="background: #4caf50; height: 40px; border-radius: 4px;"></div>
|
|
<div style="background: #2e7d32; height: 40px; border-radius: 4px;"></div>
|
|
<div style="background: #4caf50; height: 40px; border-radius: 4px;"></div>
|
|
<div style="background: #81c784; height: 40px; border-radius: 4px;"></div>
|
|
<div style="background: #4caf50; height: 40px; border-radius: 4px;"></div>
|
|
<div style="background: #a5d6a7; height: 40px; border-radius: 4px;"></div>
|
|
<div style="background: #c8e6c9; height: 40px; border-radius: 4px;"></div>
|
|
|
|
<div>Evening</div>
|
|
<div style="background: #81c784; height: 40px; border-radius: 4px;"></div>
|
|
<div style="background: #a5d6a7; height: 40px; border-radius: 4px;"></div>
|
|
<div style="background: #c8e6c9; height: 40px; border-radius: 4px;"></div>
|
|
<div style="background: #e8f5e9; height: 40px; border-radius: 4px;"></div>
|
|
<div style="background: #e8f5e9; height: 40px; border-radius: 4px;"></div>
|
|
<div style="background: #81c784; height: 40px; border-radius: 4px;"></div>
|
|
<div style="background: #4caf50; height: 40px; border-radius: 4px;"></div>
|
|
</div>
|
|
<div style="margin-top: 15px; text-align: center; color: #666;">
|
|
<span style="display: inline-block; width: 12px; height: 12px; background: #e8f5e9; margin-right: 5px;"></span> Low
|
|
<span style="display: inline-block; width: 12px; height: 12px; background: #81c784; margin: 0 5px 0 20px;"></span> Medium
|
|
<span style="display: inline-block; width: 12px; height: 12px; background: #4caf50; margin: 0 5px 0 20px;"></span> High
|
|
<span style="display: inline-block; width: 12px; height: 12px; background: #2e7d32; margin: 0 5px 0 20px;"></span> Very High
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`,
|
|
buttons: [
|
|
{
|
|
label: 'Export Report',
|
|
icon: 'download',
|
|
onClick: async () => {
|
|
await PluginAPI.showSnack({
|
|
msg: 'Generating productivity report...',
|
|
type: 'INFO',
|
|
ico: 'download',
|
|
});
|
|
},
|
|
},
|
|
{
|
|
label: 'Share',
|
|
icon: 'share',
|
|
onClick: async () => {
|
|
await PluginAPI.showSnack({
|
|
msg: 'Sharing options would appear here',
|
|
type: 'INFO',
|
|
ico: 'share',
|
|
});
|
|
},
|
|
},
|
|
{
|
|
label: 'Close',
|
|
icon: 'close',
|
|
color: 'primary',
|
|
},
|
|
],
|
|
});
|
|
log('Analytics dialog opened', 'success');
|
|
}
|
|
|
|
// Initial message
|
|
log(
|
|
'API Test Plugin Dashboard loaded. Click buttons to test individual APIs or run all tests.',
|
|
'info',
|
|
);
|
|
</script>
|
|
</body>
|
|
</html>
|