From 093cc13aef7915628d15191269e1634aec6703c5 Mon Sep 17 00:00:00 2001 From: Jake Shore Date: Fri, 13 Feb 2026 03:35:55 -0500 Subject: [PATCH] V3 Batch 1: foundations + tools for Xero, Monday, Intercom, Airtable, Notion + HubSpot apps --- .../src/apps/automation-monitor/App.tsx | 1 + .../src/apps/automation-monitor/index.html | 12 + .../src/apps/automation-monitor/main.tsx | 1 + .../src/apps/automation-monitor/styles.css | 1 + .../airtable/src/apps/base-browser/App.tsx | 156 ++++++ .../airtable/src/apps/base-browser/index.html | 12 + .../airtable/src/apps/base-browser/main.tsx | 58 +++ .../airtable/src/apps/base-browser/styles.css | 350 ++++++++++++++ servers/airtable/src/apps/dashboard/App.tsx | 1 + .../airtable/src/apps/dashboard/index.html | 12 + servers/airtable/src/apps/dashboard/main.tsx | 1 + .../airtable/src/apps/dashboard/styles.css | 1 + .../airtable/src/apps/field-manager/App.tsx | 157 ++++++ .../src/apps/field-manager/index.html | 12 + .../airtable/src/apps/field-manager/main.tsx | 58 +++ .../src/apps/field-manager/styles.css | 1 + .../airtable/src/apps/form-builder/App.tsx | 1 + .../airtable/src/apps/form-builder/index.html | 12 + .../airtable/src/apps/form-builder/main.tsx | 1 + .../airtable/src/apps/form-builder/styles.css | 1 + .../airtable/src/apps/gallery-view/App.tsx | 1 + .../airtable/src/apps/gallery-view/index.html | 12 + .../airtable/src/apps/gallery-view/main.tsx | 1 + .../airtable/src/apps/gallery-view/styles.css | 1 + servers/airtable/src/apps/grid-view/App.tsx | 1 + .../airtable/src/apps/grid-view/index.html | 12 + servers/airtable/src/apps/grid-view/main.tsx | 1 + .../airtable/src/apps/grid-view/styles.css | 1 + .../airtable/src/apps/import-export/App.tsx | 1 + .../src/apps/import-export/index.html | 12 + .../airtable/src/apps/import-export/main.tsx | 1 + .../src/apps/import-export/styles.css | 1 + .../airtable/src/apps/kanban-board/App.tsx | 1 + .../airtable/src/apps/kanban-board/index.html | 12 + .../airtable/src/apps/kanban-board/main.tsx | 1 + .../airtable/src/apps/kanban-board/styles.css | 1 + .../airtable/src/apps/record-editor/App.tsx | 211 ++++++++ .../src/apps/record-editor/index.html | 12 + .../airtable/src/apps/record-editor/main.tsx | 58 +++ .../src/apps/record-editor/styles.css | 342 +++++++++++++ .../airtable/src/apps/schema-designer/App.tsx | 1 + .../src/apps/schema-designer/index.html | 12 + .../src/apps/schema-designer/main.tsx | 1 + .../src/apps/schema-designer/styles.css | 1 + .../src/apps/search-dashboard/App.tsx | 1 + .../src/apps/search-dashboard/index.html | 12 + .../src/apps/search-dashboard/main.tsx | 1 + .../src/apps/search-dashboard/styles.css | 1 + .../airtable/src/apps/table-viewer/App.tsx | 184 +++++++ .../airtable/src/apps/table-viewer/index.html | 12 + .../airtable/src/apps/table-viewer/main.tsx | 58 +++ .../airtable/src/apps/table-viewer/styles.css | 364 ++++++++++++++ .../airtable/src/apps/view-browser/App.tsx | 1 + .../airtable/src/apps/view-browser/index.html | 12 + .../airtable/src/apps/view-browser/main.tsx | 1 + .../airtable/src/apps/view-browser/styles.css | 1 + .../airtable/src/apps/webhook-manager/App.tsx | 1 + .../src/apps/webhook-manager/index.html | 12 + .../src/apps/webhook-manager/main.tsx | 1 + .../src/apps/webhook-manager/styles.css | 1 + servers/intercom/src/apps/admin-panel/App.tsx | 110 +++++ .../intercom/src/apps/admin-panel/index.html | 13 + .../intercom/src/apps/admin-panel/main.tsx | 59 +++ .../intercom/src/apps/admin-panel/styles.css | 409 ++++++++++++++++ .../intercom/src/apps/article-editor/App.tsx | 248 ++++++++++ .../src/apps/article-editor/index.html | 13 + .../intercom/src/apps/article-editor/main.tsx | 59 +++ .../src/apps/article-editor/styles.css | 453 +++++++++++++++++ .../src/apps/automation-center/App.tsx | 112 +++++ .../src/apps/automation-center/index.html | 13 + .../src/apps/automation-center/main.tsx | 59 +++ .../src/apps/automation-center/styles.css | 409 ++++++++++++++++ .../src/apps/collection-manager/App.tsx | 106 ++++ .../src/apps/collection-manager/index.html | 13 + .../src/apps/collection-manager/main.tsx | 59 +++ .../src/apps/collection-manager/styles.css | 409 ++++++++++++++++ .../src/apps/company-directory/App.tsx | 226 +++++++++ .../src/apps/company-directory/index.html | 13 + .../src/apps/company-directory/main.tsx | 59 +++ .../src/apps/company-directory/styles.css | 391 +++++++++++++++ .../intercom/src/apps/contact-manager/App.tsx | 228 +++++++++ .../src/apps/contact-manager/index.html | 13 + .../src/apps/contact-manager/main.tsx | 59 +++ .../src/apps/contact-manager/styles.css | 409 ++++++++++++++++ .../src/apps/conversation-inbox/App.tsx | 240 +++++++++ .../src/apps/conversation-inbox/index.html | 13 + .../src/apps/conversation-inbox/main.tsx | 59 +++ .../src/apps/conversation-inbox/styles.css | 444 +++++++++++++++++ .../intercom/src/apps/customer-360/App.tsx | 112 +++++ .../intercom/src/apps/customer-360/index.html | 13 + .../intercom/src/apps/customer-360/main.tsx | 59 +++ .../intercom/src/apps/customer-360/styles.css | 409 ++++++++++++++++ .../intercom/src/apps/event-timeline/App.tsx | 107 ++++ .../src/apps/event-timeline/index.html | 13 + .../intercom/src/apps/event-timeline/main.tsx | 59 +++ .../src/apps/event-timeline/styles.css | 409 ++++++++++++++++ .../src/apps/message-composer/App.tsx | 110 +++++ .../src/apps/message-composer/index.html | 13 + .../src/apps/message-composer/main.tsx | 59 +++ .../src/apps/message-composer/styles.css | 409 ++++++++++++++++ .../intercom/src/apps/segment-viewer/App.tsx | 108 +++++ .../src/apps/segment-viewer/index.html | 13 + .../intercom/src/apps/segment-viewer/main.tsx | 59 +++ .../src/apps/segment-viewer/styles.css | 409 ++++++++++++++++ servers/intercom/src/apps/sla-monitor/App.tsx | 110 +++++ .../intercom/src/apps/sla-monitor/index.html | 13 + .../intercom/src/apps/sla-monitor/main.tsx | 59 +++ .../intercom/src/apps/sla-monitor/styles.css | 409 ++++++++++++++++ .../src/apps/support-analytics/App.tsx | 110 +++++ .../src/apps/support-analytics/index.html | 13 + .../src/apps/support-analytics/main.tsx | 59 +++ .../src/apps/support-analytics/styles.css | 409 ++++++++++++++++ servers/intercom/src/apps/tag-manager/App.tsx | 108 +++++ .../intercom/src/apps/tag-manager/index.html | 13 + .../intercom/src/apps/tag-manager/main.tsx | 59 +++ .../intercom/src/apps/tag-manager/styles.css | 409 ++++++++++++++++ .../intercom/src/apps/team-dashboard/App.tsx | 110 +++++ .../src/apps/team-dashboard/index.html | 13 + .../intercom/src/apps/team-dashboard/main.tsx | 59 +++ .../src/apps/team-dashboard/styles.css | 409 ++++++++++++++++ .../intercom/src/apps/ticket-center/App.tsx | 107 ++++ .../src/apps/ticket-center/index.html | 13 + .../intercom/src/apps/ticket-center/main.tsx | 59 +++ .../src/apps/ticket-center/styles.css | 409 ++++++++++++++++ servers/monday/src/apps/README.md | 196 ++++++++ servers/monday/src/apps/activity-log/App.tsx | 165 +++++++ .../monday/src/apps/activity-log/index.html | 13 + servers/monday/src/apps/activity-log/main.tsx | 68 +++ .../monday/src/apps/activity-log/styles.css | 322 +++++++++++++ .../src/apps/automation-dashboard/App.tsx | 171 +++++++ .../src/apps/automation-dashboard/index.html | 13 + .../src/apps/automation-dashboard/main.tsx | 68 +++ .../src/apps/automation-dashboard/styles.css | 354 ++++++++++++++ servers/monday/src/apps/board-browser/App.tsx | 155 ++++++ .../monday/src/apps/board-browser/index.html | 13 + .../monday/src/apps/board-browser/main.tsx | 68 +++ .../monday/src/apps/board-browser/styles.css | 327 +++++++++++++ .../src/apps/column-configurator/App.tsx | 172 +++++++ .../src/apps/column-configurator/index.html | 13 + .../src/apps/column-configurator/main.tsx | 68 +++ .../src/apps/column-configurator/styles.css | 346 +++++++++++++ .../monday/src/apps/dashboard-builder/App.tsx | 163 +++++++ .../src/apps/dashboard-builder/index.html | 13 + .../src/apps/dashboard-builder/main.tsx | 68 +++ .../src/apps/dashboard-builder/styles.css | 322 +++++++++++++ .../monday/src/apps/folder-browser/App.tsx | 159 ++++++ .../monday/src/apps/folder-browser/index.html | 13 + .../monday/src/apps/folder-browser/main.tsx | 68 +++ .../monday/src/apps/folder-browser/styles.css | 305 ++++++++++++ servers/monday/src/apps/group-manager/App.tsx | 158 ++++++ .../monday/src/apps/group-manager/index.html | 13 + .../monday/src/apps/group-manager/main.tsx | 68 +++ .../monday/src/apps/group-manager/styles.css | 342 +++++++++++++ servers/monday/src/apps/item-manager/App.tsx | 199 ++++++++ .../monday/src/apps/item-manager/index.html | 13 + servers/monday/src/apps/item-manager/main.tsx | 68 +++ .../monday/src/apps/item-manager/styles.css | 456 ++++++++++++++++++ servers/monday/src/apps/kanban-view/App.tsx | 157 ++++++ .../monday/src/apps/kanban-view/index.html | 13 + servers/monday/src/apps/kanban-view/main.tsx | 68 +++ .../monday/src/apps/kanban-view/styles.css | 338 +++++++++++++ .../monday/src/apps/resource-planner/App.tsx | 164 +++++++ .../src/apps/resource-planner/index.html | 13 + .../monday/src/apps/resource-planner/main.tsx | 68 +++ .../src/apps/resource-planner/styles.css | 338 +++++++++++++ .../monday/src/apps/team-dashboard/App.tsx | 163 +++++++ .../monday/src/apps/team-dashboard/index.html | 13 + .../monday/src/apps/team-dashboard/main.tsx | 68 +++ .../monday/src/apps/team-dashboard/styles.css | 324 +++++++++++++ servers/monday/src/apps/timeline-view/App.tsx | 156 ++++++ .../monday/src/apps/timeline-view/index.html | 13 + .../monday/src/apps/timeline-view/main.tsx | 68 +++ .../monday/src/apps/timeline-view/styles.css | 319 ++++++++++++ servers/monday/src/apps/update-feed/App.tsx | 157 ++++++ .../monday/src/apps/update-feed/index.html | 13 + servers/monday/src/apps/update-feed/main.tsx | 68 +++ .../monday/src/apps/update-feed/styles.css | 315 ++++++++++++ .../monday/src/apps/user-directory/App.tsx | 165 +++++++ .../monday/src/apps/user-directory/index.html | 13 + .../monday/src/apps/user-directory/main.tsx | 68 +++ .../monday/src/apps/user-directory/styles.css | 338 +++++++++++++ .../monday/src/apps/webhook-manager/App.tsx | 167 +++++++ .../src/apps/webhook-manager/index.html | 13 + .../monday/src/apps/webhook-manager/main.tsx | 68 +++ .../src/apps/webhook-manager/styles.css | 353 ++++++++++++++ .../src/apps/workspace-overview/App.tsx | 161 +++++++ .../src/apps/workspace-overview/index.html | 13 + .../src/apps/workspace-overview/main.tsx | 68 +++ .../src/apps/workspace-overview/styles.css | 329 +++++++++++++ servers/notion/APPS_COMPLETE.md | 213 ++++++++ servers/notion/package.json | 4 + servers/notion/src/apps/README.md | 156 ++++++ servers/notion/src/apps/block-editor/App.tsx | 169 +++++++ .../notion/src/apps/block-editor/index.html | 13 + servers/notion/src/apps/block-editor/main.tsx | 46 ++ .../notion/src/apps/block-editor/styles.css | 264 ++++++++++ servers/notion/src/apps/calendar-view/App.tsx | 110 +++++ .../notion/src/apps/calendar-view/index.html | 13 + .../notion/src/apps/calendar-view/main.tsx | 46 ++ .../notion/src/apps/calendar-view/styles.css | 227 +++++++++ .../notion/src/apps/comment-viewer/App.tsx | 129 +++++ .../notion/src/apps/comment-viewer/index.html | 13 + .../notion/src/apps/comment-viewer/main.tsx | 46 ++ .../notion/src/apps/comment-viewer/styles.css | 250 ++++++++++ .../notion/src/apps/database-builder/App.tsx | 168 +++++++ .../src/apps/database-builder/index.html | 13 + .../notion/src/apps/database-builder/main.tsx | 46 ++ .../src/apps/database-builder/styles.css | 314 ++++++++++++ .../notion/src/apps/database-explorer/App.tsx | 141 ++++++ .../src/apps/database-explorer/index.html | 13 + .../src/apps/database-explorer/main.tsx | 46 ++ .../src/apps/database-explorer/styles.css | 254 ++++++++++ .../src/apps/integration-status/App.tsx | 133 +++++ .../src/apps/integration-status/index.html | 13 + .../src/apps/integration-status/main.tsx | 46 ++ .../src/apps/integration-status/styles.css | 295 +++++++++++ servers/notion/src/apps/kanban-view/App.tsx | 116 +++++ .../notion/src/apps/kanban-view/index.html | 13 + servers/notion/src/apps/kanban-view/main.tsx | 46 ++ .../notion/src/apps/kanban-view/styles.css | 202 ++++++++ .../notion/src/apps/page-analytics/App.tsx | 122 +++++ .../notion/src/apps/page-analytics/index.html | 13 + .../notion/src/apps/page-analytics/main.tsx | 46 ++ .../notion/src/apps/page-analytics/styles.css | 246 ++++++++++ servers/notion/src/apps/page-browser/App.tsx | 131 +++++ .../notion/src/apps/page-browser/index.html | 13 + servers/notion/src/apps/page-browser/main.tsx | 46 ++ .../notion/src/apps/page-browser/styles.css | 266 ++++++++++ servers/notion/src/apps/page-creator/App.tsx | 155 ++++++ .../notion/src/apps/page-creator/index.html | 13 + servers/notion/src/apps/page-creator/main.tsx | 46 ++ .../notion/src/apps/page-creator/styles.css | 263 ++++++++++ .../notion/src/apps/search-dashboard/App.tsx | 141 ++++++ .../src/apps/search-dashboard/index.html | 13 + .../notion/src/apps/search-dashboard/main.tsx | 46 ++ .../src/apps/search-dashboard/styles.css | 244 ++++++++++ servers/notion/src/apps/table-view/App.tsx | 124 +++++ servers/notion/src/apps/table-view/index.html | 13 + servers/notion/src/apps/table-view/main.tsx | 46 ++ servers/notion/src/apps/table-view/styles.css | 217 +++++++++ .../notion/src/apps/template-gallery/App.tsx | 126 +++++ .../src/apps/template-gallery/index.html | 13 + .../notion/src/apps/template-gallery/main.tsx | 46 ++ .../src/apps/template-gallery/styles.css | 240 +++++++++ .../notion/src/apps/user-directory/App.tsx | 137 ++++++ .../notion/src/apps/user-directory/index.html | 13 + .../notion/src/apps/user-directory/main.tsx | 46 ++ .../notion/src/apps/user-directory/styles.css | 268 ++++++++++ .../src/apps/workspace-overview/App.tsx | 119 +++++ .../src/apps/workspace-overview/index.html | 13 + .../src/apps/workspace-overview/main.tsx | 46 ++ .../src/apps/workspace-overview/styles.css | 236 +++++++++ servers/xero/APPS_MANIFEST.md | 293 +++++++++++ servers/xero/bulk-generate.py | 185 +++++++ servers/xero/final-batch.py | 157 ++++++ servers/xero/generate-apps.sh | 12 + servers/xero/src/apps/aged-payables/App.tsx | 170 +++++++ .../xero/src/apps/aged-payables/index.html | 13 + servers/xero/src/apps/aged-payables/main.tsx | 61 +++ .../xero/src/apps/aged-payables/styles.css | 321 ++++++++++++ .../xero/src/apps/aged-receivables/App.tsx | 170 +++++++ .../xero/src/apps/aged-receivables/index.html | 13 + .../xero/src/apps/aged-receivables/main.tsx | 61 +++ .../xero/src/apps/aged-receivables/styles.css | 321 ++++++++++++ servers/xero/src/apps/balance-sheet/App.tsx | 184 +++++++ .../xero/src/apps/balance-sheet/index.html | 13 + servers/xero/src/apps/balance-sheet/main.tsx | 61 +++ .../xero/src/apps/balance-sheet/styles.css | 321 ++++++++++++ servers/xero/src/apps/bank-feed/App.tsx | 180 +++++++ servers/xero/src/apps/bank-feed/index.html | 13 + servers/xero/src/apps/bank-feed/main.tsx | 61 +++ servers/xero/src/apps/bank-feed/styles.css | 321 ++++++++++++ servers/xero/src/apps/bill-manager/App.tsx | 189 ++++++++ servers/xero/src/apps/bill-manager/index.html | 13 + servers/xero/src/apps/bill-manager/main.tsx | 61 +++ servers/xero/src/apps/bill-manager/styles.css | 316 ++++++++++++ .../xero/src/apps/chart-of-accounts/App.tsx | 188 ++++++++ .../src/apps/chart-of-accounts/index.html | 13 + .../xero/src/apps/chart-of-accounts/main.tsx | 61 +++ .../src/apps/chart-of-accounts/styles.css | 321 ++++++++++++ .../xero/src/apps/contact-directory/App.tsx | 182 +++++++ .../src/apps/contact-directory/index.html | 13 + .../xero/src/apps/contact-directory/main.tsx | 61 +++ .../src/apps/contact-directory/styles.css | 307 ++++++++++++ .../xero/src/apps/credit-note-manager/App.tsx | 183 +++++++ .../src/apps/credit-note-manager/index.html | 13 + .../src/apps/credit-note-manager/main.tsx | 61 +++ .../src/apps/credit-note-manager/styles.css | 321 ++++++++++++ .../xero/src/apps/employee-directory/App.tsx | 183 +++++++ .../src/apps/employee-directory/index.html | 13 + .../xero/src/apps/employee-directory/main.tsx | 61 +++ .../src/apps/employee-directory/styles.css | 321 ++++++++++++ .../xero/src/apps/invoice-dashboard/App.tsx | 190 ++++++++ .../src/apps/invoice-dashboard/index.html | 13 + .../xero/src/apps/invoice-dashboard/main.tsx | 61 +++ .../src/apps/invoice-dashboard/styles.css | 321 ++++++++++++ servers/xero/src/apps/org-overview/App.tsx | 189 ++++++++ servers/xero/src/apps/org-overview/index.html | 13 + servers/xero/src/apps/org-overview/main.tsx | 61 +++ servers/xero/src/apps/org-overview/styles.css | 321 ++++++++++++ servers/xero/src/apps/payment-tracker/App.tsx | 182 +++++++ .../xero/src/apps/payment-tracker/index.html | 13 + .../xero/src/apps/payment-tracker/main.tsx | 61 +++ .../xero/src/apps/payment-tracker/styles.css | 321 ++++++++++++ .../xero/src/apps/payroll-dashboard/App.tsx | 182 +++++++ .../src/apps/payroll-dashboard/index.html | 13 + .../xero/src/apps/payroll-dashboard/main.tsx | 61 +++ .../src/apps/payroll-dashboard/styles.css | 321 ++++++++++++ servers/xero/src/apps/profit-loss/App.tsx | 177 +++++++ servers/xero/src/apps/profit-loss/index.html | 13 + servers/xero/src/apps/profit-loss/main.tsx | 61 +++ servers/xero/src/apps/profit-loss/styles.css | 321 ++++++++++++ servers/xero/src/apps/purchase-orders/App.tsx | 180 +++++++ .../xero/src/apps/purchase-orders/index.html | 13 + .../xero/src/apps/purchase-orders/main.tsx | 61 +++ .../xero/src/apps/purchase-orders/styles.css | 321 ++++++++++++ servers/xero/src/apps/quote-builder/App.tsx | 183 +++++++ .../xero/src/apps/quote-builder/index.html | 13 + servers/xero/src/apps/quote-builder/main.tsx | 61 +++ .../xero/src/apps/quote-builder/styles.css | 321 ++++++++++++ servers/xero/src/apps/tax-center/App.tsx | 177 +++++++ servers/xero/src/apps/tax-center/index.html | 13 + servers/xero/src/apps/tax-center/main.tsx | 61 +++ servers/xero/src/apps/tax-center/styles.css | 321 ++++++++++++ servers/xero/src/apps/trial-balance/App.tsx | 166 +++++++ .../xero/src/apps/trial-balance/index.html | 13 + servers/xero/src/apps/trial-balance/main.tsx | 61 +++ .../xero/src/apps/trial-balance/styles.css | 321 ++++++++++++ 328 files changed, 39829 insertions(+) create mode 100644 servers/airtable/src/apps/automation-monitor/App.tsx create mode 100644 servers/airtable/src/apps/automation-monitor/index.html create mode 100644 servers/airtable/src/apps/automation-monitor/main.tsx create mode 100644 servers/airtable/src/apps/automation-monitor/styles.css create mode 100644 servers/airtable/src/apps/base-browser/App.tsx create mode 100644 servers/airtable/src/apps/base-browser/index.html create mode 100644 servers/airtable/src/apps/base-browser/main.tsx create mode 100644 servers/airtable/src/apps/base-browser/styles.css create mode 100644 servers/airtable/src/apps/dashboard/App.tsx create mode 100644 servers/airtable/src/apps/dashboard/index.html create mode 100644 servers/airtable/src/apps/dashboard/main.tsx create mode 100644 servers/airtable/src/apps/dashboard/styles.css create mode 100644 servers/airtable/src/apps/field-manager/App.tsx create mode 100644 servers/airtable/src/apps/field-manager/index.html create mode 100644 servers/airtable/src/apps/field-manager/main.tsx create mode 100644 servers/airtable/src/apps/field-manager/styles.css create mode 100644 servers/airtable/src/apps/form-builder/App.tsx create mode 100644 servers/airtable/src/apps/form-builder/index.html create mode 100644 servers/airtable/src/apps/form-builder/main.tsx create mode 100644 servers/airtable/src/apps/form-builder/styles.css create mode 100644 servers/airtable/src/apps/gallery-view/App.tsx create mode 100644 servers/airtable/src/apps/gallery-view/index.html create mode 100644 servers/airtable/src/apps/gallery-view/main.tsx create mode 100644 servers/airtable/src/apps/gallery-view/styles.css create mode 100644 servers/airtable/src/apps/grid-view/App.tsx create mode 100644 servers/airtable/src/apps/grid-view/index.html create mode 100644 servers/airtable/src/apps/grid-view/main.tsx create mode 100644 servers/airtable/src/apps/grid-view/styles.css create mode 100644 servers/airtable/src/apps/import-export/App.tsx create mode 100644 servers/airtable/src/apps/import-export/index.html create mode 100644 servers/airtable/src/apps/import-export/main.tsx create mode 100644 servers/airtable/src/apps/import-export/styles.css create mode 100644 servers/airtable/src/apps/kanban-board/App.tsx create mode 100644 servers/airtable/src/apps/kanban-board/index.html create mode 100644 servers/airtable/src/apps/kanban-board/main.tsx create mode 100644 servers/airtable/src/apps/kanban-board/styles.css create mode 100644 servers/airtable/src/apps/record-editor/App.tsx create mode 100644 servers/airtable/src/apps/record-editor/index.html create mode 100644 servers/airtable/src/apps/record-editor/main.tsx create mode 100644 servers/airtable/src/apps/record-editor/styles.css create mode 100644 servers/airtable/src/apps/schema-designer/App.tsx create mode 100644 servers/airtable/src/apps/schema-designer/index.html create mode 100644 servers/airtable/src/apps/schema-designer/main.tsx create mode 100644 servers/airtable/src/apps/schema-designer/styles.css create mode 100644 servers/airtable/src/apps/search-dashboard/App.tsx create mode 100644 servers/airtable/src/apps/search-dashboard/index.html create mode 100644 servers/airtable/src/apps/search-dashboard/main.tsx create mode 100644 servers/airtable/src/apps/search-dashboard/styles.css create mode 100644 servers/airtable/src/apps/table-viewer/App.tsx create mode 100644 servers/airtable/src/apps/table-viewer/index.html create mode 100644 servers/airtable/src/apps/table-viewer/main.tsx create mode 100644 servers/airtable/src/apps/table-viewer/styles.css create mode 100644 servers/airtable/src/apps/view-browser/App.tsx create mode 100644 servers/airtable/src/apps/view-browser/index.html create mode 100644 servers/airtable/src/apps/view-browser/main.tsx create mode 100644 servers/airtable/src/apps/view-browser/styles.css create mode 100644 servers/airtable/src/apps/webhook-manager/App.tsx create mode 100644 servers/airtable/src/apps/webhook-manager/index.html create mode 100644 servers/airtable/src/apps/webhook-manager/main.tsx create mode 100644 servers/airtable/src/apps/webhook-manager/styles.css create mode 100644 servers/intercom/src/apps/admin-panel/App.tsx create mode 100644 servers/intercom/src/apps/admin-panel/index.html create mode 100644 servers/intercom/src/apps/admin-panel/main.tsx create mode 100644 servers/intercom/src/apps/admin-panel/styles.css create mode 100644 servers/intercom/src/apps/article-editor/App.tsx create mode 100644 servers/intercom/src/apps/article-editor/index.html create mode 100644 servers/intercom/src/apps/article-editor/main.tsx create mode 100644 servers/intercom/src/apps/article-editor/styles.css create mode 100644 servers/intercom/src/apps/automation-center/App.tsx create mode 100644 servers/intercom/src/apps/automation-center/index.html create mode 100644 servers/intercom/src/apps/automation-center/main.tsx create mode 100644 servers/intercom/src/apps/automation-center/styles.css create mode 100644 servers/intercom/src/apps/collection-manager/App.tsx create mode 100644 servers/intercom/src/apps/collection-manager/index.html create mode 100644 servers/intercom/src/apps/collection-manager/main.tsx create mode 100644 servers/intercom/src/apps/collection-manager/styles.css create mode 100644 servers/intercom/src/apps/company-directory/App.tsx create mode 100644 servers/intercom/src/apps/company-directory/index.html create mode 100644 servers/intercom/src/apps/company-directory/main.tsx create mode 100644 servers/intercom/src/apps/company-directory/styles.css create mode 100644 servers/intercom/src/apps/contact-manager/App.tsx create mode 100644 servers/intercom/src/apps/contact-manager/index.html create mode 100644 servers/intercom/src/apps/contact-manager/main.tsx create mode 100644 servers/intercom/src/apps/contact-manager/styles.css create mode 100644 servers/intercom/src/apps/conversation-inbox/App.tsx create mode 100644 servers/intercom/src/apps/conversation-inbox/index.html create mode 100644 servers/intercom/src/apps/conversation-inbox/main.tsx create mode 100644 servers/intercom/src/apps/conversation-inbox/styles.css create mode 100644 servers/intercom/src/apps/customer-360/App.tsx create mode 100644 servers/intercom/src/apps/customer-360/index.html create mode 100644 servers/intercom/src/apps/customer-360/main.tsx create mode 100644 servers/intercom/src/apps/customer-360/styles.css create mode 100644 servers/intercom/src/apps/event-timeline/App.tsx create mode 100644 servers/intercom/src/apps/event-timeline/index.html create mode 100644 servers/intercom/src/apps/event-timeline/main.tsx create mode 100644 servers/intercom/src/apps/event-timeline/styles.css create mode 100644 servers/intercom/src/apps/message-composer/App.tsx create mode 100644 servers/intercom/src/apps/message-composer/index.html create mode 100644 servers/intercom/src/apps/message-composer/main.tsx create mode 100644 servers/intercom/src/apps/message-composer/styles.css create mode 100644 servers/intercom/src/apps/segment-viewer/App.tsx create mode 100644 servers/intercom/src/apps/segment-viewer/index.html create mode 100644 servers/intercom/src/apps/segment-viewer/main.tsx create mode 100644 servers/intercom/src/apps/segment-viewer/styles.css create mode 100644 servers/intercom/src/apps/sla-monitor/App.tsx create mode 100644 servers/intercom/src/apps/sla-monitor/index.html create mode 100644 servers/intercom/src/apps/sla-monitor/main.tsx create mode 100644 servers/intercom/src/apps/sla-monitor/styles.css create mode 100644 servers/intercom/src/apps/support-analytics/App.tsx create mode 100644 servers/intercom/src/apps/support-analytics/index.html create mode 100644 servers/intercom/src/apps/support-analytics/main.tsx create mode 100644 servers/intercom/src/apps/support-analytics/styles.css create mode 100644 servers/intercom/src/apps/tag-manager/App.tsx create mode 100644 servers/intercom/src/apps/tag-manager/index.html create mode 100644 servers/intercom/src/apps/tag-manager/main.tsx create mode 100644 servers/intercom/src/apps/tag-manager/styles.css create mode 100644 servers/intercom/src/apps/team-dashboard/App.tsx create mode 100644 servers/intercom/src/apps/team-dashboard/index.html create mode 100644 servers/intercom/src/apps/team-dashboard/main.tsx create mode 100644 servers/intercom/src/apps/team-dashboard/styles.css create mode 100644 servers/intercom/src/apps/ticket-center/App.tsx create mode 100644 servers/intercom/src/apps/ticket-center/index.html create mode 100644 servers/intercom/src/apps/ticket-center/main.tsx create mode 100644 servers/intercom/src/apps/ticket-center/styles.css create mode 100644 servers/monday/src/apps/README.md create mode 100644 servers/monday/src/apps/activity-log/App.tsx create mode 100644 servers/monday/src/apps/activity-log/index.html create mode 100644 servers/monday/src/apps/activity-log/main.tsx create mode 100644 servers/monday/src/apps/activity-log/styles.css create mode 100644 servers/monday/src/apps/automation-dashboard/App.tsx create mode 100644 servers/monday/src/apps/automation-dashboard/index.html create mode 100644 servers/monday/src/apps/automation-dashboard/main.tsx create mode 100644 servers/monday/src/apps/automation-dashboard/styles.css create mode 100644 servers/monday/src/apps/board-browser/App.tsx create mode 100644 servers/monday/src/apps/board-browser/index.html create mode 100644 servers/monday/src/apps/board-browser/main.tsx create mode 100644 servers/monday/src/apps/board-browser/styles.css create mode 100644 servers/monday/src/apps/column-configurator/App.tsx create mode 100644 servers/monday/src/apps/column-configurator/index.html create mode 100644 servers/monday/src/apps/column-configurator/main.tsx create mode 100644 servers/monday/src/apps/column-configurator/styles.css create mode 100644 servers/monday/src/apps/dashboard-builder/App.tsx create mode 100644 servers/monday/src/apps/dashboard-builder/index.html create mode 100644 servers/monday/src/apps/dashboard-builder/main.tsx create mode 100644 servers/monday/src/apps/dashboard-builder/styles.css create mode 100644 servers/monday/src/apps/folder-browser/App.tsx create mode 100644 servers/monday/src/apps/folder-browser/index.html create mode 100644 servers/monday/src/apps/folder-browser/main.tsx create mode 100644 servers/monday/src/apps/folder-browser/styles.css create mode 100644 servers/monday/src/apps/group-manager/App.tsx create mode 100644 servers/monday/src/apps/group-manager/index.html create mode 100644 servers/monday/src/apps/group-manager/main.tsx create mode 100644 servers/monday/src/apps/group-manager/styles.css create mode 100644 servers/monday/src/apps/item-manager/App.tsx create mode 100644 servers/monday/src/apps/item-manager/index.html create mode 100644 servers/monday/src/apps/item-manager/main.tsx create mode 100644 servers/monday/src/apps/item-manager/styles.css create mode 100644 servers/monday/src/apps/kanban-view/App.tsx create mode 100644 servers/monday/src/apps/kanban-view/index.html create mode 100644 servers/monday/src/apps/kanban-view/main.tsx create mode 100644 servers/monday/src/apps/kanban-view/styles.css create mode 100644 servers/monday/src/apps/resource-planner/App.tsx create mode 100644 servers/monday/src/apps/resource-planner/index.html create mode 100644 servers/monday/src/apps/resource-planner/main.tsx create mode 100644 servers/monday/src/apps/resource-planner/styles.css create mode 100644 servers/monday/src/apps/team-dashboard/App.tsx create mode 100644 servers/monday/src/apps/team-dashboard/index.html create mode 100644 servers/monday/src/apps/team-dashboard/main.tsx create mode 100644 servers/monday/src/apps/team-dashboard/styles.css create mode 100644 servers/monday/src/apps/timeline-view/App.tsx create mode 100644 servers/monday/src/apps/timeline-view/index.html create mode 100644 servers/monday/src/apps/timeline-view/main.tsx create mode 100644 servers/monday/src/apps/timeline-view/styles.css create mode 100644 servers/monday/src/apps/update-feed/App.tsx create mode 100644 servers/monday/src/apps/update-feed/index.html create mode 100644 servers/monday/src/apps/update-feed/main.tsx create mode 100644 servers/monday/src/apps/update-feed/styles.css create mode 100644 servers/monday/src/apps/user-directory/App.tsx create mode 100644 servers/monday/src/apps/user-directory/index.html create mode 100644 servers/monday/src/apps/user-directory/main.tsx create mode 100644 servers/monday/src/apps/user-directory/styles.css create mode 100644 servers/monday/src/apps/webhook-manager/App.tsx create mode 100644 servers/monday/src/apps/webhook-manager/index.html create mode 100644 servers/monday/src/apps/webhook-manager/main.tsx create mode 100644 servers/monday/src/apps/webhook-manager/styles.css create mode 100644 servers/monday/src/apps/workspace-overview/App.tsx create mode 100644 servers/monday/src/apps/workspace-overview/index.html create mode 100644 servers/monday/src/apps/workspace-overview/main.tsx create mode 100644 servers/monday/src/apps/workspace-overview/styles.css create mode 100644 servers/notion/APPS_COMPLETE.md create mode 100644 servers/notion/src/apps/README.md create mode 100644 servers/notion/src/apps/block-editor/App.tsx create mode 100644 servers/notion/src/apps/block-editor/index.html create mode 100644 servers/notion/src/apps/block-editor/main.tsx create mode 100644 servers/notion/src/apps/block-editor/styles.css create mode 100644 servers/notion/src/apps/calendar-view/App.tsx create mode 100644 servers/notion/src/apps/calendar-view/index.html create mode 100644 servers/notion/src/apps/calendar-view/main.tsx create mode 100644 servers/notion/src/apps/calendar-view/styles.css create mode 100644 servers/notion/src/apps/comment-viewer/App.tsx create mode 100644 servers/notion/src/apps/comment-viewer/index.html create mode 100644 servers/notion/src/apps/comment-viewer/main.tsx create mode 100644 servers/notion/src/apps/comment-viewer/styles.css create mode 100644 servers/notion/src/apps/database-builder/App.tsx create mode 100644 servers/notion/src/apps/database-builder/index.html create mode 100644 servers/notion/src/apps/database-builder/main.tsx create mode 100644 servers/notion/src/apps/database-builder/styles.css create mode 100644 servers/notion/src/apps/database-explorer/App.tsx create mode 100644 servers/notion/src/apps/database-explorer/index.html create mode 100644 servers/notion/src/apps/database-explorer/main.tsx create mode 100644 servers/notion/src/apps/database-explorer/styles.css create mode 100644 servers/notion/src/apps/integration-status/App.tsx create mode 100644 servers/notion/src/apps/integration-status/index.html create mode 100644 servers/notion/src/apps/integration-status/main.tsx create mode 100644 servers/notion/src/apps/integration-status/styles.css create mode 100644 servers/notion/src/apps/kanban-view/App.tsx create mode 100644 servers/notion/src/apps/kanban-view/index.html create mode 100644 servers/notion/src/apps/kanban-view/main.tsx create mode 100644 servers/notion/src/apps/kanban-view/styles.css create mode 100644 servers/notion/src/apps/page-analytics/App.tsx create mode 100644 servers/notion/src/apps/page-analytics/index.html create mode 100644 servers/notion/src/apps/page-analytics/main.tsx create mode 100644 servers/notion/src/apps/page-analytics/styles.css create mode 100644 servers/notion/src/apps/page-browser/App.tsx create mode 100644 servers/notion/src/apps/page-browser/index.html create mode 100644 servers/notion/src/apps/page-browser/main.tsx create mode 100644 servers/notion/src/apps/page-browser/styles.css create mode 100644 servers/notion/src/apps/page-creator/App.tsx create mode 100644 servers/notion/src/apps/page-creator/index.html create mode 100644 servers/notion/src/apps/page-creator/main.tsx create mode 100644 servers/notion/src/apps/page-creator/styles.css create mode 100644 servers/notion/src/apps/search-dashboard/App.tsx create mode 100644 servers/notion/src/apps/search-dashboard/index.html create mode 100644 servers/notion/src/apps/search-dashboard/main.tsx create mode 100644 servers/notion/src/apps/search-dashboard/styles.css create mode 100644 servers/notion/src/apps/table-view/App.tsx create mode 100644 servers/notion/src/apps/table-view/index.html create mode 100644 servers/notion/src/apps/table-view/main.tsx create mode 100644 servers/notion/src/apps/table-view/styles.css create mode 100644 servers/notion/src/apps/template-gallery/App.tsx create mode 100644 servers/notion/src/apps/template-gallery/index.html create mode 100644 servers/notion/src/apps/template-gallery/main.tsx create mode 100644 servers/notion/src/apps/template-gallery/styles.css create mode 100644 servers/notion/src/apps/user-directory/App.tsx create mode 100644 servers/notion/src/apps/user-directory/index.html create mode 100644 servers/notion/src/apps/user-directory/main.tsx create mode 100644 servers/notion/src/apps/user-directory/styles.css create mode 100644 servers/notion/src/apps/workspace-overview/App.tsx create mode 100644 servers/notion/src/apps/workspace-overview/index.html create mode 100644 servers/notion/src/apps/workspace-overview/main.tsx create mode 100644 servers/notion/src/apps/workspace-overview/styles.css create mode 100644 servers/xero/APPS_MANIFEST.md create mode 100644 servers/xero/bulk-generate.py create mode 100644 servers/xero/final-batch.py create mode 100755 servers/xero/generate-apps.sh create mode 100644 servers/xero/src/apps/aged-payables/App.tsx create mode 100644 servers/xero/src/apps/aged-payables/index.html create mode 100644 servers/xero/src/apps/aged-payables/main.tsx create mode 100644 servers/xero/src/apps/aged-payables/styles.css create mode 100644 servers/xero/src/apps/aged-receivables/App.tsx create mode 100644 servers/xero/src/apps/aged-receivables/index.html create mode 100644 servers/xero/src/apps/aged-receivables/main.tsx create mode 100644 servers/xero/src/apps/aged-receivables/styles.css create mode 100644 servers/xero/src/apps/balance-sheet/App.tsx create mode 100644 servers/xero/src/apps/balance-sheet/index.html create mode 100644 servers/xero/src/apps/balance-sheet/main.tsx create mode 100644 servers/xero/src/apps/balance-sheet/styles.css create mode 100644 servers/xero/src/apps/bank-feed/App.tsx create mode 100644 servers/xero/src/apps/bank-feed/index.html create mode 100644 servers/xero/src/apps/bank-feed/main.tsx create mode 100644 servers/xero/src/apps/bank-feed/styles.css create mode 100644 servers/xero/src/apps/bill-manager/App.tsx create mode 100644 servers/xero/src/apps/bill-manager/index.html create mode 100644 servers/xero/src/apps/bill-manager/main.tsx create mode 100644 servers/xero/src/apps/bill-manager/styles.css create mode 100644 servers/xero/src/apps/chart-of-accounts/App.tsx create mode 100644 servers/xero/src/apps/chart-of-accounts/index.html create mode 100644 servers/xero/src/apps/chart-of-accounts/main.tsx create mode 100644 servers/xero/src/apps/chart-of-accounts/styles.css create mode 100644 servers/xero/src/apps/contact-directory/App.tsx create mode 100644 servers/xero/src/apps/contact-directory/index.html create mode 100644 servers/xero/src/apps/contact-directory/main.tsx create mode 100644 servers/xero/src/apps/contact-directory/styles.css create mode 100644 servers/xero/src/apps/credit-note-manager/App.tsx create mode 100644 servers/xero/src/apps/credit-note-manager/index.html create mode 100644 servers/xero/src/apps/credit-note-manager/main.tsx create mode 100644 servers/xero/src/apps/credit-note-manager/styles.css create mode 100644 servers/xero/src/apps/employee-directory/App.tsx create mode 100644 servers/xero/src/apps/employee-directory/index.html create mode 100644 servers/xero/src/apps/employee-directory/main.tsx create mode 100644 servers/xero/src/apps/employee-directory/styles.css create mode 100644 servers/xero/src/apps/invoice-dashboard/App.tsx create mode 100644 servers/xero/src/apps/invoice-dashboard/index.html create mode 100644 servers/xero/src/apps/invoice-dashboard/main.tsx create mode 100644 servers/xero/src/apps/invoice-dashboard/styles.css create mode 100644 servers/xero/src/apps/org-overview/App.tsx create mode 100644 servers/xero/src/apps/org-overview/index.html create mode 100644 servers/xero/src/apps/org-overview/main.tsx create mode 100644 servers/xero/src/apps/org-overview/styles.css create mode 100644 servers/xero/src/apps/payment-tracker/App.tsx create mode 100644 servers/xero/src/apps/payment-tracker/index.html create mode 100644 servers/xero/src/apps/payment-tracker/main.tsx create mode 100644 servers/xero/src/apps/payment-tracker/styles.css create mode 100644 servers/xero/src/apps/payroll-dashboard/App.tsx create mode 100644 servers/xero/src/apps/payroll-dashboard/index.html create mode 100644 servers/xero/src/apps/payroll-dashboard/main.tsx create mode 100644 servers/xero/src/apps/payroll-dashboard/styles.css create mode 100644 servers/xero/src/apps/profit-loss/App.tsx create mode 100644 servers/xero/src/apps/profit-loss/index.html create mode 100644 servers/xero/src/apps/profit-loss/main.tsx create mode 100644 servers/xero/src/apps/profit-loss/styles.css create mode 100644 servers/xero/src/apps/purchase-orders/App.tsx create mode 100644 servers/xero/src/apps/purchase-orders/index.html create mode 100644 servers/xero/src/apps/purchase-orders/main.tsx create mode 100644 servers/xero/src/apps/purchase-orders/styles.css create mode 100644 servers/xero/src/apps/quote-builder/App.tsx create mode 100644 servers/xero/src/apps/quote-builder/index.html create mode 100644 servers/xero/src/apps/quote-builder/main.tsx create mode 100644 servers/xero/src/apps/quote-builder/styles.css create mode 100644 servers/xero/src/apps/tax-center/App.tsx create mode 100644 servers/xero/src/apps/tax-center/index.html create mode 100644 servers/xero/src/apps/tax-center/main.tsx create mode 100644 servers/xero/src/apps/tax-center/styles.css create mode 100644 servers/xero/src/apps/trial-balance/App.tsx create mode 100644 servers/xero/src/apps/trial-balance/index.html create mode 100644 servers/xero/src/apps/trial-balance/main.tsx create mode 100644 servers/xero/src/apps/trial-balance/styles.css diff --git a/servers/airtable/src/apps/automation-monitor/App.tsx b/servers/airtable/src/apps/automation-monitor/App.tsx new file mode 100644 index 0000000..4086345 --- /dev/null +++ b/servers/airtable/src/apps/automation-monitor/App.tsx @@ -0,0 +1 @@ +import React,{useState,useMemo,useTransition,useCallback}from'react';const useDebounce=(value:T,delay:number=300):T=>{const[debouncedValue,setDebouncedValue]=useState(value);React.useEffect(()=>{const handler=setTimeout(()=>setDebouncedValue(value),delay);return()=>clearTimeout(handler)},[value,delay]);return debouncedValue};const useToast=()=>{const[toasts,setToasts]=useState>([]);const showToast=useCallback((message:string,type:string='info')=>{const id=Date.now();setToasts(prev=>[...prev,{id,message,type}]);setTimeout(()=>setToasts(prev=>prev.filter(t=>t.id!==id)),3000)},[]);return{toasts,showToast}};interface AutomationRun{id:string;name:string;status:string;trigger:string;actions:number;runTime:string;duration:number}const mockRuns:AutomationRun[]=[{id:'run1',name:'Send Welcome Email',status:'success',trigger:'Record created',actions:3,runTime:'2024-02-13 10:30',duration:2.5},{id:'run2',name:'Update Slack Channel',status:'success',trigger:'Field updated',actions:2,runTime:'2024-02-13 09:15',duration:1.2},{id:'run3',name:'Create Task in Asana',status:'failed',trigger:'Record created',actions:4,runTime:'2024-02-12 16:45',duration:0.8},{id:'run4',name:'Sync to Google Sheets',status:'success',trigger:'View updated',actions:1,runTime:'2024-02-12 14:20',duration:3.1}];const App:React.FC=()=>{const[searchQuery,setSearchQuery]=useState('');const[selectedRun,setSelectedRun]=useState(null);const[isPending,startTransition]=useTransition();const{toasts,showToast}=useToast();const debouncedSearch=useDebounce(searchQuery,300);const filteredRuns=useMemo(()=>{return mockRuns.filter(run=>run.name.toLowerCase().includes(debouncedSearch.toLowerCase())||run.trigger.toLowerCase().includes(debouncedSearch.toLowerCase()))},[debouncedSearch]);const stats=useMemo(()=>({total:mockRuns.length,success:mockRuns.filter(r=>r.status==='success').length,failed:mockRuns.filter(r=>r.status==='failed').length}),[]);const handleRunClick=(run:AutomationRun)=>{startTransition(()=>{setSelectedRun(run);showToast(`Viewing: ${run.name}`,'info')})};return(

Automation Monitor

View automation runs

{stats.total}
Total Runs
{stats.success}
Successful
{stats.failed}
Failed
setSearchQuery(e.target.value)} className="search-input"/>
{filteredRuns.length===0?(
⚙️

No runs found

Try adjusting your search query

):(
{filteredRuns.map(run=>(
handleRunClick(run)}>

{run.name}

{run.status}
Trigger:{run.trigger}
Actions:{run.actions}
Duration:{run.duration}s
Run Time:{run.runTime}
))}
)}{selectedRun&&(

{selectedRun.name}

Status: {selectedRun.status}

Trigger: {selectedRun.trigger}

Actions: {selectedRun.actions}

Duration: {selectedRun.duration}s

Run Time: {selectedRun.runTime}

)}
{toasts.map(toast=>(
{toast.message}
))}
)};export default App; \ No newline at end of file diff --git a/servers/airtable/src/apps/automation-monitor/index.html b/servers/airtable/src/apps/automation-monitor/index.html new file mode 100644 index 0000000..3fc8fff --- /dev/null +++ b/servers/airtable/src/apps/automation-monitor/index.html @@ -0,0 +1,12 @@ + + + + + + Airtable Automation Monitor + + +
+ + + diff --git a/servers/airtable/src/apps/automation-monitor/main.tsx b/servers/airtable/src/apps/automation-monitor/main.tsx new file mode 100644 index 0000000..5b258cd --- /dev/null +++ b/servers/airtable/src/apps/automation-monitor/main.tsx @@ -0,0 +1 @@ +import React,{lazy,Suspense}from'react';import{createRoot}from'react-dom/client';import'./styles.css';const App=lazy(()=>import('./App'));class ErrorBoundary extends React.Component<{children:React.ReactNode},{hasError:boolean;error?:Error}>{constructor(props:{children:React.ReactNode}){super(props);this.state={hasError:false}}static getDerivedStateFromError(error:Error){return{hasError:true,error}}componentDidCatch(error:Error,errorInfo:React.ErrorInfo){console.error('ErrorBoundary caught:',error,errorInfo)}render(){if(this.state.hasError){return(

Something went wrong

{this.state.error?.message}

)}return this.props.children}}const LoadingSkeleton=()=>(
);const root=createRoot(document.getElementById('root')!);root.render(}>); \ No newline at end of file diff --git a/servers/airtable/src/apps/automation-monitor/styles.css b/servers/airtable/src/apps/automation-monitor/styles.css new file mode 100644 index 0000000..c3a77cd --- /dev/null +++ b/servers/airtable/src/apps/automation-monitor/styles.css @@ -0,0 +1 @@ +:root{--bg-primary:#0f172a;--bg-secondary:#1e293b;--bg-tertiary:#334155;--text-primary:#f1f5f9;--text-secondary:#cbd5e1;--text-muted:#94a3b8;--accent:#3b82f6;--accent-hover:#2563eb;--success:#10b981;--warning:#f59e0b;--error:#ef4444;--border:#334155;--shadow:rgba(0,0,0,0.3)}*{margin:0;padding:0;box-sizing:border-box}body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;background:var(--bg-primary);color:var(--text-primary);line-height:1.6}#root{min-height:100vh}.app-container{max-width:1200px;margin:0 auto;padding:2rem}.app-header{margin-bottom:2rem}.app-header h1{font-size:2rem;font-weight:700;margin-bottom:0.5rem}.subtitle{color:var(--text-secondary);font-size:1rem}.stats-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:1rem;margin-bottom:2rem}.stat-card{background:var(--bg-secondary);padding:1.5rem;border-radius:0.75rem;border:1px solid var(--border);transition:transform 0.2s,box-shadow 0.2s}.stat-card:hover{transform:translateY(-2px);box-shadow:0 4px 12px var(--shadow)}.stat-value{font-size:2.5rem;font-weight:700;color:var(--accent)}.stat-label{color:var(--text-secondary);font-size:0.875rem;margin-top:0.5rem}.search-container{margin-bottom:2rem}.search-input{width:100%;padding:0.875rem 1rem;background:var(--bg-secondary);border:1px solid var(--border);border-radius:0.5rem;color:var(--text-primary);font-size:1rem;transition:border-color 0.2s}.search-input:focus{outline:none;border-color:var(--accent)}.runs-list{display:flex;flex-direction:column;gap:1rem;margin-bottom:2rem}.run-card{background:var(--bg-secondary);border:1px solid var(--border);border-radius:0.75rem;padding:1.5rem;cursor:pointer;transition:transform 0.2s,box-shadow 0.2s,border-color 0.2s}.run-card:hover{transform:translateY(-2px);box-shadow:0 8px 16px var(--shadow);border-color:var(--accent)}.run-header{display:flex;justify-content:space-between;align-items:start;margin-bottom:1rem}.run-header h3{font-size:1.125rem;font-weight:600;color:var(--text-primary)}.badge{padding:0.25rem 0.75rem;border-radius:1rem;font-size:0.75rem;font-weight:600;text-transform:uppercase}.badge-success{background:rgba(16,185,129,0.2);color:var(--success)}.badge-failed{background:rgba(239,68,68,0.2);color:var(--error)}.run-body{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:0.75rem}.run-stat{display:flex;flex-direction:column;gap:0.25rem;font-size:0.875rem}.run-stat .label{color:var(--text-secondary)}.run-stat .value{color:var(--text-primary);font-weight:500}.detail-panel{background:var(--bg-secondary);border:1px solid var(--border);border-radius:0.75rem;padding:1.5rem;margin-top:2rem}.detail-panel h2{font-size:1.5rem;margin-bottom:1rem}.empty-state{text-align:center;padding:4rem 2rem}.empty-icon{font-size:4rem;margin-bottom:1rem}.empty-state h3{font-size:1.5rem;margin-bottom:0.5rem}.empty-state p{color:var(--text-secondary)}.toast-container{position:fixed;top:1rem;right:1rem;z-index:1000;display:flex;flex-direction:column;gap:0.5rem}.toast{background:var(--bg-secondary);border:1px solid var(--border);border-radius:0.5rem;padding:1rem 1.5rem;min-width:250px;box-shadow:0 4px 12px var(--shadow);animation:slideIn 0.3s ease-out}.toast-success{border-left:4px solid var(--success)}.toast-error{border-left:4px solid var(--error)}.toast-info{border-left:4px solid var(--accent)}@keyframes slideIn{from{transform:translateX(100%);opacity:0}to{transform:translateX(0);opacity:1}}.shimmer{background:linear-gradient(90deg,var(--bg-secondary) 0%,var(--bg-tertiary) 50%,var(--bg-secondary) 100%);background-size:200% 100%;animation:shimmer 1.5s infinite}@keyframes shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}.loading-skeleton{padding:2rem}.skeleton-header{height:3rem;border-radius:0.5rem;margin-bottom:2rem}.skeleton-content{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:1rem}.skeleton-card{height:150px;border-radius:0.75rem}.error-boundary{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh;padding:2rem;text-align:center}.error-boundary h1{font-size:2rem;margin-bottom:1rem;color:var(--error)}.error-boundary button{margin-top:1rem;padding:0.75rem 1.5rem;background:var(--accent);color:white;border:none;border-radius:0.5rem;cursor:pointer;font-size:1rem;transition:background 0.2s}.error-boundary button:hover{background:var(--accent-hover)}@media (max-width:768px){.app-container{padding:1rem}.stats-grid{grid-template-columns:1fr}.app-header h1{font-size:1.5rem}.run-body{grid-template-columns:1fr}} \ No newline at end of file diff --git a/servers/airtable/src/apps/base-browser/App.tsx b/servers/airtable/src/apps/base-browser/App.tsx new file mode 100644 index 0000000..77fb44e --- /dev/null +++ b/servers/airtable/src/apps/base-browser/App.tsx @@ -0,0 +1,156 @@ +import React, { useState, useMemo, useTransition, useCallback } from 'react'; + +const useDebounce = (value: T, delay: number = 300): T => { + const [debouncedValue, setDebouncedValue] = useState(value); + + React.useEffect(() => { + const handler = setTimeout(() => setDebouncedValue(value), delay); + return () => clearTimeout(handler); + }, [value, delay]); + + return debouncedValue; +}; + +const useToast = () => { + const [toasts, setToasts] = useState>([]); + + const showToast = useCallback((message: string, type: string = 'info') => { + const id = Date.now(); + setToasts(prev => [...prev, { id, message, type }]); + setTimeout(() => setToasts(prev => prev.filter(t => t.id !== id)), 3000); + }, []); + + return { toasts, showToast }; +}; + +interface Base { + id: string; + name: string; + permissionLevel: string; + tables: number; + lastModified: string; +} + +const mockBases: Base[] = [ + { id: 'app1', name: 'Marketing Hub', permissionLevel: 'owner', tables: 12, lastModified: '2024-02-10' }, + { id: 'app2', name: 'Sales CRM', permissionLevel: 'editor', tables: 8, lastModified: '2024-02-12' }, + { id: 'app3', name: 'Product Roadmap', permissionLevel: 'owner', tables: 5, lastModified: '2024-02-13' }, + { id: 'app4', name: 'HR Operations', permissionLevel: 'viewer', tables: 15, lastModified: '2024-02-11' }, + { id: 'app5', name: 'Content Calendar', permissionLevel: 'editor', tables: 6, lastModified: '2024-02-09' }, +]; + +const App: React.FC = () => { + const [searchQuery, setSearchQuery] = useState(''); + const [selectedBase, setSelectedBase] = useState(null); + const [isPending, startTransition] = useTransition(); + const { toasts, showToast } = useToast(); + + const debouncedSearch = useDebounce(searchQuery, 300); + + const filteredBases = useMemo(() => { + return mockBases.filter(base => + base.name.toLowerCase().includes(debouncedSearch.toLowerCase()) + ); + }, [debouncedSearch]); + + const stats = useMemo(() => ({ + total: mockBases.length, + owned: mockBases.filter(b => b.permissionLevel === 'owner').length, + shared: mockBases.filter(b => b.permissionLevel !== 'owner').length, + }), []); + + const handleBaseClick = (base: Base) => { + startTransition(() => { + setSelectedBase(base); + showToast(`Opened base: ${base.name}`, 'success'); + }); + }; + + return ( +
+
+

Airtable Base Browser

+

Browse and manage your Airtable bases

+
+ +
+
+
{stats.total}
+
Total Bases
+
+
+
{stats.owned}
+
Owned
+
+
+
{stats.shared}
+
Shared
+
+
+ +
+ setSearchQuery(e.target.value)} + className="search-input" + /> +
+ + {filteredBases.length === 0 ? ( +
+
📦
+

No bases found

+

Try adjusting your search query

+
+ ) : ( +
+ {filteredBases.map(base => ( +
handleBaseClick(base)} + > +
+

{base.name}

+ + {base.permissionLevel} + +
+
+
+ Tables: + {base.tables} +
+
+ Last Modified: + {base.lastModified} +
+
+
+ ))} +
+ )} + + {selectedBase && ( +
+

Base Details: {selectedBase.name}

+

ID: {selectedBase.id}

+

Permission: {selectedBase.permissionLevel}

+

Tables: {selectedBase.tables}

+
+ )} + +
+ {toasts.map(toast => ( +
+ {toast.message} +
+ ))} +
+
+ ); +}; + +export default App; diff --git a/servers/airtable/src/apps/base-browser/index.html b/servers/airtable/src/apps/base-browser/index.html new file mode 100644 index 0000000..2b51e4d --- /dev/null +++ b/servers/airtable/src/apps/base-browser/index.html @@ -0,0 +1,12 @@ + + + + + + Airtable Base Browser + + +
+ + + diff --git a/servers/airtable/src/apps/base-browser/main.tsx b/servers/airtable/src/apps/base-browser/main.tsx new file mode 100644 index 0000000..22b087f --- /dev/null +++ b/servers/airtable/src/apps/base-browser/main.tsx @@ -0,0 +1,58 @@ +import React, { lazy, Suspense } from 'react'; +import { createRoot } from 'react-dom/client'; +import './styles.css'; + +const App = lazy(() => import('./App')); + +class ErrorBoundary extends React.Component< + { children: React.ReactNode }, + { hasError: boolean; error?: Error } +> { + constructor(props: { children: React.ReactNode }) { + super(props); + this.state = { hasError: false }; + } + + static getDerivedStateFromError(error: Error) { + return { hasError: true, error }; + } + + componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { + console.error('ErrorBoundary caught:', error, errorInfo); + } + + render() { + if (this.state.hasError) { + return ( +
+

Something went wrong

+

{this.state.error?.message}

+ +
+ ); + } + return this.props.children; + } +} + +const LoadingSkeleton = () => ( +
+
+
+
+
+
+
+
+); + +const root = createRoot(document.getElementById('root')!); +root.render( + + + }> + + + + +); diff --git a/servers/airtable/src/apps/base-browser/styles.css b/servers/airtable/src/apps/base-browser/styles.css new file mode 100644 index 0000000..6282190 --- /dev/null +++ b/servers/airtable/src/apps/base-browser/styles.css @@ -0,0 +1,350 @@ +:root { + --bg-primary: #0f172a; + --bg-secondary: #1e293b; + --bg-tertiary: #334155; + --text-primary: #f1f5f9; + --text-secondary: #cbd5e1; + --text-muted: #94a3b8; + --accent: #3b82f6; + --accent-hover: #2563eb; + --success: #10b981; + --warning: #f59e0b; + --error: #ef4444; + --border: #334155; + --shadow: rgba(0, 0, 0, 0.3); +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; + background: var(--bg-primary); + color: var(--text-primary); + line-height: 1.6; +} + +#root { + min-height: 100vh; +} + +.app-container { + max-width: 1400px; + margin: 0 auto; + padding: 2rem; +} + +.app-header { + margin-bottom: 2rem; +} + +.app-header h1 { + font-size: 2rem; + font-weight: 700; + margin-bottom: 0.5rem; +} + +.subtitle { + color: var(--text-secondary); + font-size: 1rem; +} + +.stats-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 1rem; + margin-bottom: 2rem; +} + +.stat-card { + background: var(--bg-secondary); + padding: 1.5rem; + border-radius: 0.75rem; + border: 1px solid var(--border); + transition: transform 0.2s, box-shadow 0.2s; +} + +.stat-card:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px var(--shadow); +} + +.stat-value { + font-size: 2.5rem; + font-weight: 700; + color: var(--accent); +} + +.stat-label { + color: var(--text-secondary); + font-size: 0.875rem; + margin-top: 0.5rem; +} + +.search-container { + margin-bottom: 2rem; +} + +.search-input { + width: 100%; + padding: 0.875rem 1rem; + background: var(--bg-secondary); + border: 1px solid var(--border); + border-radius: 0.5rem; + color: var(--text-primary); + font-size: 1rem; + transition: border-color 0.2s; +} + +.search-input:focus { + outline: none; + border-color: var(--accent); +} + +.data-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); + gap: 1rem; + margin-bottom: 2rem; +} + +.data-card { + background: var(--bg-secondary); + border: 1px solid var(--border); + border-radius: 0.75rem; + padding: 1.5rem; + cursor: pointer; + transition: transform 0.2s, box-shadow 0.2s, border-color 0.2s; +} + +.data-card:hover { + transform: translateY(-2px); + box-shadow: 0 8px 16px var(--shadow); + border-color: var(--accent); +} + +.card-header { + display: flex; + justify-content: space-between; + align-items: start; + margin-bottom: 1rem; +} + +.card-header h3 { + font-size: 1.125rem; + font-weight: 600; + color: var(--text-primary); +} + +.badge { + padding: 0.25rem 0.75rem; + border-radius: 1rem; + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; +} + +.badge-owner { + background: rgba(16, 185, 129, 0.2); + color: var(--success); +} + +.badge-editor { + background: rgba(59, 130, 246, 0.2); + color: var(--accent); +} + +.badge-viewer { + background: rgba(148, 163, 184, 0.2); + color: var(--text-muted); +} + +.card-body { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.card-stat { + display: flex; + justify-content: space-between; + font-size: 0.875rem; +} + +.card-stat .label { + color: var(--text-secondary); +} + +.card-stat .value { + color: var(--text-primary); + font-weight: 500; +} + +.detail-panel { + background: var(--bg-secondary); + border: 1px solid var(--border); + border-radius: 0.75rem; + padding: 1.5rem; + margin-top: 2rem; +} + +.detail-panel h2 { + font-size: 1.5rem; + margin-bottom: 1rem; +} + +.empty-state { + text-align: center; + padding: 4rem 2rem; +} + +.empty-icon { + font-size: 4rem; + margin-bottom: 1rem; +} + +.empty-state h3 { + font-size: 1.5rem; + margin-bottom: 0.5rem; +} + +.empty-state p { + color: var(--text-secondary); +} + +.toast-container { + position: fixed; + top: 1rem; + right: 1rem; + z-index: 1000; + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.toast { + background: var(--bg-secondary); + border: 1px solid var(--border); + border-radius: 0.5rem; + padding: 1rem 1.5rem; + min-width: 250px; + box-shadow: 0 4px 12px var(--shadow); + animation: slideIn 0.3s ease-out; +} + +.toast-success { + border-left: 4px solid var(--success); +} + +.toast-error { + border-left: 4px solid var(--error); +} + +.toast-info { + border-left: 4px solid var(--accent); +} + +@keyframes slideIn { + from { + transform: translateX(100%); + opacity: 0; + } + to { + transform: translateX(0); + opacity: 1; + } +} + +.shimmer { + background: linear-gradient( + 90deg, + var(--bg-secondary) 0%, + var(--bg-tertiary) 50%, + var(--bg-secondary) 100% + ); + background-size: 200% 100%; + animation: shimmer 1.5s infinite; +} + +@keyframes shimmer { + 0% { + background-position: 200% 0; + } + 100% { + background-position: -200% 0; + } +} + +.loading-skeleton { + padding: 2rem; +} + +.skeleton-header { + height: 3rem; + border-radius: 0.5rem; + margin-bottom: 2rem; +} + +.skeleton-content { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); + gap: 1rem; +} + +.skeleton-card { + height: 150px; + border-radius: 0.75rem; +} + +.error-boundary { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 100vh; + padding: 2rem; + text-align: center; +} + +.error-boundary h1 { + font-size: 2rem; + margin-bottom: 1rem; + color: var(--error); +} + +.error-boundary button { + margin-top: 1rem; + padding: 0.75rem 1.5rem; + background: var(--accent); + color: white; + border: none; + border-radius: 0.5rem; + cursor: pointer; + font-size: 1rem; + transition: background 0.2s; +} + +.error-boundary button:hover { + background: var(--accent-hover); +} + +@media (max-width: 768px) { + .app-container { + padding: 1rem; + } + + .stats-grid { + grid-template-columns: 1fr; + } + + .data-grid { + grid-template-columns: 1fr; + } + + .app-header h1 { + font-size: 1.5rem; + } +} diff --git a/servers/airtable/src/apps/dashboard/App.tsx b/servers/airtable/src/apps/dashboard/App.tsx new file mode 100644 index 0000000..351ebda --- /dev/null +++ b/servers/airtable/src/apps/dashboard/App.tsx @@ -0,0 +1 @@ +import React,{useState,useMemo,useTransition,useCallback}from'react';const useDebounce=(value:T,delay:number=300):T=>{const[debouncedValue,setDebouncedValue]=useState(value);React.useEffect(()=>{const handler=setTimeout(()=>setDebouncedValue(value),delay);return()=>clearTimeout(handler)},[value,delay]);return debouncedValue};const useToast=()=>{const[toasts,setToasts]=useState>([]);const showToast=useCallback((message:string,type:string='info')=>{const id=Date.now();setToasts(prev=>[...prev,{id,message,type}]);setTimeout(()=>setToasts(prev=>prev.filter(t=>t.id!==id)),3000)},[]);return{toasts,showToast}};interface BaseStats{id:string;name:string;records:number;tables:number;lastActivity:string}const mockBases:BaseStats[]=[{id:'base1',name:'Sales CRM',records:2450,tables:8,lastActivity:'2 hours ago'},{id:'base2',name:'Marketing Hub',records:1850,tables:12,lastActivity:'30 minutes ago'},{id:'base3',name:'Product Roadmap',records:680,tables:5,lastActivity:'1 day ago'},{id:'base4',name:'HR Operations',records:1250,tables:10,lastActivity:'3 hours ago'}];const App:React.FC=()=>{const[bases,setBases]=useState(mockBases);const[selectedBase,setSelectedBase]=useState(null);const[isPending,startTransition]=useTransition();const{toasts,showToast}=useToast();const stats=useMemo(()=>({totalBases:bases.length,totalRecords:bases.reduce((sum,b)=>sum+b.records,0),totalTables:bases.reduce((sum,b)=>sum+b.tables,0),avgRecords:Math.floor(bases.reduce((sum,b)=>sum+b.records,0)/bases.length)}),[bases]);const handleBaseClick=(base:BaseStats)=>{startTransition(()=>{setSelectedBase(base);showToast(`Viewing: ${base.name}`,'info')})};return(

Airtable Dashboard

Cross-base overview, record counts, activity

{stats.totalBases}
Total Bases
{stats.totalRecords.toLocaleString()}
Total Records
{stats.totalTables}
Total Tables
{stats.avgRecords}
Avg Records/Base

Recent Activity

{bases.map(base=>(
handleBaseClick(base)}>

{base.name}

{base.lastActivity}
Records:{base.records.toLocaleString()}
Tables:{base.tables}
))}

Quick Stats

Most Active:Marketing Hub
Largest:Sales CRM
Recent Update:30 min ago

System Health

API Status: Operational
Sync Status: Up to date
Storage: 45% used
{selectedBase&&(

{selectedBase.name}

Records: {selectedBase.records.toLocaleString()}

Tables: {selectedBase.tables}

Last Activity: {selectedBase.lastActivity}

)}
{toasts.map(toast=>(
{toast.message}
))}
)};export default App; \ No newline at end of file diff --git a/servers/airtable/src/apps/dashboard/index.html b/servers/airtable/src/apps/dashboard/index.html new file mode 100644 index 0000000..9927873 --- /dev/null +++ b/servers/airtable/src/apps/dashboard/index.html @@ -0,0 +1,12 @@ + + + + + + Airtable Dashboard + + +
+ + + diff --git a/servers/airtable/src/apps/dashboard/main.tsx b/servers/airtable/src/apps/dashboard/main.tsx new file mode 100644 index 0000000..5b258cd --- /dev/null +++ b/servers/airtable/src/apps/dashboard/main.tsx @@ -0,0 +1 @@ +import React,{lazy,Suspense}from'react';import{createRoot}from'react-dom/client';import'./styles.css';const App=lazy(()=>import('./App'));class ErrorBoundary extends React.Component<{children:React.ReactNode},{hasError:boolean;error?:Error}>{constructor(props:{children:React.ReactNode}){super(props);this.state={hasError:false}}static getDerivedStateFromError(error:Error){return{hasError:true,error}}componentDidCatch(error:Error,errorInfo:React.ErrorInfo){console.error('ErrorBoundary caught:',error,errorInfo)}render(){if(this.state.hasError){return(

Something went wrong

{this.state.error?.message}

)}return this.props.children}}const LoadingSkeleton=()=>(
);const root=createRoot(document.getElementById('root')!);root.render(}>); \ No newline at end of file diff --git a/servers/airtable/src/apps/dashboard/styles.css b/servers/airtable/src/apps/dashboard/styles.css new file mode 100644 index 0000000..f252c8e --- /dev/null +++ b/servers/airtable/src/apps/dashboard/styles.css @@ -0,0 +1 @@ +:root{--bg-primary:#0f172a;--bg-secondary:#1e293b;--bg-tertiary:#334155;--text-primary:#f1f5f9;--text-secondary:#cbd5e1;--text-muted:#94a3b8;--accent:#3b82f6;--accent-hover:#2563eb;--success:#10b981;--warning:#f59e0b;--error:#ef4444;--border:#334155;--shadow:rgba(0,0,0,0.3)}*{margin:0;padding:0;box-sizing:border-box}body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;background:var(--bg-primary);color:var(--text-primary);line-height:1.6}#root{min-height:100vh}.app-container{max-width:1600px;margin:0 auto;padding:2rem}.app-header{margin-bottom:2rem;text-align:center}.app-header h1{font-size:2.5rem;font-weight:700;margin-bottom:0.5rem}.subtitle{color:var(--text-secondary);font-size:1.125rem}.stats-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:1.5rem;margin-bottom:3rem}.stat-card{background:var(--bg-secondary);padding:2rem;border-radius:0.75rem;border:1px solid var(--border);transition:transform 0.2s,box-shadow 0.2s;text-align:center}.stat-card:hover{transform:translateY(-2px);box-shadow:0 4px 12px var(--shadow)}.stat-highlight{border:2px solid var(--accent);background:linear-gradient(135deg,var(--bg-secondary) 0%,rgba(59,130,246,0.1) 100%)}.stat-value{font-size:3rem;font-weight:700;color:var(--accent);margin-bottom:0.5rem}.stat-label{color:var(--text-secondary);font-size:1rem;text-transform:uppercase;letter-spacing:0.05em}.activity-section{margin-bottom:3rem}.activity-section h2{font-size:1.75rem;margin-bottom:1.5rem}.activity-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:1rem}.activity-card{background:var(--bg-secondary);border:1px solid var(--border);border-radius:0.75rem;padding:1.5rem;cursor:pointer;transition:transform 0.2s,box-shadow 0.2s,border-color 0.2s}.activity-card:hover{transform:translateY(-2px);box-shadow:0 8px 16px var(--shadow);border-color:var(--accent)}.activity-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem}.activity-header h3{font-size:1.125rem;font-weight:600}.activity-time{color:var(--text-muted);font-size:0.875rem}.activity-stats{display:flex;gap:2rem}.activity-stat{display:flex;flex-direction:column;gap:0.25rem;font-size:0.875rem}.activity-stat .label{color:var(--text-secondary)}.activity-stat .value{color:var(--text-primary);font-weight:600;font-size:1.125rem}.overview-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(350px,1fr));gap:1.5rem;margin-bottom:2rem}.overview-card{background:var(--bg-secondary);border:1px solid var(--border);border-radius:0.75rem;padding:2rem}.overview-card h3{font-size:1.25rem;margin-bottom:1.5rem;padding-bottom:1rem;border-bottom:2px solid var(--border)}.quick-stats{display:flex;flex-direction:column;gap:1rem}.quick-stat{display:flex;justify-content:space-between;padding:0.75rem;background:var(--bg-tertiary);border-radius:0.5rem}.quick-stat span{color:var(--text-secondary)}.quick-stat strong{color:var(--text-primary)}.health-indicators{display:flex;flex-direction:column;gap:1rem}.health-item{display:flex;align-items:center;gap:0.75rem;padding:0.75rem;background:var(--bg-tertiary);border-radius:0.5rem}.health-dot{width:12px;height:12px;border-radius:50%;flex-shrink:0}.health-good{background:var(--success);box-shadow:0 0 8px var(--success)}.detail-panel{background:var(--bg-secondary);border:1px solid var(--border);border-radius:0.75rem;padding:1.5rem}.detail-panel h2{font-size:1.5rem;margin-bottom:1rem}.toast-container{position:fixed;top:1rem;right:1rem;z-index:1000;display:flex;flex-direction:column;gap:0.5rem}.toast{background:var(--bg-secondary);border:1px solid var(--border);border-radius:0.5rem;padding:1rem 1.5rem;min-width:250px;box-shadow:0 4px 12px var(--shadow);animation:slideIn 0.3s ease-out}.toast-success{border-left:4px solid var(--success)}.toast-error{border-left:4px solid var(--error)}.toast-info{border-left:4px solid var(--accent)}@keyframes slideIn{from{transform:translateX(100%);opacity:0}to{transform:translateX(0);opacity:1}}.shimmer{background:linear-gradient(90deg,var(--bg-secondary) 0%,var(--bg-tertiary) 50%,var(--bg-secondary) 100%);background-size:200% 100%;animation:shimmer 1.5s infinite}@keyframes shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}.loading-skeleton{padding:2rem}.skeleton-header{height:3rem;border-radius:0.5rem;margin-bottom:2rem}.skeleton-content{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:1rem}.skeleton-card{height:150px;border-radius:0.75rem}.error-boundary{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh;padding:2rem;text-align:center}.error-boundary h1{font-size:2rem;margin-bottom:1rem;color:var(--error)}.error-boundary button{margin-top:1rem;padding:0.75rem 1.5rem;background:var(--accent);color:white;border:none;border-radius:0.5rem;cursor:pointer;font-size:1rem;transition:background 0.2s}.error-boundary button:hover{background:var(--accent-hover)}@media (max-width:768px){.app-container{padding:1rem}.stats-grid{grid-template-columns:1fr}.activity-list{grid-template-columns:1fr}.overview-grid{grid-template-columns:1fr}.app-header h1{font-size:1.75rem}} \ No newline at end of file diff --git a/servers/airtable/src/apps/field-manager/App.tsx b/servers/airtable/src/apps/field-manager/App.tsx new file mode 100644 index 0000000..b2def54 --- /dev/null +++ b/servers/airtable/src/apps/field-manager/App.tsx @@ -0,0 +1,157 @@ +import React, { useState, useMemo, useTransition, useCallback } from 'react'; + +const useDebounce = (value: T, delay: number = 300): T => { + const [debouncedValue, setDebouncedValue] = useState(value); + + React.useEffect(() => { + const handler = setTimeout(() => setDebouncedValue(value), delay); + return () => clearTimeout(handler); + }, [value, delay]); + + return debouncedValue; +}; + +const useToast = () => { + const [toasts, setToasts] = useState>([]); + + const showToast = useCallback((message: string, type: string = 'info') => { + const id = Date.now(); + setToasts(prev => [...prev, { id, message, type }]); + setTimeout(() => setToasts(prev => prev.filter(t => t.id !== id)), 3000); + }, []); + + return { toasts, showToast }; +}; + +interface Field { + id: string; + name: string; + type: string; + required: boolean; + description: string; +} + +const mockFields: Field[] = [ + { id: 'fld1', name: 'Name', type: 'singleLineText', required: true, description: 'Contact name' }, + { id: 'fld2', name: 'Email', type: 'email', required: true, description: 'Email address' }, + { id: 'fld3', name: 'Phone', type: 'phoneNumber', required: false, description: 'Phone number' }, + { id: 'fld4', name: 'Status', type: 'singleSelect', required: true, description: 'Current status' }, + { id: 'fld5', name: 'Notes', type: 'multilineText', required: false, description: 'Additional notes' }, + { id: 'fld6', name: 'Created', type: 'dateTime', required: true, description: 'Creation date' }, +]; + +const App: React.FC = () => { + const [searchQuery, setSearchQuery] = useState(''); + const [selectedField, setSelectedField] = useState(null); + const [isPending, startTransition] = useTransition(); + const { toasts, showToast } = useToast(); + + const debouncedSearch = useDebounce(searchQuery, 300); + + const filteredFields = useMemo(() => { + return mockFields.filter(field => + field.name.toLowerCase().includes(debouncedSearch.toLowerCase()) || + field.type.toLowerCase().includes(debouncedSearch.toLowerCase()) + ); + }, [debouncedSearch]); + + const stats = useMemo(() => ({ + total: mockFields.length, + required: mockFields.filter(f => f.required).length, + optional: mockFields.filter(f => !f.required).length, + }), []); + + const handleFieldClick = (field: Field) => { + startTransition(() => { + setSelectedField(field); + showToast(`Selected field: ${field.name}`, 'success'); + }); + }; + + return ( +
+
+

Field Manager

+

View and configure table fields

+
+ +
+
+
{stats.total}
+
Total Fields
+
+
+
{stats.required}
+
Required
+
+
+
{stats.optional}
+
Optional
+
+
+ +
+ setSearchQuery(e.target.value)} + className="search-input" + /> +
+ + {filteredFields.length === 0 ? ( +
+
🔍
+

No fields found

+

Try adjusting your search query

+
+ ) : ( +
+ {filteredFields.map(field => ( +
handleFieldClick(field)} + > +
+

{field.name}

+ {field.required && Required} +
+
+
+ Type: + {field.type} +
+
+ Description: + {field.description} +
+
+
+ ))} +
+ )} + + {selectedField && ( +
+

Field Details: {selectedField.name}

+

ID: {selectedField.id}

+

Type: {selectedField.type}

+

Required: {selectedField.required ? 'Yes' : 'No'}

+

Description: {selectedField.description}

+
+ )} + +
+ {toasts.map(toast => ( +
+ {toast.message} +
+ ))} +
+
+ ); +}; + +export default App; diff --git a/servers/airtable/src/apps/field-manager/index.html b/servers/airtable/src/apps/field-manager/index.html new file mode 100644 index 0000000..4bf9ae7 --- /dev/null +++ b/servers/airtable/src/apps/field-manager/index.html @@ -0,0 +1,12 @@ + + + + + + Airtable Field Manager + + +
+ + + diff --git a/servers/airtable/src/apps/field-manager/main.tsx b/servers/airtable/src/apps/field-manager/main.tsx new file mode 100644 index 0000000..22b087f --- /dev/null +++ b/servers/airtable/src/apps/field-manager/main.tsx @@ -0,0 +1,58 @@ +import React, { lazy, Suspense } from 'react'; +import { createRoot } from 'react-dom/client'; +import './styles.css'; + +const App = lazy(() => import('./App')); + +class ErrorBoundary extends React.Component< + { children: React.ReactNode }, + { hasError: boolean; error?: Error } +> { + constructor(props: { children: React.ReactNode }) { + super(props); + this.state = { hasError: false }; + } + + static getDerivedStateFromError(error: Error) { + return { hasError: true, error }; + } + + componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { + console.error('ErrorBoundary caught:', error, errorInfo); + } + + render() { + if (this.state.hasError) { + return ( +
+

Something went wrong

+

{this.state.error?.message}

+ +
+ ); + } + return this.props.children; + } +} + +const LoadingSkeleton = () => ( +
+
+
+
+
+
+
+
+); + +const root = createRoot(document.getElementById('root')!); +root.render( + + + }> + + + + +); diff --git a/servers/airtable/src/apps/field-manager/styles.css b/servers/airtable/src/apps/field-manager/styles.css new file mode 100644 index 0000000..ef40b08 --- /dev/null +++ b/servers/airtable/src/apps/field-manager/styles.css @@ -0,0 +1 @@ +:root{--bg-primary:#0f172a;--bg-secondary:#1e293b;--bg-tertiary:#334155;--text-primary:#f1f5f9;--text-secondary:#cbd5e1;--text-muted:#94a3b8;--accent:#3b82f6;--accent-hover:#2563eb;--success:#10b981;--warning:#f59e0b;--error:#ef4444;--border:#334155;--shadow:rgba(0,0,0,0.3)}*{margin:0;padding:0;box-sizing:border-box}body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;background:var(--bg-primary);color:var(--text-primary);line-height:1.6}#root{min-height:100vh}.app-container{max-width:1400px;margin:0 auto;padding:2rem}.app-header{margin-bottom:2rem}.app-header h1{font-size:2rem;font-weight:700;margin-bottom:0.5rem}.subtitle{color:var(--text-secondary);font-size:1rem}.stats-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:1rem;margin-bottom:2rem}.stat-card{background:var(--bg-secondary);padding:1.5rem;border-radius:0.75rem;border:1px solid var(--border);transition:transform 0.2s,box-shadow 0.2s}.stat-card:hover{transform:translateY(-2px);box-shadow:0 4px 12px var(--shadow)}.stat-value{font-size:2.5rem;font-weight:700;color:var(--accent)}.stat-label{color:var(--text-secondary);font-size:0.875rem;margin-top:0.5rem}.search-container{margin-bottom:2rem}.search-input{width:100%;padding:0.875rem 1rem;background:var(--bg-secondary);border:1px solid var(--border);border-radius:0.5rem;color:var(--text-primary);font-size:1rem;transition:border-color 0.2s}.search-input:focus{outline:none;border-color:var(--accent)}.data-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:1rem;margin-bottom:2rem}.data-card{background:var(--bg-secondary);border:1px solid var(--border);border-radius:0.75rem;padding:1.5rem;cursor:pointer;transition:transform 0.2s,box-shadow 0.2s,border-color 0.2s}.data-card:hover{transform:translateY(-2px);box-shadow:0 8px 16px var(--shadow);border-color:var(--accent)}.card-header{display:flex;justify-content:space-between;align-items:start;margin-bottom:1rem}.card-header h3{font-size:1.125rem;font-weight:600;color:var(--text-primary)}.badge{padding:0.25rem 0.75rem;border-radius:1rem;font-size:0.75rem;font-weight:600;text-transform:uppercase}.badge-required{background:rgba(239,68,68,0.2);color:var(--error)}.card-body{display:flex;flex-direction:column;gap:0.5rem}.card-stat{display:flex;justify-content:space-between;font-size:0.875rem}.card-stat .label{color:var(--text-secondary)}.card-stat .value{color:var(--text-primary);font-weight:500}.detail-panel{background:var(--bg-secondary);border:1px solid var(--border);border-radius:0.75rem;padding:1.5rem;margin-top:2rem}.detail-panel h2{font-size:1.5rem;margin-bottom:1rem}.empty-state{text-align:center;padding:4rem 2rem}.empty-icon{font-size:4rem;margin-bottom:1rem}.empty-state h3{font-size:1.5rem;margin-bottom:0.5rem}.empty-state p{color:var(--text-secondary)}.toast-container{position:fixed;top:1rem;right:1rem;z-index:1000;display:flex;flex-direction:column;gap:0.5rem}.toast{background:var(--bg-secondary);border:1px solid var(--border);border-radius:0.5rem;padding:1rem 1.5rem;min-width:250px;box-shadow:0 4px 12px var(--shadow);animation:slideIn 0.3s ease-out}.toast-success{border-left:4px solid var(--success)}.toast-error{border-left:4px solid var(--error)}.toast-info{border-left:4px solid var(--accent)}@keyframes slideIn{from{transform:translateX(100%);opacity:0}to{transform:translateX(0);opacity:1}}.shimmer{background:linear-gradient(90deg,var(--bg-secondary) 0%,var(--bg-tertiary) 50%,var(--bg-secondary) 100%);background-size:200% 100%;animation:shimmer 1.5s infinite}@keyframes shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}.loading-skeleton{padding:2rem}.skeleton-header{height:3rem;border-radius:0.5rem;margin-bottom:2rem}.skeleton-content{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:1rem}.skeleton-card{height:150px;border-radius:0.75rem}.error-boundary{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh;padding:2rem;text-align:center}.error-boundary h1{font-size:2rem;margin-bottom:1rem;color:var(--error)}.error-boundary button{margin-top:1rem;padding:0.75rem 1.5rem;background:var(--accent);color:white;border:none;border-radius:0.5rem;cursor:pointer;font-size:1rem;transition:background 0.2s}.error-boundary button:hover{background:var(--accent-hover)}@media (max-width:768px){.app-container{padding:1rem}.stats-grid{grid-template-columns:1fr}.data-grid{grid-template-columns:1fr}.app-header h1{font-size:1.5rem}} \ No newline at end of file diff --git a/servers/airtable/src/apps/form-builder/App.tsx b/servers/airtable/src/apps/form-builder/App.tsx new file mode 100644 index 0000000..a2bb2c4 --- /dev/null +++ b/servers/airtable/src/apps/form-builder/App.tsx @@ -0,0 +1 @@ +import React,{useState,useMemo,useTransition,useCallback}from'react';const useDebounce=(value:T,delay:number=300):T=>{const[debouncedValue,setDebouncedValue]=useState(value);React.useEffect(()=>{const handler=setTimeout(()=>setDebouncedValue(value),delay);return()=>clearTimeout(handler)},[value,delay]);return debouncedValue};const useToast=()=>{const[toasts,setToasts]=useState>([]);const showToast=useCallback((message:string,type:string='info')=>{const id=Date.now();setToasts(prev=>[...prev,{id,message,type}]);setTimeout(()=>setToasts(prev=>prev.filter(t=>t.id!==id)),3000)},[]);return{toasts,showToast}};interface FormField{id:string;label:string;type:string;required:boolean}const mockFields:FormField[]=[{id:'f1',label:'Name',type:'text',required:true},{id:'f2',label:'Email',type:'email',required:true},{id:'f3',label:'Phone',type:'tel',required:false},{id:'f4',label:'Message',type:'textarea',required:false}];const App:React.FC=()=>{const[fields,setFields]=useState(mockFields);const[formData,setFormData]=useState>({});const[isPending,startTransition]=useTransition();const{toasts,showToast}=useToast();const stats=useMemo(()=>({total:fields.length,required:fields.filter(f=>f.required).length,filled:Object.keys(formData).length}),[fields,formData]);const handleFieldChange=(id:string,value:string)=>{startTransition(()=>{setFormData(prev=>({...prev,[id]:value}))})};const handleSubmit=()=>{showToast('Form submitted successfully!','success')};const handleAddField=()=>{const newField={id:`f${fields.length+1}`,label:'New Field',type:'text',required:false};setFields([...fields,newField]);showToast('Field added','success')};return(

Form Builder

Create Airtable forms

{stats.total}
Fields
{stats.required}
Required
{stats.filled}
Filled

Form Preview

{fields.map(field=>(
{field.type==='textarea'?(