Skip to content

feat: AI Create Card on the dashboard#156

Open
parth0025 wants to merge 1 commit into
stagingfrom
feature/ai-create-dashboard-card
Open

feat: AI Create Card on the dashboard#156
parth0025 wants to merge 1 commit into
stagingfrom
feature/ai-create-dashboard-card

Conversation

@parth0025
Copy link
Copy Markdown
Collaborator

Adds an "AI Create Card" button beside the existing "+ Add Card" on the dashboard. Clicking it opens a sidebar where the user types a natural-language request ("show me a pie chart of urgent open tasks for the AlianHub project"). The AI returns a fully-populated card definition, the user previews it, and on confirm the card commits via the exact same backend write path the manual modal already uses — no new dashboard routes, no schema changes.

What landed in this PR:

== Backend ==

  • utils/aiPrompts.json: new prompt entry "Dashboard Card Generator" (_id 67ff000000000000aicard001). The prompt now includes:
    • USER_REQUEST / CARD_CATALOGUE / USER_CONTEXT substitution keys.
    • responseFormat: {type: "json_object"} so the model is contractually required to return parseable JSON.
    • temperature: 0.2 for deterministic output.
    • Six few-shot examples covering pie/bar charts, task list with multi-filter, assignee filter, time-tracked summary, task counts with measure/calculation/timerange, TASKLIST.fields multi-select, and QueueListComp.statusArray.
    • Per-field-type output rules (enum id vs name, multi-select arrays, project/user/status id resolution).
  • Modules/AI/controller.js:
    • Fixed pre-existing outputFormat duplication bug — was appended once per matched substitution key (3x for our prompt). Now appended once after the substitution loop. Backwards-compatible.
    • Non-streaming branch now forwards optional responseFormat and temperature from the prompt entry to OpenAI. Existing prompts without these fields keep OpenAI defaults.

== Frontend ==

  • frontend/src/plugins/dashboard/components/AICardSidebar.vue (new): Self-contained sidebar. Bypasses composable/aiHelper.js because the existing helper has two silent-bail bugs documented inline (companyUsers not-array TypeError + permission=null routing to projectRules). Replicates only the plan check + Swal upgrade dialog and POSTs to /api/v1/generatePrompt directly. Server-side quota tracking (limitCountUpdate) is preserved.

    Schema-aware catalogue summary in buildCatalogueSummary:

    • One indented line per configurable field with type, required flag, enum {id=name, ...} mapping for dropdowns, default value.
    • Distinguishes single-select vs multi-select (Array.isArray of default value) and emits "array of enum ids" vs "enum" so the model knows TASKLIST.fields takes [3, 4, 5] not 3.
    • Skips fields with disabled:true / hidden:true / type:"filter" so the AI doesn't try to populate them.
    • Resolves dashboardCard. via vue-i18n into a human sentence per card.

    Per-field validateField with type-specific coercion:

    • text → trimmed string capped by rules max length.
    • radio → coerced boolean.
    • dropdown w/ options → exact id → numeric coercion ("3" → 3) → name fallback ("both" → 3) → catalogue default (with $numberLong normalisation so TASKLIST.groupBy "0" comes through as 0).
    • multi-select dropdown → maps every supplied value through the coercer, de-dupes, falls back to array default.
    • projectId → resolveProjectIds (exact _id, case-insensitive name, first-project fallback).
    • AssigneeUserId → resolveMemberIds (userId, Employee_Name).
    • statusArray (QueueListComp) → resolveStatusKeys against USER_CONTEXT.statusKeys.
    • Disabled/hidden fields inherit the catalogue default unconditionally.

    Runtime context (buildUserContext): { projects, statusKeys,
    priorityKeys, members, taskTypes } so the model has the IDs it needs
    for filters and member resolution.

    Modern minimalist UI:

    • Heading + subtitle, no asterisk-on-label.
    • 10px-radius textarea with indigo focus ring.
    • Live char counter (current / 500) + dynamic helper text ("Minimum 5 characters" idle, "X more to go" warning).
    • Five quick-pick chips (workload, assignee, urgent, calendar, time-tracking) filtered against the catalogue's available cardTypes. Clicking populates the textarea.
    • dl-based preview with subtle row dividers and indigo filter tags.
    • Indigo primary / outline secondary buttons with proper disabled treatment.
    • Loading spinner with min-height so the panel doesn't collapse.
    • Responsive: <=767px → full-viewport width, 16px font (avoids iOS auto-zoom on focus), buttons stack column-reverse.
  • frontend/src/plugins/dashboard/views/HomePage.vue: Mounts beside the existing AdvanceSearchModal, exposes openAiSidebar() via defineExpose alongside handleToggle, and routes the card-generated event through handleCardAddOnDashboard so the AI path lands on the same backend write as the manual modal.

  • frontend/src/plugins/dashboard/views/Home.vue: New "AI Create Card" button beside "+ Add Card", gated by selectedCompany.planFeature.aiPermission so users on plans without AI never see the entry point.

  • frontend/src/locales/en.js: New AICard.* section (button label, sidebar copy, helper text, chip labels + their full prompts, preview labels, error messages). The other 10 locales fall back to English via vue-i18n until translators backfill (follow-up task already spawned).

