Skip to content

merge: sync upstream preview + worklog and custom-field fixes#9454

Closed
mohammad425 wants to merge 8 commits into
makeplane:previewfrom
webhead-GmbH:merge/upstream-sync
Closed

merge: sync upstream preview + worklog and custom-field fixes#9454
mohammad425 wants to merge 8 commits into
makeplane:previewfrom
webhead-GmbH:merge/upstream-sync

Conversation

@mohammad425

@mohammad425 mohammad425 commented Jul 21, 2026

Copy link
Copy Markdown

Description

Merges 44 upstream commits from makeplane/plane into the fork, and fixes four bugs found while verifying the result.

Upstream merge — the bulk is a large batch of security fixes (IDOR/query scoping, stored XSS via SVG attachments and comment HTML, ORM order_by/group_by injection, OAuth email verification, deactivated/bot login, invite token disclosure), plus dependency bumps and a ce/core/ consolidation.

That consolidation was the hard part: upstream deleted apps/web/ce entirely along with the @/plane-web/* path alias, and our time-tracker feature lived there. Resolution:

  • The 13 worklog components moved to core/components/issues/worklog/, and every @/plane-web/... import was rewritten to @/....
  • The ce IssueDetail wrapper (which added the worklog store to core's) no longer exists, so its store and delegating methods were folded directly into core/store/issue/issue-details/root.store.ts.
  • Kept our activity tab bar, which had replaced upstream's activity filter dropdown, plus the worklog and custom-field sidebar properties.
  • Dropped the ce-only stubs upstream deleted (WorkItemAdditionalSidebarProperties, WorkItemLayoutAdditionalProperties).

Bug fixes

  1. The empty worklog list showed the raw key common.activity_empty_state.no_worklogs. activity_empty_state sits at the root of common.json, not under its common object. The same class of bug affected three toasts calling t("common.error"), which resolves to an object rather than a string.
  2. Date and datetime custom fields accepted only fixed calendar dates for Earliest date, Latest date and Default value, which go stale. They now also accept a value relative to today (today+30d, today-1w, …), resolved on every render. Fixed dates pass through untouched, so existing fields are unaffected.
  3. Starting or stopping a timer updated the active-timer maps but never the per-issue running-timer list that the Worklogs Overview reads, so its stop button appeared or disappeared only after a tab switch or reload. Both paths now keep that list in sync, matching what adminStopTimer already did.
  4. The activity tab bar overflowed on narrow screens. It now scrolls on its own with a thin scrollbar, while the timer and log-work buttons stay pinned and collapse to icons so both remain reachable without scrolling the page.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • Feature (non-breaking change which adds functionality)
  • Improvement (change that would cause existing functionality to not work as expected)
  • Code refactoring
  • Performance improvements
  • Documentation update

Screenshots and Media (if applicable)

Activity tab bar at 420px — tabs scroll horizontally with a thin scrollbar; the start-timer and log-work buttons collapse to icons and stay in view.

Narrow-screen activity tab bar

Test Scenarios

Verified in the browser against the running app:

  • Merge: work item detail renders with the All / Activity / Comments / Worklogs / Custom Fields tabs and the Log work button; /worklogs/, /timer/, /active-timers/ and /custom-field-values/ all return 200, which exercises the store methods relocated out of ce. CRM Sync settings page still loads and Test Connection succeeds.
  • Bug 1: a work item with no worklogs shows "No worklogs yet" instead of the raw key.
  • Bug 2: created a date field with Latest date = relative, today + 30 days. Persisted as settings.max = "today+30d"; on the work item the native input rendered max="2026-08-20" against a system date of 2026-07-21.
  • Bug 3: with the Worklogs tab open, starting the timer immediately added the running row and stop control to Overview, and stopping it immediately removed them — no tab switch or reload.
  • Bug 4: at a 420px viewport the tab strip has its own horizontal scroll (scrollWidth 424 > clientWidth 257), the page itself does not scroll horizontally, and the log-work button stays fully in view.

Also clean: web check:types, oxlint (0 errors), Django manage.py check, and no migration drift. All test data created during verification was removed.

References

Upstream: makeplane/plane@7cef741c2 and the 43 commits before it on preview.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added work logging with start/stop timers, summaries, activity tabs, and tracked-time displays.
    • Added customizable fields for projects and work items, including multiple field types and admin controls.
    • Added CRM integration configuration, connection testing, manual and scheduled synchronization, and sync history.
    • Added workspace and project settings for controlling when timers can start.
  • Bug Fixes
    • Prevented issues with active timers from being marked complete.
    • Improved modal interaction to prevent unintended view closure.
  • Localization
    • Added English and German translations for the new features.

mohammad425 and others added 8 commits June 17, 2026 22:26
…trols

- Work item timers (start/stop) with live elapsed in the button and browser tab title
- Manual "Log work" with start/end datetime; editable worklog entries with delete confirmation
- Worklogs activity tab with a per-person totals overview and per-person filter
- State-gated timers: workspace default allowed states, overridable per project (admin configurable)
- Active-timer banner above the title showing who is currently working on the item
- Block moving an item to a completed state while a timer is running
- Admins can stop any user's timer and edit/delete any worklog; members only their own
- ModalCore marks its panel data-prevent-outside-click so dialogs don't close an underlying peek view

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
feat(worklog): time tracking with timers, worklogs, and admin controls
…and work items

Workspace admins can define typed custom fields (12 types: text, paragraph, number,
select, multi-select, boolean, radio, date, datetime, color, hyperlink, email) for
Projects and Work Items under a new Workspace Settings > Custom Fields category.

Backend:
- CustomField + CustomFieldValue models with entity_type discriminator (migration 0125/0126)
- Hard-delete values on field deletion; IDOR guard on issue values endpoint
- Endpoints: admin CRUD, active-fields (member-visible), project values, issue values
- Optimised serialisation (single many=True call instead of per-field loop)

Frontend:
- MobX store + SWR hook with shared cache key (Properties <-> Custom Fields tab sync)
- Settings management pages (Projects + Work Items) with create/edit/delete/reorder
- CustomFieldsSection: 12-column grid, required validation, default values
- Project create modal and General settings: custom fields persisted after save
- Work-item issue detail: Custom Fields tab (full editor) after Worklogs
- Properties sidebar (detail + peek): filled fields only, read-only with click-to-edit,
  hover pencil icon (admin-aware), ExternalLink for hyperlinks, colour circle display
- URL/Hyperlink: { url, text } shape with display text; non-editors click to open link

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…d custom-fields features

- Add 24 missing keys to common.json (worklog/time-tracking + custom_fields)
- Add full custom_fields section to workspace-settings.json (76 keys)
- Fix 4 untranslated keys (your_profile, developer, work_structure, execution)
- Fix brand-mark violation: pi_chat value corrected to "Plane AI"
- Fix workspace_dashboards typo ("Däschbords" → "Dashboards")
- Remove spurious `few` plural form from `member` key (de CLDR: one/other only)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
At the start of each month a Celery Beat task pushes the previous
month's logged hours per project into Perfex CRM as a task with an
"Invoice hours" custom field, enabling client billing.

Backend:
- CrmIntegration (per-workspace singleton, Fernet-encrypted API key)
  and CrmSyncLog models + migration 0127
- Workspace-admin endpoints under /workspaces/<slug>/crm-integration/
  (CRUD, test connection, manual sync, CRM field proxy, sync logs)
- Shared CrmApiClient with CRM_VERIFY_SSL setting
- monthly_crm_sync task (idempotent per month, per-issue hour
  breakdown, HTML-escaped descriptions) on Celery Beat

Frontend:
- New Integrations settings category with CRM Sync page (form,
  Test Connection, Sync Now, fetch CRM fields, sync history)
- en/de translations

The Perfex-side plane_api module (Bearer-auth REST endpoints, hashed
API keys, request logging) lives in the CRM codebase.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
feat(crm): monthly worklog sync to Perfex CRM
Brings in 44 upstream commits, mostly a large batch of security fixes
(IDOR/query scoping, stored XSS via SVG and comment HTML, ORM
order_by/group_by injection, OAuth email verification, deactivated and
bot user login, invite token disclosure), dependency bumps, and the
ce/ -> core/ store/component/hook consolidation.

Conflict resolution: upstream removed apps/web/ce entirely along with
the @/plane-web/* path alias, so our time-tracker files moved to their
core/ equivalents and every @/plane-web import was rewritten to @/.
The ce IssueDetail wrapper is gone, so its worklog store and delegating
methods were folded directly into core's IssueDetail. Kept our activity
tab bar (which replaced upstream's activity filter dropdown) and the
worklog and custom-field sidebar properties; dropped the ce-only stubs
upstream deleted (WorkItemAdditionalSidebarProperties,
WorkItemLayoutAdditionalProperties).

Verified: web check:types clean, oxlint 0 errors, Django check clean,
no migration drift.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…es, responsive tabs

- Empty worklog list rendered the raw key: activity_empty_state lives at the
  root of common.json, not under its `common` object. Same class of bug fixed
  in three toasts that used common.error, which is an object, not a string.

- Starting or stopping a timer only updated the active-timer maps, never the
  per-issue running-timer list the Worklogs overview reads, so its stop button
  appeared or vanished only after a tab switch or reload. Both now keep that
  list in sync, matching what adminStopTimer already did.

- Date and datetime custom fields accepted only fixed calendar dates for
  earliest/latest/default, which go stale. They now also accept a value
  relative to today (today+30d, today-1w, ...), resolved on every render.
  Fixed dates are untouched, so existing fields keep working.

- The activity tab bar overflowed on narrow screens. It now scrolls on its own
  with a thin scrollbar while the timer and log-work buttons stay pinned and
  collapse to icons, keeping both reachable without scrolling the page.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5a055cf2-2e82-403f-aded-bdb5389ed8a3

📥 Commits

Reviewing files that changed from the base of the PR and between 7cef741 and 5362ffd.

📒 Files selected for processing (115)
  • apps/api/Dockerfile.dev
  • apps/api/plane/app/serializers/__init__.py
  • apps/api/plane/app/serializers/crm_integration.py
  • apps/api/plane/app/serializers/custom_field.py
  • apps/api/plane/app/serializers/issue.py
  • apps/api/plane/app/urls/__init__.py
  • apps/api/plane/app/urls/crm_integration.py
  • apps/api/plane/app/urls/custom_field.py
  • apps/api/plane/app/urls/issue.py
  • apps/api/plane/app/views/__init__.py
  • apps/api/plane/app/views/crm_integration/base.py
  • apps/api/plane/app/views/custom_field/base.py
  • apps/api/plane/app/views/issue/base.py
  • apps/api/plane/app/views/issue/worklog.py
  • apps/api/plane/bgtasks/crm_sync_task.py
  • apps/api/plane/celery.py
  • apps/api/plane/db/migrations/0122_issueworklog.py
  • apps/api/plane/db/migrations/0123_project_worklog_timer_state_groups_and_more.py
  • apps/api/plane/db/migrations/0124_remove_issueworklog_unique_active_timer_per_user_and_more.py
  • apps/api/plane/db/migrations/0125_customfield_customfieldvalue_and_more.py
  • apps/api/plane/db/migrations/0126_customfieldvalue_issue_and_more.py
  • apps/api/plane/db/migrations/0127_crmintegration_crmsynclog.py
  • apps/api/plane/db/models/__init__.py
  • apps/api/plane/db/models/crm_integration.py
  • apps/api/plane/db/models/custom_field.py
  • apps/api/plane/db/models/issue.py
  • apps/api/plane/db/models/project.py
  • apps/api/plane/db/models/workspace.py
  • apps/api/plane/settings/common.py
  • apps/api/plane/utils/crm_client.py
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/crm-sync/header.tsx
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/crm-sync/page.tsx
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/custom-fields/projects/header.tsx
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/custom-fields/projects/page.tsx
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/custom-fields/work-items/header.tsx
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/custom-fields/work-items/page.tsx
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/(workspace)/page.tsx
  • apps/web/app/(all)/[workspaceSlug]/(settings)/settings/projects/[projectId]/page.tsx
  • apps/web/app/(all)/[workspaceSlug]/layout.tsx
  • apps/web/app/routes/core.ts
  • apps/web/core/components/crm-integration/crm-sync-root.tsx
  • apps/web/core/components/crm-integration/index.ts
  • apps/web/core/components/custom-fields/create-update-field-modal.tsx
  • apps/web/core/components/custom-fields/custom-field-input.tsx
  • apps/web/core/components/custom-fields/custom-field-value-display.tsx
  • apps/web/core/components/custom-fields/custom-fields-list-item.tsx
  • apps/web/core/components/custom-fields/custom-fields-list.tsx
  • apps/web/core/components/custom-fields/custom-fields-section.tsx
  • apps/web/core/components/custom-fields/date-setting-input.tsx
  • apps/web/core/components/custom-fields/delete-field-modal.tsx
  • apps/web/core/components/custom-fields/empty-state.tsx
  • apps/web/core/components/custom-fields/field-form.tsx
  • apps/web/core/components/custom-fields/field-type-icon.tsx
  • apps/web/core/components/custom-fields/index.ts
  • apps/web/core/components/custom-fields/issue-custom-fields-properties.tsx
  • apps/web/core/components/custom-fields/issue-custom-fields-tab.tsx
  • apps/web/core/components/custom-fields/management-root.tsx
  • apps/web/core/components/custom-fields/options-editor.tsx
  • apps/web/core/components/custom-fields/relative-date.ts
  • apps/web/core/components/issues/issue-detail/issue-activity/activity-tab-bar.tsx
  • apps/web/core/components/issues/issue-detail/issue-activity/helper.tsx
  • apps/web/core/components/issues/issue-detail/issue-activity/root.tsx
  • apps/web/core/components/issues/issue-detail/main-content.tsx
  • apps/web/core/components/issues/issue-detail/sidebar.tsx
  • apps/web/core/components/issues/issue-layouts/properties/all-properties.tsx
  • apps/web/core/components/issues/peek-overview/properties.tsx
  • apps/web/core/components/issues/worklog/active-timer-banner.tsx
  • apps/web/core/components/issues/worklog/activity/index.ts
  • apps/web/core/components/issues/worklog/activity/log-work-modal.tsx
  • apps/web/core/components/issues/worklog/activity/root.tsx
  • apps/web/core/components/issues/worklog/activity/worklog-create-button.tsx
  • apps/web/core/components/issues/worklog/activity/worklog-list.tsx
  • apps/web/core/components/issues/worklog/list-timer-button.tsx
  • apps/web/core/components/issues/worklog/property/index.ts
  • apps/web/core/components/issues/worklog/property/root.tsx
  • apps/web/core/components/issues/worklog/settings/project-timer-settings.tsx
  • apps/web/core/components/issues/worklog/settings/timer-states-field.tsx
  • apps/web/core/components/issues/worklog/settings/workspace-timer-settings.tsx
  • apps/web/core/components/issues/worklog/timer-title-sync.tsx
  • apps/web/core/components/issues/worklog/utils.ts
  • apps/web/core/components/power-k/ui/pages/work-item-selection-page.tsx
  • apps/web/core/components/project/settings/custom-fields.tsx
  • apps/web/core/components/projects/create/root.tsx
  • apps/web/core/components/settings/helper.ts
  • apps/web/core/components/settings/workspace/sidebar/item-icon.tsx
  • apps/web/core/hooks/store/use-custom-field.ts
  • apps/web/core/hooks/use-issue-custom-fields.ts
  • apps/web/core/hooks/use-issue-properties.tsx
  • apps/web/core/hooks/use-project-custom-field-values.ts
  • apps/web/core/hooks/use-worklog-timer-allowed.tsx
  • apps/web/core/services/crm-integration.service.ts
  • apps/web/core/services/custom-field.service.ts
  • apps/web/core/services/issue/index.ts
  • apps/web/core/services/issue/issue_worklog.service.ts
  • apps/web/core/store/issue/issue-details/activity.store.ts
  • apps/web/core/store/issue/issue-details/root.store.ts
  • apps/web/core/store/issue/issue-details/worklog.store.ts
  • apps/web/core/store/workspace/custom-field.store.ts
  • apps/web/core/store/workspace/index.ts
  • docker-compose-local.yml
  • packages/constants/src/custom-field/index.ts
  • packages/constants/src/index.ts
  • packages/constants/src/issue/filter.ts
  • packages/constants/src/settings/workspace.ts
  • packages/i18n/src/locales/de/common.json
  • packages/i18n/src/locales/de/workspace-settings.json
  • packages/i18n/src/locales/en/common.json
  • packages/i18n/src/locales/en/workspace-settings.json
  • packages/types/src/custom-field.ts
  • packages/types/src/index.ts
  • packages/types/src/issues/issue_worklog.ts
  • packages/types/src/project/projects.ts
  • packages/types/src/settings.ts
  • packages/types/src/workspace.ts
  • packages/ui/src/modals/modal-core.tsx

📝 Walkthrough

Walkthrough

Changes

The PR adds issue worklog and timer tracking, workspace/project custom fields, and CRM integration with scheduled monthly synchronization. It updates API models, routes, serializers, web stores/services/components, shared types/constants, settings navigation, translations, and local development configuration.

Worklog and timer tracking

Layer / File(s) Summary
Worklog persistence and API
apps/api/plane/db/models/..., apps/api/plane/app/views/issue/..., apps/api/plane/app/urls/issue.py
Adds worklog storage, timer lifecycle endpoints, active-timer queries, summaries, permission checks, and a guard against completing issues with running timers.
Web worklog state and controls
apps/web/core/store/issue/..., apps/web/core/services/issue/..., apps/web/core/components/issues/worklog/...
Adds client worklog state, timer controls, manual logging, editing/deletion, activity rendering, active-timer banners, sidebar properties, and title synchronization.
Timer configuration
apps/api/plane/db/models/project.py, apps/api/plane/db/models/workspace.py, apps/web/core/components/issues/worklog/settings/*
Adds workspace defaults and project overrides for timer-eligible state groups with corresponding settings UI.

Custom fields

Layer / File(s) Summary
Custom-field contracts and API
apps/api/plane/db/models/custom_field.py, apps/api/plane/app/serializers/custom_field.py, apps/api/plane/app/views/custom_field/*
Adds typed custom-field definitions, values, validation, admin-only filtering, project/work-item value APIs, and issue ownership checks.
Custom-field stores and services
apps/web/core/store/workspace/custom-field.store.ts, apps/web/core/services/custom-field.service.ts, apps/web/core/hooks/use-*-custom-field*.ts
Adds client-side definition/value fetching, CRUD operations, SWR synchronization, required-field validation, and project creation integration.
Custom-field UI
apps/web/core/components/custom-fields/*, apps/web/core/components/project/settings/custom-fields.tsx
Adds field forms, typed inputs, option/date editors, management lists, project settings, issue tabs, inline sidebar editing, and value display components.

CRM synchronization

Layer / File(s) Summary
CRM models and client
apps/api/plane/db/models/crm_integration.py, apps/api/plane/utils/crm_client.py, apps/api/plane/bgtasks/crm_sync_task.py
Adds encrypted CRM credentials, CRM HTTP operations, monthly worklog aggregation, task creation, invoice-hour updates, idempotency checks, and sync logs.
CRM API and settings
apps/api/plane/app/views/crm_integration/*, apps/web/core/services/crm-integration.service.ts, apps/web/core/components/crm-integration/*
Adds integration CRUD, connection testing, CRM field discovery, manual sync triggering, log retrieval, and the CRM settings interface.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • makeplane/plane#9433: Both changes modify issue state update handling in IssueViewSet.partial_update.

Suggested labels: ready to merge

Suggested reviewers: sriramveeraghanta, pablohashescobar

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Checkov (3.3.8)
apps/api/Dockerfile.dev

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

docker-compose-local.yml

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

packages/i18n/src/locales/de/common.json

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

  • 3 others

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@mohammad425

Copy link
Copy Markdown
Author

Opened by mistake against upstream — this targets our fork. Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants