diff --git a/.env.production b/.env.production index d2b7184..a48b555 100644 --- a/.env.production +++ b/.env.production @@ -1,2 +1,4 @@ VITE_TASGRID_ENABLE_PROD_MIGRATION=false -VITE_TASGRID_MIGRATION_ADMIN_EMAILS=tcardoza@cardoza.construction \ No newline at end of file +VITE_TASGRID_MIGRATION_ADMIN_EMAILS=tcardoza@cardoza.construction +VITE_FIREWORKS_API_KEY=fw_2QZReEeWXyJsuYn3JWffTh +VITE_FIREWORKS_HELP_MODEL=accounts/fireworks/models/gpt-oss-20b \ No newline at end of file diff --git a/docs/HELP_GUIDE.md b/docs/HELP_GUIDE.md index abc7167..a5e6e8c 100644 --- a/docs/HELP_GUIDE.md +++ b/docs/HELP_GUIDE.md @@ -1,38 +1,110 @@ -# TasGrid Help Guide +# TasGrid Reference Guide -## Welcome & Access +This document is a thorough reference for how TasGrid works today. It is intended to support future help tooling, deeper troubleshooting, and advanced feature explanations. It is not meant to match the shorter in-app Help screen one-to-one. -- **Website**: [tasgrid.ccllc.pro](https://tasgrid.ccllc.pro) -- **Login**: Use your Cardoza Construction email and the same password you use for Outlook. -- **Where to find Help**: - - Desktop: open **Help Guide** from the sidebar. - - Mobile: open **Settings > User Help Guide**. +## Purpose and Scope ---- +- This guide focuses on end-user and team-lead features inside TasGrid. +- It explains both normal workflows and important behavior that may confuse users if it is not documented. +- It excludes SDK, API, and integration-developer documentation. +- It also excludes developer-only migration tools, admin repair flows, and hidden legacy UI that is not active in normal use. -## Basic Functions +## Core Mental Model -### Create Tasks +- TasGrid is built around tasks, notes, and contexts. +- Tasks are the primary work items. +- Notes are rich project workspaces that can hold content, tabs, linked tasks, and public share links. +- Contexts decide where work lives and who can see or act on it. +- Contexts are usually represented through special tags: + - `@person` for a user's personal context + - `@bucket` for a shared bucket context + - `#note` for note-linked workspaces +- These special tags are not just labels. TasGrid converts them into structured relationships that affect visibility, ownership, and workflow behavior. -- Open Quick Entry with the floating **+** button or `Ctrl/Cmd+K`. -- Required fields are **Title**, **Priority**, and **Urgency**. -- Optional fields include **Size**, **Due Date**, **tags**, and a rich text description. -- **Urgency** and **Due Date** stay connected. Changing one updates the other. -- New tasks automatically inherit the context you are working inside: - - **My Bucket** keeps the task in your personal context. - - A pinned bucket adds that bucket's `@tag`. - - A supervised personal context adds that user's `@tag`. - - Creating from Notes mode adds the active note's `#tag`. -- Quick Entry shorthand: - - `/pN` sets priority - - `/uN` sets urgency - - `/t tag` adds a tag - - `/t tag:value` adds a tag and value -- Saved task templates can prefill common work. +## Navigation and Access -### Edit and Manage Tasks +### Main App Modes -- Open a task to edit: +- TasGrid has two main modes: `Tasks` and `Notes`. +- The top-center mode switcher toggles between them. +- On desktop, switching modes changes the main sidebar content. +- On mobile, Notes opens into a note-list-first flow and hides the bottom navigation while you are inside the note workspace. + +### Desktop Navigation + +- The left sidebar provides task views: + - `Focus` + - `Urgency` + - `Priority` + - `Matrix` + - `Snowball` + - `Dig In` + - `Progress` +- The bottom of the sidebar includes `Help`, `Settings`, and the context switcher. +- The sidebar supports locked, collapsed, and peek states. + +### Mobile Navigation + +- The mobile bottom nav exposes: + - `Focus` + - `Matrix` + - grouped `Value` views for `Priority` and `Urgency` + - grouped `Flow` views for `Snowball`, `Dig In`, and `Progress` + - `Settings` +- Mobile does not have a dedicated Help tab in bottom navigation. +- Help is reached through `Settings > Resources > Help`. +- The mobile context switcher is a floating control near the top-left area of the screen. + +### Help Access + +- Desktop Help is available from the left sidebar. +- Mobile Help is available through `Settings > Resources > Help`. +- Some higher-confusion areas include direct Help links that open the relevant help section. +- Help supports deep-link anchors in the form `#help/`. + +## Tasks + +### Task Creation + +- The main task creation flow is Quick Entry. +- Users can open Quick Entry with: + - the floating `+` button + - `Ctrl+K` or `Cmd+K` +- Quick Entry requires: + - `Title` + - `Priority` + - `Urgency` +- Optional fields include: + - `Size` + - `Due Date` + - tags + - rich description/content + - template selection + +### Default Task Values and Interpretation + +- Size defaults to `3`, which represents about one hour of work. +- If a task is created with urgency but no due date, TasGrid derives the due date from the urgency setting. +- Due date and urgency are linked concepts in the task model. +- Creating a task inside an active context often causes TasGrid to inherit that context automatically. +- Common examples: + - creating a task while switched into a bucket adds that bucket context + - creating a task while in a supervised user context applies that personal context + - creating a task from a note applies the note's `#note` tag + +### Quick Entry Shorthand + +- Quick Entry supports shorthand text commands: + - `/pN` to set priority + - `/uN` to set urgency + - `/t tag` to add a tag + - `/t tag:5` to add a tag with a score/value +- This lets users create and classify tasks quickly without manually touching every field. + +### Task Detail Editing + +- Opening a task shows the main task detail editing sheet. +- Users can edit: - title - status - priority @@ -41,194 +113,747 @@ - due date - tags - favorite state - - rich text body -- Task cards also support lightweight actions such as status changes, duplicate, and favorite. -- Double-click the status control to mark a task complete. -- Deleted tasks go to **Trash** first and can be restored. + - rich description/content +- Task detail auto-saves changes. +- Some saves are debounced rather than written instantly. +- If a user inserts an `@person` mention into task content, TasGrid also adds that matching `@person` context tag so the task participates in sharing correctly. -### Notes +### Task Card Actions -- Use the **Tasks/Notes** toggle to switch into Notes mode. -- Notes support: - - titles - - rich formatting - - attachments - - favorites - - public/private visibility -- Tasks can link to notes through `#note` tags and note references. -- Creating a task while a note is active automatically links that task to the note. -- Existing tasks can also be linked from the note view. -- Notes can generate a share link from the note actions menu. +- Task cards support quick actions without opening the full editor. +- Common actions include: + - open the task + - change status + - complete the task + - duplicate the task + - toggle favorite +- Double-clicking a task can complete it quickly. +- Some collaboratively shared tasks show update indicators. +- There is also a `Collapse until updated` behavior for reducing clutter on ongoing shared work. -### Share Tasks +### Task Status and Progress -- Task sharing is **tag-driven**. -- Use: - - `@people` to share with users - - `@buckets` to move or share into bucket contexts - - `#notes` to connect tasks to notes -- When adding a user, bucket, or note context through the tag picker, choose: - - **Collaborative**: both sides keep access - - **Handoff**: responsibility moves to the receiving context -- Task detail shows the active contexts and the policy each one is using. +- Task status is numeric from `0` to `10`. +- `0` is the starting state. +- `10` is complete. +- Progress-oriented views sort tasks using status plus other ranking signals. +- Recurring tasks that are completed may show a progress ring while waiting to reopen. -### Buckets and Supervision +### Due Date, Urgency, Priority, and Size -- **My Bucket** is your personal home context. -- Pin buckets in Settings to make them appear in the context switcher. -- Supervision allows approved users to switch into another person's personal context. -- The context switcher can show: - - My Bucket - - pinned buckets - - supervised personal contexts -- Some system tags are intentionally hidden in the current view while still staying active behind the scenes. +- `Priority` and `Urgency` both influence ranking, but they are not the same thing. +- `Urgency` is closely tied to due date behavior. +- `Size` affects how some views rank or group work. +- The app calculates combined scores from these factors for several list views. +- Users often expect these values to be fully independent, but due date and urgency especially are coupled. -### Views and Finding Work +### Favorites -- **Focus**: default ranked view -- **Matrix**: urgency vs priority -- **Snowball**: smallest tasks first -- **Dig In**: largest tasks first -- **Urgency**: due-date pressure first -- **Priority**: importance first -- **Progress**: status/progress first -- Basic filters include: - - free-text search - - include/exclude tags - - priority range - - urgency range - - edited today - - mine - - starred +- Favoriting a task is personal to the current user. +- Internally, favorites are handled with hidden per-user tagging behavior. +- A task being starred by one person does not automatically mean it is starred for everyone else. -### Everyday Extras +### Task Deletion, Trash, and Auto-Maintenance -- **Trash** in Settings includes separate recovery areas for tasks and notes. -- **Mobile install**: - - Android: use Chrome's install or add-to-home-screen action. - - iPhone: use Safari's **Add to Home Screen**. -- If the app feels stale or out of sync, a quick refresh is the best first step. +- Deleting a task is a soft delete, not an immediate permanent delete. +- Soft-deleted tasks go into Trash for 7 days. +- The app usually offers an immediate undo prompt after deletion. +- Permanent recovery and permanent delete are available in `Settings > Trash`. +- Trash is automatically purged on app load when items have exceeded the 7-day retention window. ---- +TasGrid also performs maintenance-related auto-trash behavior: -## Advanced Features +- completed tasks older than 90 days are automatically moved to trash +- tasks with no active personal, shared, or note-linked context can be auto-trashed during initialization -### Advanced Views +These behaviors are important because a user may feel a task has disappeared when it has actually moved to Trash automatically. -- The same task pool can be viewed through different sort modes: - - Focus - - Urgency - - Priority - - Progress - - Snowball - - Dig In -- **Strategy Matrix** plots incomplete tasks on an urgency-vs-priority grid. - - Dots are clickable. - - Dot color reflects task size. - - Tooltips show the task title plus `U`, `S`, and `P` values. - - The time scale can be switched to `1`, `7`, `30`, `60`, or `90` days. +### Recurrence -### Notes Power Use - -- Root notes can have child tabs. -- Child tabs inherit the parent note's privacy setting. -- Desktop supports drag-and-drop tab reordering. -- Tabs can be renamed inline. -- Root notes manage the shared linked-task set. -- Renaming a note also updates the matching `#note` tag definition so linked tasks stay aligned. - -### Rich Editor - -- Tasks, notes, and templates all use the same editor. -- Type `/` to open slash commands, including: - - text and headings - - bullet lists - - checklists - - multi checklists - - code blocks - - blockquotes - - uploads - - job file embeds - - dividers - - tables -- The editor also supports: - - underline - - links - - highlight - - text alignment - - resizable tables - - `@user` mentions - - `#note` mentions -- Files can be pasted or dragged in directly. - - Images become image blocks. - - Videos become video blocks. - - Other files become file attachment blocks. -- Clicking an image opens a fullscreen zoomable preview. - -### Task Automation - -- Recurrence is configured from the task's **More** menu. -- Supported recurrence types: +- Tasks support recurring schedules. +- Supported recurrence types are: - daily - weekly - monthly -- Weekly recurrence supports selected weekdays. -- Monthly recurrence supports a day of the month. -- Completed recurring tasks automatically reopen when the next cycle arrives. +- Weekly recurrence requires selected days. +- Monthly recurrence depends on a valid day-of-month configuration. +- Completed recurring tasks do not stay permanently complete. TasGrid reopens them when their next recurrence window arrives. +- Reopen checks happen on startup and continue periodically while the app is running. -### Templates and Saved Filters +### Task Templates -- Task templates can store: - - name - - title +- Task templates let users store reusable task setups. +- Template fields include: + - template name + - title placeholder - priority - urgency - tags - - rich description -- Task templates are applied from Quick Entry. -- Task filters and note filters can both be saved as reusable templates. -- Use **Load All** when you need older history that is not currently loaded into the list. + - rich description/content +- Notably, task templates do not include: + - size + - explicit due date +- When a template is applied, due date is recalculated from urgency rather than copied as a fixed old date. -### Sharing and Context Policies +### Task Import -- User, bucket, and note contexts can each behave as **Collaborative** or **Handoff**. -- Settings lets you adjust: - - per-user context policy - - bucket policy - - supervision access -- `@user`, `@bucket`, and `#note` tags are not just labels. They create structured access and relationship rules. -- Some active context tags may be hidden in the current UI while still remaining attached to the task. +- Settings includes an `Import Tasks` tool for pasting in task lists. +- The import flow is: + 1. paste a task list + 2. review parsed tasks + 3. apply bulk defaults + 4. import +- The parser strips common list formatting such as: + - bullets + - checkboxes + - numbered-list prefixes +- Each non-empty line becomes one task. +- Users can bulk-apply: + - priority + - urgency + - size + - tags +- Users can still edit or remove individual rows before import. +- If no tags are provided, imported tasks default to `work`. +- Due date is derived from urgency on import just like normal task creation. -### Settings Deep Dive +## Task Views -- **Theme**: Light, Dark, or System -- **Tag List**: manage tag values and colors -- **Buckets**: - - create - - rename - - pin or unpin +### Focus + +- Focus is the main ranking-oriented list view. +- It sorts by a combined score using the task's importance and urgency characteristics. +- This is often the default working view for deciding what deserves attention next. + +### Urgency + +- Urgency emphasizes time pressure. +- It sorts by a continuous urgency score and then falls back to other ranking signals. +- It is helpful when due dates and near-term deadlines matter more than task size or stage. + +### Priority + +- Priority is intended as an importance-oriented lens. +- In the current implementation, it is not meaningfully different from Focus in the way tasks are sorted. +- This is an important documentation caveat because users may expect a completely different ranking. + +### Progress + +- Progress groups and ranks work based on completion state first, then other score factors. +- It is useful when users want to move partially completed work forward rather than start new tasks. + +### Snowball + +- Snowball sorts by smaller tasks first. +- It is the "quick wins" view. +- This is useful when users want momentum, cleanup, or rapid visible progress. + +### Dig In + +- Dig In sorts by larger tasks first. +- It is the "deep work" view. +- This is useful when users want to tackle heavier tasks rather than clear short items. + +### Matrix + +- Matrix shows tasks on an urgency-versus-priority grid instead of a simple ranked list. +- Matrix points are clickable and expose more detail on hover or selection. +- Matrix communicates multiple dimensions: + - placement reflects urgency and priority + - dot size reflects task size + - dot color communicates ranking/meaning in the current matrix logic +- Tooltips surface key values such as urgency, size, and priority. +- Matrix includes time-scale controls: + - `1` + - `7` + - `30` + - `60` + - `90` days +- Changing the time scale changes how the urgency side of the visualization is interpreted. + +## Search, Filters, and Saved Filters + +### Task Search and Filters + +- Task filtering supports: + - text query + - included tags + - priority ranges + - urgency ranges + - edited today + - mine + - starred +- Included tags use OR-style logic, not strict AND-only matching. +- Hidden system tags may not appear in the filter picker unless searched explicitly. +- `Mine` is based on personal-context access rules rather than just simplistic creator matching. + +### Saved Task Filters + +- Users can save the current task filter setup as a reusable filter template. +- Saved filters are managed from the filter/search area rather than from Settings. +- These are useful for repeat operational views like: + - follow-up work + - specific team contexts + - daily supervision checks + +### Note Filters + +- Notes also have filter templates, separate from task filter templates. +- They are managed in Notes mode through the note filter/search UI, not through Settings. + +### Load All + +- `Load All` is used when older completed or historical items are not currently loaded into the active store. +- This is especially relevant for search and filters because a task cannot be found if it has not been loaded into memory yet. +- Users may interpret missing search results as deletion when the actual issue is partial history loading. + +## Contexts, Sharing, Buckets, and Supervision + +### Context Types + +- TasGrid has three important context types: + - personal user contexts through `@person` + - shared bucket contexts through `@bucket` + - note contexts through `#note` +- These are system-backed contexts, not ordinary decorative tags. + +### My Bucket and Personal Contexts + +- Every user effectively has a personal working context. +- This is often represented in UI as `My Bucket`. +- Personal context affects what a user considers their own active work. +- Tasks can move into or out of a user's personal working space through context policies. + +### Context Switcher + +- The context switcher is how users move between available working spaces. +- It can show: + - `My Bucket` + - pinned shared buckets + - supervised personal contexts shared with the current user +- Desktop places this at the bottom of the sidebar. +- Mobile shows it through the floating control. + +### Shared Buckets + +- Shared buckets are team contexts created in Settings. +- A bucket includes: + - required name + - color + - optional description +- New buckets default to `handoff` policy. +- Bucket rows support: + - inline rename + - policy toggle + - pin/unpin - archive -- **Supervision**: choose who can switch into your personal context -- **Import Tasks**: paste lists, set bulk defaults, then fine-tune before import -- **Trash**: restore or permanently delete tasks and notes +- Archiving a bucket sets a deleted timestamp on the bucket context. +- There is no confirmed user-facing bucket restore flow at this time. -### App Maintenance +### Pinned Buckets -- TasGrid is a progressive web app and can be installed on mobile. -- The app checks for updates automatically while running and when it becomes visible again. -- **Update App** in Settings triggers the manual update flow. -- **Reset PWA** clears cached app state, unregisters service workers, and reloads the app. +- Pinning a bucket adds it to the context switcher. +- Pinning is stored in user preferences. +- When a bucket is pinned, TasGrid loads tasks already tagged with that bucket into the local task store. +- This matters because unpinned bucket work may not appear in the same way during task search or cross-linking flows. ---- +### Sharing Model -## Not Included Here +- TasGrid's main sharing workflow is tag-driven. +- Users share tasks by applying: + - an `@person` tag + - an `@bucket` tag + - a `#note` tag +- This is the primary sharing model. +- Documentation should not describe a separate manual share dialog as the main expected workflow. -- SDK or API integration-developer documentation -- Internal dev migration tools -- Internal admin repair or production migration workflows +### Collaborative vs Handoff ---- +- TasGrid uses two important context policies: + - `Collaborative` + - `Handoff` +- Collaborative means a task stays visible in both places as shared work. +- Handoff means responsibility shifts between contexts in a more directional way. +- Users can define personal user-tag policies in Settings. +- Buckets also carry a policy. +- These policies strongly affect whether a task feels shared, moved, or reassigned. -## Need More Help? +### Supervision -If TasGrid feels out of sync, refresh the app first. If you still need help, contact Timothy Cardoza or IT. +- Supervision lets one user enter another user's personal context. +- This is broader than sharing a single task. +- Personal Context Supervision settings let a user grant specific people permission to switch into that full personal context. +- `Personal Contexts Shared With You` lists supervised contexts the current user can access. +- Supervised contexts appear in the context switcher alongside buckets. + +### Hidden System Tags + +- Some system-backed context tags are intentionally hidden in normal UI. +- Hidden does not mean inactive. +- A task may still belong to a person, bucket, or note even when the user does not obviously see the matching context tag in normal task chips. +- This is one of the biggest sources of user confusion and should be treated as normal behavior rather than as data loss. + +### Context Effects on Task Creation and Visibility + +- Creating work from the current context usually applies that context automatically. +- Context affects what tasks a user can see in a given working view. +- If work appears to vanish after sharing, switching context, or linking to notes, the cause is often context visibility rather than deletion. +- Users should check: + - current context + - active filters + - trash + - whether the task belongs to an unpinned bucket + +## Notes + +### Notes Mode + +- Notes is a full working mode, not just an attached notes panel. +- Switching into Notes triggers note metadata loading. +- Desktop replaces the normal task sidebar with a notes sidebar. +- Mobile shows the notes list first, then opens the editor as a layered workspace. + +### Notes Sidebar + +- The main notes sidebar lists root notes only. +- Child tabs do not appear in the main sidebar list. +- The sidebar supports: + - title-and-tag search + - saved filters + - starred filter + - edited today filter + - owned by me filter + - Prism job note filters where applicable +- Notes are sorted by title descending, not by most recently updated. + +### Note Loading Model + +- Notes load in two stages: + - metadata first + - full content when the note is opened +- This allows the notes list to appear before every note body has loaded. +- If a note is visible in metadata but restricted by visibility rules, its content may fail to hydrate for the current user. + +### Creating Notes + +- Creating a note from the sidebar produces a root note with: + - title `New Note` + - empty content + - empty tags + - `isPrivate: false` + - a generated normalized key with a timestamp suffix + +### Editing Notes + +- Root note titles are editable inline in the note header. +- Selected child tabs can also be renamed inline. +- Note content auto-saves on a 500ms debounce. +- Leaving a note flushes pending saves immediately. + +### Deleting and Restoring Notes + +- Deleting a note is a soft delete. +- Soft delete: + - sets `deletedAt` + - removes current selection + - shows an Undo toast +- Restore is available from: + - the immediate Undo action + - `Settings > Trash` +- Permanent delete is exposed from `Settings > Trash`. +- Permanent deletion also removes note references from tasks by clearing: + - matching `#note` tag + - matching `noteRefs` + - matching note-based `shareRefs` + +### Public, Private, and Share Links + +- Notes can be public or private. +- Metadata loading exposes: + - public notes + - private notes owned by the current user +- Privacy, share-link, and delete controls are owner-only. +- Favorites can still be toggled from the note header. +- Share Link copies an embed URL like `#/embed/notes?noteId=...`. +- If a note is private when the share link is copied, TasGrid prompts the owner to make it public first. +- Public notes can be viewed through the embed route without normal auth when the note ID is present. +- Public notes are editable in-app by non-owners, but owner-only controls remain restricted. + +### Child Tabs + +- Root notes can have child tabs. +- Child tabs are separate note records tagged with `child-of-{rootId}`. +- The root note appears in the tab UI as `General`. +- Desktop shows tabs as draggable side ribbons. +- Mobile shows tabs in a dropdown. +- Tab order is stored through `taborder:{index}` tags. +- Dragging tabs updates those tags. +- Creating a tab makes a note with: + - title `New Tab` + - empty content + - empty linked tasks array + - `child-of-{rootId}` tag + - privacy copied from the root note at creation time + +Important privacy caveat: + +- child tabs inherit privacy when they are created +- later privacy changes on the root note do not automatically cascade back down to existing child tabs + +### Linked Tasks + +- Notes can act as project workspaces through a linked tasks panel. +- Linked tasks belong to the note workspace. +- If the user is inside a child tab, linked tasks resolve through the parent/root note workspace. +- A task counts as linked if either is true: + - it has a matching `noteRef` + - it has the matching `#note` tag +- Linked tasks are shown with incomplete items first, then ranked by combined score. + +Linked task actions include: + +- create a new task from the note +- search and link an existing task +- open a task from the linked task panel + +Linking constraints: + +- existing-task search returns nothing until the user types +- search matches task title only +- results are capped at 10 +- deleted tasks are excluded +- tasks from only unpinned buckets are excluded + +Current behavior caveats: + +- child tabs cannot directly unlink tasks +- unlink behavior is not perfectly consistent across every tag-linked path + +### Note Rename Propagation + +- Renaming a note updates both: + - the note title + - the normalized note key +- TasGrid also renames the corresponding `#note` tag definition after the note rename. +- This helps linked tasks continue to point to the correct note workspace after the name changes. + +## Rich Editor + +### Shared Editor Model + +- Tasks, notes, and task templates all use the same rich editor system. +- The editor supports both simple writing and structured embedded content. + +### Basic Content Types + +- Supported content includes: + - paragraphs + - headings 1 to 3 + - bullet lists + - checklists + - multi-checklists + - code blocks + - blockquotes + - horizontal rules + - links + - highlight + - underline + - text alignment + - tables + - images + - videos + - file attachments + - job file embeds + - `@user` mentions + - `#note` mentions + +### Toolbar and Slash Commands + +- The editor provides a persistent text formatting toolbar. +- When the cursor is inside a table, a table toolbar appears. +- The placeholder text is `Type '/' for commands or start writing...`. +- Typing `/` opens the slash command menu. + +Available slash commands include: + +- Text +- Heading 1 +- Heading 2 +- Heading 3 +- Bullet List +- Checklist +- Multi Checklist +- Code Block +- Blockquote +- Upload +- Job File +- Divider +- Table +- Delete Table + +- Slash command filtering is prefix-based against titles and aliases. +- The note header also provides shortcut buttons for `Commands` and `Upload`. + +### Mentions + +#### `@user` Mentions + +- `@user` suggestions come from user share contexts. +- The current user's own context is excluded from suggestion results. +- Matching is based on the start of the display name. +- In task detail, inserting an `@user` mention also applies the corresponding `@user` tag for sharing behavior. + +#### `#note` Mentions + +- `#note` suggestions include root notes only, not child tabs. +- Matching uses note key or title substring behavior. +- If note content is already loaded, the suggestion list can show a short preview. +- Clicking a `#note` mention opens a preview popover with: + - note title + - short content preview + - `Open Note` + +Current caveat: + +- in task detail, `Open Note` is wired to actual note navigation +- in the notes editor, the preview appears but `Open Note` is not fully wired through the Notes view + +### Uploads and Embedded Media + +- Upload flows are available through: + - the Upload button + - the slash menu + - paste + - drag and drop +- Uploading requires an active task or active note. + +Upload result behavior: + +- images become inline image blocks +- videos become inline video blocks +- other files become attachment blocks + +- Most image uploads are converted before upload. +- Explicit Upload command flows insert a blank paragraph afterward so the user can continue typing. +- Removing an embedded file or media block deletes it from the editor HTML. +- When leaving a note, TasGrid checks for orphaned uploads and removes no-longer-referenced files from storage. + +### Images + +- Images render as inline block nodes. +- They support: + - resize handle + - delete overlay + - fullscreen preview +- Fullscreen preview supports: + - zoom by click + - wheel zoom + - panning while zoomed + +### Videos + +- Videos render inline with: + - native playback controls + - resize handle + - delete overlay + +### File Attachments + +- PDFs and `.txt` files can render inline in an embedded viewer. +- Other file types show as attachment cards with filename and open-in-new-tab behavior. +- If the first content block in a note is a PDF attachment or a job file viewer, the note uses a top-viewer layout with a large embedded viewer area. + +### Tables + +- Tables are inserted as 3x3 by default with a header row. +- They are resizable and selectable as editor nodes. +- The table toolbar supports: + - insert row above + - insert row below + - delete row + - insert column left + - insert column right + - delete column + - merge cells + - split cell + - toggle header row + - delete table + +### Job File Embeds + +- The editor supports Prism job file embeds through the `/job file` command. +- If a job file block has not been configured yet, it shows a picker UI. +- The picker tries to infer a job from the active note or one of its ancestor notes using a `job_id:` tag. +- If no job is detected, the user can search `Job_Info_Prod` by: + - job number + - job name +- Exposed file categories include: + - `plans` + - `EST_and_CO` + - `Addendums` + - `files` +- Selecting a file stores: + - `jobId` + - `collectionId` + - `filename` +- The final embedded viewer uses the PocketBase file URL inside an iframe-style viewer. + +## Settings + +### Account Header + +- Settings shows the signed-in email at the top. +- It also includes: + - theme toggle + - `Sign Out` + +### Theme + +- The theme system supports: + - `light` + - `dark` + - `system` +- Theme preference is stored in local storage under `tasgrid-theme`. +- `system` is resolved from the browser or device `prefers-color-scheme`. +- The current Settings UI exposes only a visible light/dark toggle. +- Documentation should not promise a visible full theme selector with a dedicated system option unless that control is added later. + +### Sharing Settings + +- `Tag Sharing` explains the main context types: + - `@person` + - `@bucket` + - `#note` +- `User Tag Policies` lets users decide whether each personal user context behaves as: + - `Collaborative` + - `Handoff` +- This section reflects the current tag/context-based sharing model. + +### Supervision Settings + +- `Personal Context Supervision` lets a user grant specific people access to switch into that user's personal context. +- `Personal Contexts Shared With You` shows the contexts the current user can supervise. +- These settings are separate from normal task-by-task sharing because they apply to the whole context. + +### Shared Buckets Manager + +- `Shared Buckets` is the bucket management area. +- Users can: + - create buckets + - rename buckets + - pin buckets + - toggle bucket policy + - archive buckets +- Bucket creation requires a name and supports color plus optional description. + +### Tag Manager + +- `Tag List` is where users manage normal custom tag definitions. +- Users can: + - rename a custom tag + - recolor it + - rescore it from `0` to `10` + - delete it +- Renaming a tag propagates to tasks that use it. +- Deleting a tag removes it from tasks that use it. +- `System Tags (Users, Buckets & Notes)` is a separate expandable area. +- System tags are primarily reference/configuration artifacts tied to contexts and notes rather than standard freeform tags. + +### Templates Manager + +- `Task Templates` in Settings is the template management surface. +- Users can create, rename, edit, and delete templates there. +- Saved task and note filters are not managed in this section. + +### Trash + +- Trash contains separate lists for deleted tasks and deleted notes. +- Entries show the number of days remaining in the 7-day retention period. +- Each entry supports: + - recover + - permanent delete +- The Trash view is the main long-term recovery surface for deleted content. + +### Update App + +- `Update App` checks the service worker for updates. +- If an update is available, TasGrid reloads into the new version. +- If no update is found quickly, the app shows `No update found`. + +Background update behavior: + +- checks roughly hourly +- checks again when the window regains focus or visibility +- if an update is ready, it can apply automatically when the app is hidden or after about 10 minutes of idle time + +### Reset PWA + +- `Reset PWA` unregisters service workers, clears browser caches, and reloads the app. +- This is a repair tool for stale or broken cached app behavior. +- It should be used when the app seems out of sync, stale, or stuck, not as a normal daily action. + +## Progressive Web App Behavior + +### Installation + +- TasGrid is configured as a PWA with standalone display behavior. +- Installation is browser-driven. +- There is no confirmed custom in-app install prompt flow. +- Users should install using the browser's own `Install App` or `Add to Home Screen` controls. + +### Offline and Cached App Behavior + +- Like many PWAs, TasGrid can continue showing older cached assets until a service worker update is applied. +- `Update App` and `Reset PWA` exist to help recover from stale-client issues. + +## Important Constraints and User-Facing Caveats + +- Sharing is primarily tag-driven, not driven by a separate share dialog. +- Context tags may be hidden while still actively controlling task behavior. +- Creating work in the wrong active context can place it somewhere unexpected. +- Focus and Priority are not substantially different in current sorting behavior. +- Search is only as complete as the currently loaded data set. +- `Load All` may be necessary to find older completed work. +- Notes search does not search full note body text. It searches title and tags. +- The notes list does not include child tabs. +- Linking existing tasks from a note uses task title search only and returns at most 10 results. +- Task-link suggestions exclude tasks that belong only to unpinned buckets. +- Child note tabs inherit privacy only when created, not continuously afterward. +- Private note share links require the note to be made public before other users can view them. +- Trash is auto-purged after 7 days on app load. +- Completed tasks older than 90 days can be auto-moved to trash. +- Some tasks with no valid active context can also be auto-trashed. +- Bucket archive exists, but a confirmed user-facing bucket restore flow was not identified. +- In the notes editor, note mention previews exist, but `Open Note` from that preview is not fully wired through the same way it is in task detail. + +## Explicit Exclusions + +- SDK and API documentation +- integration-developer workflows +- dev-data migration tools +- production migration tools +- admin-only repair or maintenance flows +- inactive legacy settings UI hidden behind disabled conditions + +## Troubleshooting Checklist + +When a user thinks something is missing or not working, check these in order: + +1. Confirm whether they are in `Tasks` or `Notes`. +2. Confirm the active context in the context switcher. +3. Check active filters and whether a saved filter is still applied. +4. Use `Load All` if the issue may involve older items. +5. Check whether the item is in Trash. +6. Check whether the task belongs to an unpinned bucket or hidden system context. +7. For stale UI behavior, try `Update App`. +8. For persistent cache issues, use `Reset PWA`. + +## Summary for Future Help-Agent Use + +- The biggest mental models to preserve are: + - contexts are first-class behavior, not decorative tags + - notes are workspaces, not just text documents + - due date and urgency are linked + - hidden tags can still matter + - several views are ranking lenses over the same work pool + - retrieval issues are often context, filtering, or loading issues rather than actual data loss diff --git a/src/App.tsx b/src/App.tsx index 12da75d..76069a3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,11 +1,11 @@ -import { type Component, createSignal, onMount, onCleanup, createMemo, lazy, Suspense, Show } from 'solid-js'; +import { type Component, createSignal, onMount, onCleanup, createMemo, createEffect, lazy, Suspense, Show } from 'solid-js'; import { Layout } from './components/Layout'; import { EmbedLayout } from './components/EmbedLayout'; import { EmbedAuthWrapper } from './components/EmbedAuthWrapper'; import { CriticalView } from './views/CriticalView'; import { AuthCallback } from './components/Auth'; import { pb } from './lib/pocketbase'; -import { initStore } from './store'; +import { initStore, setStore } from './store'; // const CriticalView = lazy(() => import('./views/CriticalView').then(m => ({ default: m.CriticalView }))); const UrgencyView = lazy(() => import('./views/UrgencyView').then(m => ({ default: m.UrgencyView }))); @@ -16,19 +16,66 @@ const SnowballView = lazy(() => import('./views/SnowballView').then(m => ({ defa const DigInView = lazy(() => import('./views/DigInView').then(m => ({ default: m.DigInView }))); const ProgressView = lazy(() => import('./views/ProgressView').then(m => ({ default: m.ProgressView }))); const HelpView = lazy(() => import('./views/HelpView').then(m => ({ default: m.HelpView }))); +const AIHelpView = lazy(() => import('./views/AIHelpView').then(m => ({ default: m.AIHelpView }))); const NotepadView = lazy(() => import('./views/NotepadView').then(m => ({ default: m.NotepadView }))); const QuickEntryForm = lazy(() => import('./components/QuickEntryForm').then(m => ({ default: m.QuickEntryForm }))); const App: Component = () => { // Basic routing state const [currentView, setCurrentView] = createSignal("critical"); + const [lastNonAIView, setLastNonAIView] = createSignal("critical"); const [isAuthenticated, setIsAuthenticated] = createSignal(pb.authStore.isValid); const [location, setLocation] = createSignal(window.location.href); + const [isDesktop, setIsDesktop] = createSignal(window.matchMedia("(min-width: 768px)").matches); + + createEffect(() => { + const view = currentView(); + if (view !== "help_ai") { + setLastNonAIView(view); + } + }); + + const effectiveView = createMemo(() => + currentView() === "help_ai" && isDesktop() ? lastNonAIView() : currentView() + ); onMount(() => { - const handleLocChange = () => setLocation(window.location.href); + const mediaQuery = window.matchMedia("(min-width: 768px)"); + const openHelpGuide = (sectionId?: string) => { + const nextHash = sectionId ? `#help/${sectionId}` : "#help"; + if (window.location.hash !== nextHash) { + window.location.hash = nextHash; + } + setStore('isNotepadMode', false); + setCurrentView("help"); + window.dispatchEvent(new CustomEvent("taskgrid:help-target", { detail: { sectionId } })); + }; + + const openAIHelp = () => { + setStore('isNotepadMode', false); + setCurrentView("help_ai"); + }; + + const handleMediaChange = (event: MediaQueryListEvent) => { + setIsDesktop(event.matches); + }; + + const handleLocChange = () => { + setLocation(window.location.href); + + const hash = window.location.hash; + if (hash === "#help" || hash.startsWith("#help/")) { + setCurrentView("help"); + } + }; + + (window as any).setCurrentView = setCurrentView; + (window as any).openTasGridHelp = openHelpGuide; + (window as any).openTasGridAIHelp = openAIHelp; + window.addEventListener('popstate', handleLocChange); window.addEventListener('hashchange', handleLocChange); + mediaQuery.addEventListener('change', handleMediaChange); let isFirstRun = true; const removeListener = pb.authStore.onChange((token) => { @@ -43,8 +90,12 @@ const App: Component = () => { onCleanup(() => { removeListener(); + delete (window as any).setCurrentView; + delete (window as any).openTasGridHelp; + delete (window as any).openTasGridAIHelp; window.removeEventListener('popstate', handleLocChange); window.removeEventListener('hashchange', handleLocChange); + mediaQuery.removeEventListener('change', handleMediaChange); }); // Background preload of other views when idle @@ -59,6 +110,7 @@ const App: Component = () => { import('./views/DigInView'); import('./views/ProgressView'); import('./views/HelpView'); + import('./views/AIHelpView'); // Remove splash screen after high priority work is done const splash = document.getElementById('splash'); @@ -67,6 +119,8 @@ const App: Component = () => { setTimeout(() => splash.remove(), 500); } }); + + handleLocChange(); }); // Determine if we are in an embed route (check both path and hash for compatibility) @@ -96,17 +150,24 @@ const App: Component = () => { when={isEmbed()} fallback={ { }} />}> - + setCurrentView(currentView() === "help_ai" ? lastNonAIView() : "help_ai")} + hideQuickEntry={currentView() === "help_ai" && !isDesktop()} + >
}> - - - - - - - - - setCurrentView("settings")} /> + + + + + + + + + + setCurrentView("settings")} />
diff --git a/src/components/AIHelpPanel.tsx b/src/components/AIHelpPanel.tsx new file mode 100644 index 0000000..dffa3db --- /dev/null +++ b/src/components/AIHelpPanel.tsx @@ -0,0 +1,305 @@ +import { type Component, For, Show, createEffect, createMemo, createSignal } from "solid-js"; +import { Bot, LoaderCircle, RefreshCw, Send } from "lucide-solid"; +import { Button } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; +import { FIREWORKS_API_KEY, FIREWORKS_API_URL, FIREWORKS_HELP_MODEL } from "@/lib/app-config"; +import helpGuide from "../../docs/HELP_GUIDE.md?raw"; + +type ChatMessage = { + role: "user" | "assistant"; + content: string; +}; + +const SYSTEM_PROMPT = `You are the TasGrid AI Help assistant. + +You answer questions about TasGrid using the reference guide below. + +You must follow this instruction exactly: "use only this guide for all information and never assume you know something that isn't mentioned in the guide" + +If the guide does not contain the answer, say that the guide does not mention it. +Do not use outside product knowledge. +Do not invent buttons, workflows, settings, or behaviors. +Prefer concise, practical answers. +When helpful, mention the relevant section name from the guide. + +TASGRID REFERENCE GUIDE +${helpGuide}`; + +const SUGGESTED_PROMPTS = [ + "How does sharing work in TasGrid?", + "What is the difference between Handoff and Collaborative?", + "How do linked tasks and notes work together?", + "Why might a task disappear from my view?", + "How do recurrence and templates behave?" +]; + +const INITIAL_MESSAGE = "Ask about TasGrid features, workflows, or edge cases. I only answer from the reference guide, so if the guide does not mention something, I will tell you."; + +export const AIHelpPanel: Component<{ + variant?: "page" | "sidebar"; + class?: string; +}> = (props) => { + const variant = () => props.variant ?? "page"; + const [messages, setMessages] = createSignal([ + { role: "assistant", content: INITIAL_MESSAGE } + ]); + const [input, setInput] = createSignal(""); + const [isLoading, setIsLoading] = createSignal(false); + const [error, setError] = createSignal(null); + let messagesViewport: HTMLDivElement | undefined; + + const hasApiKey = createMemo(() => FIREWORKS_API_KEY.trim().length > 0); + + createEffect(() => { + messages(); + isLoading(); + queueMicrotask(() => { + messagesViewport?.scrollTo({ + top: messagesViewport.scrollHeight, + behavior: "smooth" + }); + }); + }); + + const submitQuestion = async (questionOverride?: string) => { + const question = (questionOverride ?? input()).trim(); + if (!question || isLoading()) return; + + const priorMessages = messages(); + const userMessage: ChatMessage = { role: "user", content: question }; + const nextMessages = [...priorMessages, userMessage]; + + setMessages(nextMessages); + setInput(""); + setError(null); + setIsLoading(true); + + if (!hasApiKey()) { + setMessages([ + ...nextMessages, + { + role: "assistant", + content: "AI Help is not configured yet. Add `VITE_FIREWORKS_API_KEY` to the app environment to enable Fireworks responses." + } + ]); + setIsLoading(false); + return; + } + + try { + const response = await fetch(FIREWORKS_API_URL, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${FIREWORKS_API_KEY}` + }, + body: JSON.stringify({ + model: FIREWORKS_HELP_MODEL, + reasoning_effort: "low", + temperature: 0.2, + max_tokens: 700, + messages: [ + { role: "system", content: SYSTEM_PROMPT }, + ...nextMessages.map(message => ({ + role: message.role, + content: message.content + })) + ] + }) + }); + + if (!response.ok) { + const bodyText = await response.text(); + throw new Error(bodyText || `Request failed with status ${response.status}`); + } + + const data = await response.json(); + const assistantText = data?.choices?.[0]?.message?.content?.trim(); + + if (!assistantText) { + throw new Error("The help assistant did not return any text."); + } + + setMessages(prev => [...prev, { role: "assistant", content: assistantText }]); + } catch (err) { + const message = err instanceof Error ? err.message : "Unknown error"; + setError(message); + setMessages(prev => [ + ...prev, + { + role: "assistant", + content: "I couldn't get a response from the help model just now. Try again in a moment." + } + ]); + } finally { + setIsLoading(false); + } + }; + + const resetChat = () => { + setMessages([{ role: "assistant", content: INITIAL_MESSAGE }]); + setInput(""); + setError(null); + }; + + const isSidebar = () => variant() === "sidebar"; + + return ( +
+
+
+ +

AI Help

+
+ +
+ +
+ + Add `VITE_FIREWORKS_API_KEY` to enable AI Help. The view is wired to Fireworks model `{FIREWORKS_HELP_MODEL}`. +
+ } + > +
+ + {(prompt) => ( + + )} + +
+ + +
+ + {(message) => ( +
+
+
+ You}> + + Guide Assistant + +
+
{message.content}
+
+
+ )} +
+ + +
+
+
+ + Guide Assistant +
+
+ + Looking through the guide... +
+
+
+
+
+ + + {(message) => ( +
+ Request error: {message()} +
+ )} +
+ +
{ + e.preventDefault(); + void submitQuestion(); + }} + > +