== Card schemas covered (full catalogue audit) ==
Verified each catalogue entry against its renderer. The AI now emits fully-populated cardData for:

  • TASKLIST: fields (multi-select 1-7), groupBy (0/2/3/4), projectId.
  • QueueListComp: statusArray from company status keys.
  • TimeEstimatedComp / TimeTrackComp / TimeEstimatedWorkloadComp: logtype enum (1-3), timerange enum (1-8), AssigneeUserId, projectId.
  • TotalUrgentTasksComp: measure enum (1-3 with $numberLong handling), calculation enum (1-6), timerange, taskLabel, AssigneeUserId.
  • WorkloadByStatus* / TasksByAssignee*: isPercentage, isShowLegend, isShowDataLabels, isParentTask, projectId.
  • CalendarCard: projectId only (its renderer reads only projectId).

== Deferred (separate follow-ups) ==

  • Streaming generation, chat-style refinement, inline preview editing.
  • Server-side card validation hardening (benefits the manual flow too).
  • 3x duplicate TotalUrgentTasksComp entries in cardComponent.json.
  • Translation backfill for the 10 non-English locales.

Pull Request Template Chooser

Please click the link that matches your contribution type to load the correct format.

Note: Clicking a link will reload this page and clear any text you've already typed here.

  • Bug Fix
    Use this for fixing broken logic or UI glitches.

  • New Feature
    Use this for adding new functionality or components.

  • Refactor
    Use this for code cleanup, performance tweaks, or technical debt.


General Summary

If you don't want to use a specific template, please provide a brief summary of your changes below.

Adds an "AI Create Card" button beside the existing "+ Add Card" on
the dashboard. Clicking it opens a sidebar where the user types a
natural-language request ("show me a pie chart of urgent open tasks
for the AlianHub project"). The AI returns a fully-populated card
definition, the user previews it, and on confirm the card commits via
the exact same backend write path the manual modal already uses — no
new dashboard routes, no schema changes.

What landed in this PR:

== Backend ==
- utils/aiPrompts.json: new prompt entry "Dashboard Card Generator"
  (_id 67ff000000000000aicard001). The prompt now includes:
    * USER_REQUEST / CARD_CATALOGUE / USER_CONTEXT substitution keys.
    * responseFormat: {type: "json_object"} so the model is contractually
      required to return parseable JSON.
    * temperature: 0.2 for deterministic output.
    * Six few-shot examples covering pie/bar charts, task list with
      multi-filter, assignee filter, time-tracked summary, task counts
      with measure/calculation/timerange, TASKLIST.fields multi-select,
      and QueueListComp.statusArray.
    * Per-field-type output rules (enum id vs name, multi-select arrays,
      project/user/status id resolution).
- Modules/AI/controller.js:
    * Fixed pre-existing outputFormat duplication bug — was appended once
      per matched substitution key (3x for our prompt). Now appended once
      after the substitution loop. Backwards-compatible.
    * Non-streaming branch now forwards optional responseFormat and
      temperature from the prompt entry to OpenAI. Existing prompts
      without these fields keep OpenAI defaults.

== Frontend ==
- frontend/src/plugins/dashboard/components/AICardSidebar.vue (new):
  Self-contained sidebar. Bypasses composable/aiHelper.js because the
  existing helper has two silent-bail bugs documented inline (companyUsers
  not-array TypeError + permission=null routing to projectRules).
  Replicates only the plan check + Swal upgrade dialog and POSTs to
  /api/v1/generatePrompt directly. Server-side quota tracking
  (limitCountUpdate) is preserved.

  Schema-aware catalogue summary in buildCatalogueSummary:
    * One indented line per configurable field with type, required flag,
      enum {id=name, ...} mapping for dropdowns, default value.
    * Distinguishes single-select vs multi-select (Array.isArray of
      default value) and emits "array of enum ids" vs "enum" so the model
      knows TASKLIST.fields takes [3, 4, 5] not 3.
    * Skips fields with disabled:true / hidden:true / type:"filter" so
      the AI doesn't try to populate them.
    * Resolves dashboardCard.<description> via vue-i18n into a human
      sentence per card.

  Per-field validateField with type-specific coercion:
    * text → trimmed string capped by rules max length.
    * radio → coerced boolean.
    * dropdown w/ options → exact id → numeric coercion ("3" → 3) →
      name fallback ("both" → 3) → catalogue default (with $numberLong
      normalisation so TASKLIST.groupBy "0" comes through as 0).
    * multi-select dropdown → maps every supplied value through the
      coercer, de-dupes, falls back to array default.
    * projectId → resolveProjectIds (exact _id, case-insensitive name,
      first-project fallback).
    * AssigneeUserId → resolveMemberIds (userId, Employee_Name).
    * statusArray (QueueListComp) → resolveStatusKeys against
      USER_CONTEXT.statusKeys.
    * Disabled/hidden fields inherit the catalogue default unconditionally.

  Runtime context (buildUserContext): { projects, statusKeys,
  priorityKeys, members, taskTypes } so the model has the IDs it needs
  for filters and member resolution.

  Modern minimalist UI:
    * Heading + subtitle, no asterisk-on-label.
    * 10px-radius textarea with indigo focus ring.
    * Live char counter (current / 500) + dynamic helper text
      ("Minimum 5 characters" idle, "X more to go" warning).
    * Five quick-pick chips (workload, assignee, urgent, calendar,
      time-tracking) filtered against the catalogue's available
      cardTypes. Clicking populates the textarea.
    * dl-based preview with subtle row dividers and indigo filter tags.
    * Indigo primary / outline secondary buttons with proper disabled
      treatment.
    * Loading spinner with min-height so the panel doesn't collapse.
    * Responsive: <=767px → full-viewport width, 16px font (avoids iOS
      auto-zoom on focus), buttons stack column-reverse.

- frontend/src/plugins/dashboard/views/HomePage.vue:
  Mounts <AICardSidebar/> beside the existing AdvanceSearchModal,
  exposes openAiSidebar() via defineExpose alongside handleToggle, and
  routes the card-generated event through handleCardAddOnDashboard so
  the AI path lands on the same backend write as the manual modal.

- frontend/src/plugins/dashboard/views/Home.vue:
  New "AI Create Card" button beside "+ Add Card", gated by
  selectedCompany.planFeature.aiPermission so users on plans without
  AI never see the entry point.

- frontend/src/locales/en.js:
  New AICard.* section (button label, sidebar copy, helper text, chip
  labels + their full prompts, preview labels, error messages). The
  other 10 locales fall back to English via vue-i18n until translators
  backfill (follow-up task already spawned).

== Card schemas covered (full catalogue audit) ==
Verified each catalogue entry against its renderer. The AI now emits
fully-populated cardData for:
- TASKLIST: fields (multi-select 1-7), groupBy (0/2/3/4), projectId.
- QueueListComp: statusArray from company status keys.
- TimeEstimatedComp / TimeTrackComp / TimeEstimatedWorkloadComp:
  logtype enum (1-3), timerange enum (1-8), AssigneeUserId, projectId.
- TotalUrgentTasksComp: measure enum (1-3 with $numberLong handling),
  calculation enum (1-6), timerange, taskLabel, AssigneeUserId.
- WorkloadByStatus* / TasksByAssignee*: isPercentage, isShowLegend,
  isShowDataLabels, isParentTask, projectId.
- CalendarCard: projectId only (its renderer reads only projectId).

== Deferred (separate follow-ups) ==
- Streaming generation, chat-style refinement, inline preview editing.
- Server-side card validation hardening (benefits the manual flow too).
- 3x duplicate TotalUrgentTasksComp entries in cardComponent.json.
- Translation backfill for the 10 non-English locales.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@parth0025 parth0025 self-assigned this May 15, 2026
@parth0025 parth0025 added the Hold label May 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant