|
65517
|
2308
|
7
|
2026-05-21T07:46:11.199478+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349571199_m1.jpg...
|
Slack
|
releases (Channel) - Jiminny Inc - 4 new items - S releases (Channel) - Jiminny Inc - 4 new items - Slack...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
happy_birthday
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Nikolay Yankov
Aneliya Angelova
Stoyan Tanev
James Graham
Stefka Stoyanova
Galya Dimitrova
Vasil Vasilev
Stoyan Tomov
Todor Stamatov
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Files
Files
Bookmarks
Bookmarks
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
GitHub
APP
Yesterday at 5:20:09 PM
5:20 PM
19 new commits
19 new commits
pushed to
master
master
by
nikolay-yankov
nikolay-yankov
6fae8bb2
6fae8bb2
- JY-20613 support owner role on setup team
b7df5604
b7df5604
- JY-20613 fix tests
2864624e
2864624e
- JY-20613 Add Owner Role field
d2d5ccca
d2d5ccca
- Merge branch 'JY-20613-allow-owner-role-on-team-setup' of
github.com:jiminny/app
github.com:jiminny/app
into JY-20613-allow-owner-role-on-team-setup
190239df
190239df
- Merge branch 'master' into JY-20613-allow-owner-role-on-team-setup
Show more
jiminny/app
jiminny/app
|
Added by
GitHub
GitHub
CircleCI
APP
Yesterday at 5:45:56 PM
5:45 PM
Deployment Successful! tada emoji
Deployment Successful!
Project
: app
When
: 05/20/2026 14:45:56
Tag
:
View Job
View Job
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Jump to date
New
GitHub
APP
Today at 10:44:15 AM
10:44 AM
6 new commits
6 new commits
pushed to
master
master
by
TodorStamatovJiminny
TodorStamatovJiminny
b6926974
b6926974
- JY-20947: fix twilio video downloads
f2f9ee6e
f2f9ee6e
- JY-20947: fix unit test, add constants
c73862ce
c73862ce
- JY-20947: fix tests
abf2f032
abf2f032
- JY-20947: add unit tests
e90ca7cd
e90ca7cd
- Merge branch 'master' into JY-20947-twilio-video-downloads
Show more
jiminny/app
jiminny/app
|
Added by
GitHub
GitHub
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Processing uploaded file… complete! Message ready to be sent.
Channel releases...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"happy_birthday","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tomov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Bookmarks","depth":17,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Bookmarks","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"GitHub","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"APP","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 5:20:09 PM","depth":22,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:20 PM","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"19 new commits","depth":22,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19 new commits","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"pushed to","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"master","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"master","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"by","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"nikolay-yankov","depth":22,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"nikolay-yankov","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"6fae8bb2","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6fae8bb2","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20613 support owner role on setup team","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"b7df5604","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"b7df5604","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20613 fix tests","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"2864624e","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2864624e","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20613 Add Owner Role field","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"d2d5ccca","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"d2d5ccca","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- Merge branch 'JY-20613-allow-owner-role-on-team-setup' of","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"github.com:jiminny/app","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"github.com:jiminny/app","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"into JY-20613-allow-owner-role-on-team-setup","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"190239df","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"190239df","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- Merge branch 'master' into JY-20613-allow-owner-role-on-team-setup","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Show more","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"jiminny/app","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"jiminny/app","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"|","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Added by","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"GitHub","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"GitHub","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"CircleCI","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"APP","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 5:45:56 PM","depth":22,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:45 PM","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"Deployment Successful! tada emoji","depth":22,"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"Deployment Successful!","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Project","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":": app","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"When","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":": 05/20/2026 14:45:56","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Tag","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":":","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"View Job","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"View Job","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"New","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"GitHub","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"APP","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 10:44:15 AM","depth":22,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:44 AM","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"6 new commits","depth":22,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6 new commits","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"pushed to","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"master","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"master","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"by","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"TodorStamatovJiminny","depth":22,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"TodorStamatovJiminny","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"b6926974","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"b6926974","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20947: fix twilio video downloads","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"f2f9ee6e","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"f2f9ee6e","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20947: fix unit test, add constants","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"c73862ce","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"c73862ce","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20947: fix tests","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"abf2f032","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"abf2f032","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20947: add unit tests","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"e90ca7cd","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"e90ca7cd","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- Merge branch 'master' into JY-20947-twilio-video-downloads","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Show more","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"jiminny/app","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"jiminny/app","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"|","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Added by","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"GitHub","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"GitHub","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":23,"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Processing uploaded file… complete! Message ready to be sent.","depth":11,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Channel releases","depth":11,"on_screen":true,"role_description":"text"}]...
|
2967908158313616818
|
7940291397176052831
|
idle
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
happy_birthday
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Nikolay Yankov
Aneliya Angelova
Stoyan Tanev
James Graham
Stefka Stoyanova
Galya Dimitrova
Vasil Vasilev
Stoyan Tomov
Todor Stamatov
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Files
Files
Bookmarks
Bookmarks
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
GitHub
APP
Yesterday at 5:20:09 PM
5:20 PM
19 new commits
19 new commits
pushed to
master
master
by
nikolay-yankov
nikolay-yankov
6fae8bb2
6fae8bb2
- JY-20613 support owner role on setup team
b7df5604
b7df5604
- JY-20613 fix tests
2864624e
2864624e
- JY-20613 Add Owner Role field
d2d5ccca
d2d5ccca
- Merge branch 'JY-20613-allow-owner-role-on-team-setup' of
github.com:jiminny/app
github.com:jiminny/app
into JY-20613-allow-owner-role-on-team-setup
190239df
190239df
- Merge branch 'master' into JY-20613-allow-owner-role-on-team-setup
Show more
jiminny/app
jiminny/app
|
Added by
GitHub
GitHub
CircleCI
APP
Yesterday at 5:45:56 PM
5:45 PM
Deployment Successful! tada emoji
Deployment Successful!
Project
: app
When
: 05/20/2026 14:45:56
Tag
:
View Job
View Job
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Jump to date
New
GitHub
APP
Today at 10:44:15 AM
10:44 AM
6 new commits
6 new commits
pushed to
master
master
by
TodorStamatovJiminny
TodorStamatovJiminny
b6926974
b6926974
- JY-20947: fix twilio video downloads
f2f9ee6e
f2f9ee6e
- JY-20947: fix unit test, add constants
c73862ce
c73862ce
- JY-20947: fix tests
abf2f032
abf2f032
- JY-20947: add unit tests
e90ca7cd
e90ca7cd
- Merge branch 'master' into JY-20947-twilio-video-downloads
Show more
jiminny/app
jiminny/app
|
Added by
GitHub
GitHub
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Processing uploaded file… complete! Message ready to be sent.
Channel releases
SlackFileEditViewGoHistoryWindowHelpscreelDOCKER0 81DEV (-zsh)₴2APP (-zsh)whisper_init_state:whisper_init_state:kv padsize=2.36 MBcompute buffer (conv)whisper_init_state: compute buffer (encode) =whisper_init_state: compute buffer (cross)=whisper_init_state:compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocatingwhisper_backend_init_gpu: device 0: Metal (type:1)whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)whisper_backend_init_gpu: using Metal backendggml_metal_init: allocatingggml_metal_init: found device: Apple M1ggml_metal_init: picking default device: Apple M1ggml_metal_init:use fusion= trueggml_metal_init:use concurrency= trueggml_metal_init: use graph optimizetruewhisper_backend_init: using BLAS backendwhisper_init_state: kv self size3.15 MBwhisper_init_state: kv cross size =9.44 MBwhisper_init_state: kv padsize =2.36 MBwhisper_init_state: compute buffer (conv)whisper_init_state: compute buffer (encode) =whisper_init_state: compute buffer (cross)=whisper_init_state: compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocatingwhisper_backend_init_gpu:device 0: Metal (type: 1)whisper_backend_init_gpu: found GPUdevice 0: Metal (type: 1, cnt: 0)whisper_backend_init_gpu: using Metal backendggml_metal_init: allocatingggml_metal_init: found device: Apple M1ggml_metal_init: picking default device: Apple M1ggml_metal_init:use fusion= trueggml_metal_init:use concurrencytrueggml_metal_init:use graph optimizetruewhisper_backend_init: using BLAS backendwhisper_init_state: kv self size3.15 MBwhisper_init_state: kv cross size =9.44 MBwhisper_init_state: kv padsize=2.36 MBwhisper_init_state: compute buffer (conv)whisper_init_state: compute buffer (encode) =whisper_init_state: compute buffer (cross)whisper_init_state: compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocating2026-05-21T10:13:41.913005ZINFO screenpipe_audio::audio_manager::manager: reconciliatior2026-05-21710:15:15.5768762INFO screenpipe_engine::event_driven_capture: content dedup:j Support Daily - in 4h 45 m100% С8• Thu 21 May 10:15:32•••EDQHomeDMsActivityFilesLater•••More+→Describe what you are looking forJiminny ...ThreadsC9 Unreadsà platform-inner-teamGalya Dimitrova, Nikolay Yankov, and youa ThreadsHuddles• Drafts & sentDirectories01External connections* Starred& jiminny-x-integrati...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# curiosity_lab# engineering# general# happy_birthday# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# supportLukas Kovalik 31 minutes agoдобро утро, тази страница не трябва ли да япоказваме само ако няма reportsCleanShot 2026-05-21 at [EMAIL] your questions into ongoing insightsGalya Dimitrova 23 minutes agoДа, би трябвалоLukas Kovalik 22 minutes agoче сега ми го показва и ако имам reportLukas Kovalik 21 minutes agoна neptuneNewNikolay Yankov 6 minutes agoвсичко е наредReply...Also send to à platform-inner-team+AaYou're up to date...
|
65515
|
NULL
|
NULL
|
NULL
|
|
65516
|
2309
|
8
|
2026-05-21T07:45:48.683765+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349548683_m2.jpg...
|
Slack
|
releases (Channel) - Jiminny Inc - 4 new items - S releases (Channel) - Jiminny Inc - 4 new items - Slack...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
happy_birthday
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Nikolay Yankov
Aneliya Angelova
Stoyan Tanev
James Graham
Stefka Stoyanova
Galya Dimitrova
Vasil Vasilev
Stoyan Tomov
Todor Stamatov
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Files
Files
Bookmarks
Bookmarks
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
GitHub
APP
Yesterday at 5:20:09 PM
5:20 PM
19 new commits
19 new commits
pushed to
master
master
by
nikolay-yankov
nikolay-yankov
6fae8bb2
6fae8bb2
- JY-20613 support owner role on setup team
b7df5604
b7df5604
- JY-20613 fix tests
2864624e
2864624e
- JY-20613 Add Owner Role field
d2d5ccca
d2d5ccca
- Merge branch 'JY-20613-allow-owner-role-on-team-setup' of
github.com:jiminny/app
github.com:jiminny/app
into JY-20613-allow-owner-role-on-team-setup
190239df
190239df
- Merge branch 'master' into JY-20613-allow-owner-role-on-team-setup
Show more
jiminny/app
jiminny/app
|
Added by
GitHub
GitHub
CircleCI
APP
Yesterday at 5:45:56 PM
5:45 PM
Deployment Successful! tada emoji
Deployment Successful!
Project
: app
When
: 05/20/2026 14:45:56
Tag
:
View Job
View Job
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Jump to date
New
GitHub
APP
Today at 10:44:15 AM
10:44 AM
6 new commits
6 new commits
pushed to
master
master
by
TodorStamatovJiminny
TodorStamatovJiminny
b6926974
b6926974
- JY-20947: fix twilio video downloads
f2f9ee6e
f2f9ee6e
- JY-20947: fix unit test, add constants
c73862ce
c73862ce
- JY-20947: fix tests
abf2f032
abf2f032
- JY-20947: add unit tests
e90ca7cd
e90ca7cd
- Merge branch 'master' into JY-20947-twilio-video-downloads
Show more
jiminny/app
jiminny/app
|
Added by
GitHub
GitHub
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Processing uploaded file… complete! Message ready to be sent.
Channel releases...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.0056515955,"top":0.058260176,"width":0.011968086,"height":0.028731046},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"bounds":{"left":0.0029920214,"top":0.10055866,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"bounds":{"left":0.0066489363,"top":0.13806863,"width":0.009973404,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.0029920214,"top":0.15482841,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"bounds":{"left":0.0076462766,"top":0.19233839,"width":0.007978723,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.0029920214,"top":0.20909816,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"bounds":{"left":0.004986702,"top":0.24660814,"width":0.012965426,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.005319149,"top":0.24660814,"width":0.0026595744,"height":0.011173184}},{"char_start":1,"char_count":7,"bounds":{"left":0.0076462766,"top":0.24660814,"width":0.010638298,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.0029920214,"top":0.26336792,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"bounds":{"left":0.0076462766,"top":0.3008779,"width":0.0076462766,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.007978723,"top":0.3008779,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.009973404,"top":0.3008779,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.0029920214,"top":0.31763768,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"bounds":{"left":0.00731383,"top":0.35514766,"width":0.008643617,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.00731383,"top":0.35514766,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.00930851,"top":0.35514766,"width":0.0066489363,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.0029920214,"top":0.3719074,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"bounds":{"left":0.006981383,"top":0.4094174,"width":0.008976064,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.00731383,"top":0.4094174,"width":0.0033244682,"height":0.011173184}},{"char_start":1,"char_count":3,"bounds":{"left":0.010638298,"top":0.4094174,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.042220745,"top":0.09177973,"width":0.025598405,"height":0.003990423},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.042220745,"top":0.103751,"width":0.015957447,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.103751,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.04488032,"top":0.103751,"width":0.013297873,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"happy_birthday","depth":23,"bounds":{"left":0.042220745,"top":0.12609737,"width":0.033909574,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.12609737,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":13,"bounds":{"left":0.045212764,"top":0.12609737,"width":0.030917553,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.042220745,"top":0.14844373,"width":0.022938829,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.14844373,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.043550532,"top":0.14844373,"width":0.021609042,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.042220745,"top":0.1707901,"width":0.034906916,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.1707901,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.045212764,"top":0.1707901,"width":0.031914894,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.042220745,"top":0.19313647,"width":0.03856383,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.19313647,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.045212764,"top":0.19313647,"width":0.03557181,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.042220745,"top":0.21548285,"width":0.01662234,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.21548285,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":5,"bounds":{"left":0.044215426,"top":0.21548285,"width":0.014960106,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.042220745,"top":0.23782921,"width":0.01761968,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.23782921,"width":0.0016622341,"height":0.014365523}},{"char_start":1,"char_count":7,"bounds":{"left":0.043882977,"top":0.23782921,"width":0.015957447,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.042220745,"top":0.2601756,"width":0.024268618,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.2601756,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.04454787,"top":0.2601756,"width":0.021941489,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.042220745,"top":0.28252193,"width":0.016954787,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.28252193,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.04454787,"top":0.28252193,"width":0.01462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.042220745,"top":0.3048683,"width":0.024268618,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.3048683,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.044215426,"top":0.3048683,"width":0.022606382,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.042220745,"top":0.3272147,"width":0.04488032,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.3272147,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":20,"bounds":{"left":0.044215426,"top":0.3272147,"width":0.04720745,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"bounds":{"left":0.042220745,"top":0.37988827,"width":0.032912236,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.37988827,"width":0.0039893617,"height":0.014365523}},{"char_start":1,"char_count":13,"bounds":{"left":0.046210106,"top":0.37988827,"width":0.028922873,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.042220745,"top":0.40223464,"width":0.03756649,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.40223464,"width":0.0033244682,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.045545213,"top":0.40223464,"width":0.034242023,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.042220745,"top":0.424581,"width":0.028922873,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.424581,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.04488032,"top":0.424581,"width":0.026263298,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.042220745,"top":0.44692737,"width":0.031914894,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.44692737,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.044215426,"top":0.44692737,"width":0.029920213,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.042220745,"top":0.46927375,"width":0.03756649,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.46927375,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.04488032,"top":0.46927375,"width":0.03523936,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.042220745,"top":0.49162012,"width":0.034906916,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.49162012,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":14,"bounds":{"left":0.045877658,"top":0.49162012,"width":0.03158245,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.042220745,"top":0.5139665,"width":0.026263298,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.5139665,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.045212764,"top":0.5139665,"width":0.023271276,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tomov","depth":23,"bounds":{"left":0.042220745,"top":0.5363129,"width":0.030585106,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.5363129,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.04488032,"top":0.5363129,"width":0.027925532,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"bounds":{"left":0.042220745,"top":0.5586592,"width":0.034242023,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.5586592,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":13,"bounds":{"left":0.04454787,"top":0.5586592,"width":0.031914894,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.042220745,"top":0.5810056,"width":0.02925532,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.5810056,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.04488032,"top":0.5810056,"width":0.026928192,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.07413564,"top":0.5810056,"width":0.0063164895,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.07446808,"top":0.5810056,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":2,"bounds":{"left":0.07679521,"top":0.5810056,"width":0.0056515955,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.042220745,"top":0.63367915,"width":0.011968086,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.63367915,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":4,"bounds":{"left":0.04488032,"top":0.63367915,"width":0.009640957,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.042220745,"top":0.6560255,"width":0.021609042,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.6560255,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.044215426,"top":0.6560255,"width":0.019946808,"height":0.014365523}}],"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.10206117,"top":0.09177973,"width":0.030585106,"height":0.030327214},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"bounds":{"left":0.111369684,"top":0.10055866,"width":0.01861702,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.111369684,"top":0.10055866,"width":0.0039893617,"height":0.012769354}},{"char_start":1,"char_count":7,"bounds":{"left":0.115359046,"top":0.10055866,"width":0.014960106,"height":0.012769354}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.13397606,"top":0.09177973,"width":0.020944148,"height":0.030327214},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"bounds":{"left":0.14328457,"top":0.10055866,"width":0.008976064,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.14328457,"top":0.10055866,"width":0.0026595744,"height":0.012769354}},{"char_start":1,"char_count":4,"bounds":{"left":0.14594415,"top":0.10055866,"width":0.0063164895,"height":0.012769354}}],"role_description":"text"},{"role":"AXRadioButton","text":"Bookmarks","depth":17,"bounds":{"left":0.15591756,"top":0.09177973,"width":0.033909574,"height":0.030327214},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Bookmarks","depth":19,"bounds":{"left":0.16522606,"top":0.10055866,"width":0.021941489,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.16555852,"top":0.10055866,"width":0.0029920214,"height":0.012769354}},{"char_start":1,"char_count":8,"bounds":{"left":0.16821809,"top":0.10055866,"width":0.019281914,"height":0.012769354}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.19115691,"top":0.09177973,"width":0.010638298,"height":0.030327214},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"bounds":{"left":0.096409574,"top":0.0518755,"width":0.015625,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"bounds":{"left":0.096409574,"top":0.0518755,"width":0.0076462766,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"bounds":{"left":0.096409574,"top":0.0518755,"width":0.013962766,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"bounds":{"left":0.14228724,"top":0.12689546,"width":0.032579787,"height":0.022346368},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"GitHub","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"APP","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 5:20:09 PM","depth":22,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:20 PM","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"19 new commits","depth":22,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19 new commits","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"pushed to","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"master","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"master","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"by","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"nikolay-yankov","depth":22,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"nikolay-yankov","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"6fae8bb2","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6fae8bb2","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20613 support owner role on setup team","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"b7df5604","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"b7df5604","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20613 fix tests","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"2864624e","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2864624e","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20613 Add Owner Role field","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"d2d5ccca","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"d2d5ccca","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- Merge branch 'JY-20613-allow-owner-role-on-team-setup' of","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"github.com:jiminny/app","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"github.com:jiminny/app","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"into JY-20613-allow-owner-role-on-team-setup","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"190239df","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"190239df","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- Merge branch 'master' into JY-20613-allow-owner-role-on-team-setup","depth":24,"bounds":{"left":0.12333777,"top":0.11572227,"width":0.084773935,"height":0.008778931},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.14527926,"top":0.075019956,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":67,"bounds":{"left":0.12333777,"top":0.075019956,"width":0.084773935,"height":0.049481247}}],"role_description":"text"},{"role":"AXButton","text":"Show more","depth":24,"bounds":{"left":0.12333777,"top":0.12609737,"width":0.024601065,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"jiminny/app","depth":24,"bounds":{"left":0.1299867,"top":0.14764565,"width":0.020611702,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"jiminny/app","depth":25,"bounds":{"left":0.1299867,"top":0.14764565,"width":0.020611702,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.1299867,"top":0.14764565,"width":0.0009973404,"height":0.011971269}},{"char_start":1,"char_count":10,"bounds":{"left":0.13098404,"top":0.14764565,"width":0.019614361,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"|","depth":24,"bounds":{"left":0.15026596,"top":0.14764565,"width":0.0033244682,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Added by","depth":24,"bounds":{"left":0.15325798,"top":0.14764565,"width":0.017952127,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.15359043,"top":0.14764565,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":7,"bounds":{"left":0.15625,"top":0.14764565,"width":0.013962766,"height":0.011971269}}],"role_description":"text"},{"role":"AXLink","text":"GitHub","depth":24,"bounds":{"left":0.17087767,"top":0.14764565,"width":0.012965426,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"GitHub","depth":25,"bounds":{"left":0.17087767,"top":0.14764565,"width":0.012965426,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.17121011,"top":0.14764565,"width":0.0029920214,"height":0.011971269}},{"char_start":1,"char_count":5,"bounds":{"left":0.17386968,"top":0.14764565,"width":0.010305851,"height":0.011971269}}],"role_description":"text"},{"role":"AXButton","text":"CircleCI","depth":22,"bounds":{"left":0.11801862,"top":0.1707901,"width":0.01761968,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"APP","depth":22,"bounds":{"left":0.13796543,"top":0.17478053,"width":0.0066489363,"height":0.009577015},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.14527926,"top":0.17238627,"width":0.0026595744,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 5:45:56 PM","depth":22,"bounds":{"left":0.14793883,"top":0.17478053,"width":0.015292553,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:45 PM","depth":23,"bounds":{"left":0.14793883,"top":0.17478053,"width":0.015292553,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.14793883,"top":0.17478053,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":6,"bounds":{"left":0.15026596,"top":0.17478053,"width":0.012965426,"height":0.011971269}}],"role_description":"text"},{"role":"AXHeading","text":"Deployment Successful! tada emoji","depth":22,"bounds":{"left":0.11801862,"top":0.1915403,"width":0.095744684,"height":0.017557861},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"Deployment Successful!","depth":24,"bounds":{"left":0.11801862,"top":0.19313647,"width":0.054853722,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.11801862,"top":0.19313647,"width":0.0039893617,"height":0.014365523}},{"char_start":1,"char_count":21,"bounds":{"left":0.12200798,"top":0.19313647,"width":0.049867023,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Project","depth":23,"bounds":{"left":0.11801862,"top":0.22027135,"width":0.015957447,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.11801862,"top":0.22027135,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.12101064,"top":0.22027135,"width":0.012965426,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":": app","depth":23,"bounds":{"left":0.11801862,"top":0.22027135,"width":0.017287234,"height":0.031923383},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.13397606,"top":0.22027135,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":4,"bounds":{"left":0.11801862,"top":0.23782921,"width":0.00831117,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"When","depth":23,"bounds":{"left":0.14926861,"top":0.22027135,"width":0.013630319,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":": 05/20/2026 14:45:56","depth":23,"bounds":{"left":0.14926861,"top":0.22027135,"width":0.024601065,"height":0.049481247},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.16289894,"top":0.22027135,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":20,"bounds":{"left":0.14926861,"top":0.23782921,"width":0.024933511,"height":0.031923383}}],"role_description":"text"},{"role":"AXStaticText","text":"Tag","depth":23,"bounds":{"left":0.11801862,"top":0.27294493,"width":0.0076462766,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.11801862,"top":0.27294493,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":2,"bounds":{"left":0.120678194,"top":0.27294493,"width":0.004986702,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":":","depth":23,"bounds":{"left":0.12533244,"top":0.27294493,"width":0.0016622341,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"View Job","depth":23,"bounds":{"left":0.11801862,"top":0.30167598,"width":0.023271276,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"View Job","depth":25,"bounds":{"left":0.12101064,"top":0.3056664,"width":0.017287234,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.12101064,"top":0.3064645,"width":0.0029920214,"height":0.012769354}},{"char_start":1,"char_count":7,"bounds":{"left":0.12400266,"top":0.3064645,"width":0.01462766,"height":0.012769354}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.12865691,"top":0.15722266,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.1392952,"top":0.15722266,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.14993352,"top":0.15722266,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16057181,"top":0.15722266,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17121011,"top":0.15722266,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.1818484,"top":0.15722266,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.21476063,"top":0.15722266,"width":0.0003324468,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.21476063,"top":0.15722266,"width":0.0003324468,"height":0.025538707},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"bounds":{"left":0.14594415,"top":0.3415802,"width":0.025265958,"height":0.022346368},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"New","depth":21,"bounds":{"left":0.20478724,"top":0.34557062,"width":0.00930851,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"GitHub","depth":22,"bounds":{"left":0.11801862,"top":0.37270552,"width":0.016289894,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"APP","depth":22,"bounds":{"left":0.13663563,"top":0.37669593,"width":0.0066489363,"height":0.009577015},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.14394946,"top":0.37430167,"width":0.0026595744,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 10:44:15 AM","depth":22,"bounds":{"left":0.14660904,"top":0.37669593,"width":0.01761968,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:44 AM","depth":23,"bounds":{"left":0.14660904,"top":0.37669593,"width":0.01761968,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.14660904,"top":0.37669593,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":7,"bounds":{"left":0.14893617,"top":0.37669593,"width":0.015625,"height":0.011971269}}],"role_description":"text"},{"role":"AXLink","text":"6 new commits","depth":22,"bounds":{"left":0.11801862,"top":0.39185953,"width":0.03324468,"height":0.014365523},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6 new commits","depth":23,"bounds":{"left":0.11801862,"top":0.39185953,"width":0.03324468,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"pushed to","depth":22,"bounds":{"left":0.15093085,"top":0.39185953,"width":0.024601065,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"master","depth":23,"bounds":{"left":0.1768617,"top":0.3942538,"width":0.014295213,"height":0.011971269},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"master","depth":24,"bounds":{"left":0.1768617,"top":0.3942538,"width":0.014295213,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"by","depth":22,"bounds":{"left":0.1924867,"top":0.39185953,"width":0.0066489363,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"TodorStamatovJiminny","depth":22,"bounds":{"left":0.11801862,"top":0.4094174,"width":0.04920213,"height":0.014365523},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"TodorStamatovJiminny","depth":23,"bounds":{"left":0.11801862,"top":0.4094174,"width":0.04920213,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"b6926974","depth":25,"bounds":{"left":0.124667555,"top":0.43575418,"width":0.019281914,"height":0.011971269},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"b6926974","depth":26,"bounds":{"left":0.124667555,"top":0.43575418,"width":0.019281914,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20947: fix twilio video downloads","depth":24,"bounds":{"left":0.12333777,"top":0.43335995,"width":0.08178192,"height":0.031923383},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"f2f9ee6e","depth":25,"bounds":{"left":0.124667555,"top":0.4708699,"width":0.019281914,"height":0.011971269},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"f2f9ee6e","depth":26,"bounds":{"left":0.124667555,"top":0.4708699,"width":0.019281914,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20947: fix unit test, add constants","depth":24,"bounds":{"left":0.12333777,"top":0.46847567,"width":0.08510638,"height":0.031923383},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"c73862ce","depth":25,"bounds":{"left":0.124667555,"top":0.5059856,"width":0.019281914,"height":0.011971269},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"c73862ce","depth":26,"bounds":{"left":0.124667555,"top":0.5059856,"width":0.019281914,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20947: fix tests","depth":24,"bounds":{"left":0.14494681,"top":0.50359136,"width":0.045212764,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"abf2f032","depth":25,"bounds":{"left":0.124667555,"top":0.5235435,"width":0.019281914,"height":0.011971269},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"abf2f032","depth":26,"bounds":{"left":0.124667555,"top":0.5235435,"width":0.019281914,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20947: add unit tests","depth":24,"bounds":{"left":0.14494681,"top":0.5211492,"width":0.057845745,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"e90ca7cd","depth":25,"bounds":{"left":0.124667555,"top":0.54110134,"width":0.019281914,"height":0.011971269},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"e90ca7cd","depth":26,"bounds":{"left":0.124667555,"top":0.54110134,"width":0.019281914,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- Merge branch 'master' into JY-20947-twilio-video-downloads","depth":24,"bounds":{"left":0.12333777,"top":0.5387071,"width":0.084773935,"height":0.031923383},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Show more","depth":24,"bounds":{"left":0.12333777,"top":0.57222664,"width":0.024601065,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"jiminny/app","depth":24,"bounds":{"left":0.1299867,"top":0.5937749,"width":0.020611702,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"jiminny/app","depth":25,"bounds":{"left":0.1299867,"top":0.5937749,"width":0.020611702,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"|","depth":24,"bounds":{"left":0.15026596,"top":0.5937749,"width":0.0033244682,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Added by","depth":24,"bounds":{"left":0.15325798,"top":0.5937749,"width":0.017952127,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"GitHub","depth":24,"bounds":{"left":0.17087767,"top":0.5937749,"width":0.012965426,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"GitHub","depth":25,"bounds":{"left":0.17087767,"top":0.5937749,"width":0.012965426,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.12865691,"top":0.35913807,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.1392952,"top":0.35913807,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.14993352,"top":0.35913807,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16057181,"top":0.35913807,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17121011,"top":0.35913807,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.1818484,"top":0.35913807,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.21476063,"top":0.35913807,"width":0.0003324468,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.21476063,"top":0.35913807,"width":0.0003324468,"height":0.025538707},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":23,"bounds":{"left":0.10372341,"top":0.6272945,"width":0.109707445,"height":0.030327214},"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Processing uploaded file… complete! Message ready to be sent.","depth":11,"bounds":{"left":0.0,"top":0.7126895,"width":0.022606382,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Channel releases","depth":11,"bounds":{"left":0.0,"top":0.7126895,"width":0.017287234,"height":0.0007980846},"on_screen":true,"role_description":"text"}]...
|
2967908158313616818
|
7940291397176052831
|
idle
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
happy_birthday
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Nikolay Yankov
Aneliya Angelova
Stoyan Tanev
James Graham
Stefka Stoyanova
Galya Dimitrova
Vasil Vasilev
Stoyan Tomov
Todor Stamatov
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Files
Files
Bookmarks
Bookmarks
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
GitHub
APP
Yesterday at 5:20:09 PM
5:20 PM
19 new commits
19 new commits
pushed to
master
master
by
nikolay-yankov
nikolay-yankov
6fae8bb2
6fae8bb2
- JY-20613 support owner role on setup team
b7df5604
b7df5604
- JY-20613 fix tests
2864624e
2864624e
- JY-20613 Add Owner Role field
d2d5ccca
d2d5ccca
- Merge branch 'JY-20613-allow-owner-role-on-team-setup' of
github.com:jiminny/app
github.com:jiminny/app
into JY-20613-allow-owner-role-on-team-setup
190239df
190239df
- Merge branch 'master' into JY-20613-allow-owner-role-on-team-setup
Show more
jiminny/app
jiminny/app
|
Added by
GitHub
GitHub
CircleCI
APP
Yesterday at 5:45:56 PM
5:45 PM
Deployment Successful! tada emoji
Deployment Successful!
Project
: app
When
: 05/20/2026 14:45:56
Tag
:
View Job
View Job
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Jump to date
New
GitHub
APP
Today at 10:44:15 AM
10:44 AM
6 new commits
6 new commits
pushed to
master
master
by
TodorStamatovJiminny
TodorStamatovJiminny
b6926974
b6926974
- JY-20947: fix twilio video downloads
f2f9ee6e
f2f9ee6e
- JY-20947: fix unit test, add constants
c73862ce
c73862ce
- JY-20947: fix tests
abf2f032
abf2f032
- JY-20947: add unit tests
e90ca7cd
e90ca7cd
- Merge branch 'master' into JY-20947-twilio-video-downloads
Show more
jiminny/app
jiminny/app
|
Added by
GitHub
GitHub
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Processing uploaded file… complete! Message ready to be sent.
Channel releases
slackFV [EMAIL]=.phounit.result.cacheE .prettierignore= windsurtrulesphpde neloer.onophpide heloer_models.ohophp artisanM'CLAUDE.mdcomooser.isoncomooser.lockdependency-checker.json8 dev ison= ids tytl=infection.ison.distMLINSTAlI.mdMLINTERNAI WERHOOK SFTUP mdEjiminny_storageMiliconsos mdllM Makefile1рackace-lock. sonE phpstan.neon.dist= phostan-baseline.neon<> phpunit.xmlTe raw sal query.saM+ README.mdsô sonar-proiect propertiesE test.ov‹> Untitled Diaaram.xmliusvetur.confio.isM+ WEBHOOK FILTERING_IMPLEMENTATION.mo>1h External Librariesv =° Scratches and Consolesv batabase Consolesv AEU# console (EUlI DEAL RISKS (SU1A DITEUlA EU (EU]v Ajiminny@localhostA console (jiminny@localhost]# Di [liminny@localhostlA HS local [iiminny@localhostlA SF ['iiminny@localhost]& zoho dev [iiminny@localhost]V & PRODA console [PROD]& console 1 [PROD1LDIIPRODCActivityController.ong© ConvertLeadActivities.php= laravel.log4 SF jiminny@localhost]4 HS_local [jiminny@localhost]& console (PROD] X# console [euyLeadkepository.ong© PurgeLookupCache.php© SyncPlanhat.phpo synerorlannatpnpA console [STAGING]AcuivityLeadConverted.php© UserAutomatedreporscontroller.phpx© PlaybackController.php)Inteqrationapp/service.onoC) LeadConverted.ono570571C) CreateCommentedEvent.php(C) CreateSmsSentEvent.phpC) PlanhatActivityListener.php© AskAnythingPromptService.php572(C) AutomatedReportsRepositorv.php© AutomatedReportsCommand.phpphp api_v2.phpC) RequestGenerateReportJob.php573574© AutomatedReportResult.php(C) AutomatedReport.oho575use Jiminny \Services \Kiosk \AutomatedReports \ReportSortDirection;A1422 ^ v 576use Jiminny \Services\PlanhatService;use ectumtnace hutp kequestuse Inrowable,class UserAutomatedReportsController extends Controllenpublic const int RESULTS PER_ PAGE = 25:public const string SORT COLUMN = 'sort column':public const strina SORT DIRECTION = "sort direction':public function constructprivate readonly AutomatedReportsRepository $automatedReportsRepository.private readonly AutomatedRenortsService SautomatedRenortsServicelorivate readoni.v AniResponseService samiResponseServi.ce.orivate readoni.v Resnonse Sresnonse.private readonly PlanhatService $planhatService1...poST lanilv1lautomated-renorts/interest 1usadepublic function trackInterest(Request $request): JsonResponse(...}* Othnows ApplicationException58(09 >GET /api/v1/automated-reportspublic function list(Request Srequest): JsonResponse(...}125 0)DELETE/api/vl/automated-reports/kuuidpublic function delete(Request Srequest. string Suuid): JsonResponsef...} -609610--611612613616Tx: AutovSo jiminny vCONCAT(u.id, CASE WHEN U.id = t.owner_id THEN' (owner)' ELSE'' END) AS USEr_i041 A1 A40 V65 ^sa.*t.owner_id FROM social_accounts saNoun usens u on u.ide sa.sociablle 1diJOIN teams t 1..n<->1: on t.id = u.team_idWHERE u.team_id = 581 and sa.provider = 'salesforce';SELECT * FROM automated_report_results order by id desc;select * from features;select * from team_features where feature_id = 40;select * from teams where id = 556:select * trom automated reports:where id = 54: # 4fdd41f6-dcf0-30d0-b339-7345381b6044|"pat", "podcast"SELECT * FROM automated report results WHERE uuid to bin( '822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;select * from automated_report_results order by id desc;SELECT * FROMWHERE id = 1919:select * fromautomated report results WHERE report id = 54:select * from opportunities where id = 7594349:SELECT * FROM teams WHERE name LIKE '%Lesg': # 711. 692. [EMAIL] * from playbooks where team_id = 711; # event 226147SELEd * FROM Dlavbook catedonies WHERE Dlavbook 1d = 55151SELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event':SELECT * SROM eom fields WHEREI1d = 2261471SELECT * FROM crm_field_values WHERE crm_field_id = 226147;SELECT * FROM crm_configurations WHERE id = 692;SELSCTCONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '• END) AS user_id,v.emailsa.*,t.owner id FROM social accounts saJOIN users u on v.id = sa.sociable idJOIN teams t 1..n<->1: on t.id = u.team idWHERE U.team_id = 711 and sa.provider = 'salesforce";SELECT * FROM crm profiles cp JOIN users u 1..n<->1: on u.id = co.user id WHERE u.team_id = 711:select * from leadsselect * from calendarsSELECTS 0 hllsupoont Dally • In 4h 40m100% 52• Inu z1 May 10.10.34AskJiminnyReportActivityServiceTestvCascadePlaybook Categorie+0 ..connected. How isi. Can we vali eoneactivity tyee nith orit cabest aeeiewmane o, W dati anwsyggesinsingrow hohow to distinguishThoughts68 Fast Context How are playbook_categories populated and synced from crm_fields / crm_field_values... in 4.14s >Explored 4 files and searched 5 queriesRead ImportActivitvTypes.php #L95-104Searched olavbook cateaories in databaselmiarations (4) >egories|playbook_categories.*create in database/migrations (0)searched playoook_categor in database/migrations (<)Searched activity type in database/migrations (4)SurtingAsk anvthina (*4L)@ Codo Caudo Onue 17 ModiumNN Windeurf Toame 504.60...
|
65514
|
NULL
|
NULL
|
NULL
|
|
65515
|
2308
|
6
|
2026-05-21T07:45:40.541861+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349540541_m1.jpg...
|
Slack
|
releases (Channel) - Jiminny Inc - 4 new items - S releases (Channel) - Jiminny Inc - 4 new items - Slack...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
happy_birthday
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Nikolay Yankov
Aneliya Angelova
Stoyan Tanev
James Graham
Stefka Stoyanova
Galya Dimitrova
Vasil Vasilev
Stoyan Tomov
Todor Stamatov
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Files
Files
Bookmarks
Bookmarks
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
GitHub
APP
Yesterday at 5:20:09 PM
5:20 PM
19 new commits
19 new commits
pushed to
master
master
by
nikolay-yankov
nikolay-yankov
6fae8bb2
6fae8bb2
- JY-20613 support owner role on setup team
b7df5604
b7df5604
- JY-20613 fix tests
2864624e
2864624e
- JY-20613 Add Owner Role field
d2d5ccca
d2d5ccca
- Merge branch 'JY-20613-allow-owner-role-on-team-setup' of
github.com:jiminny/app
github.com:jiminny/app
into JY-20613-allow-owner-role-on-team-setup
190239df
190239df
- Merge branch 'master' into JY-20613-allow-owner-role-on-team-setup
Show more
jiminny/app
jiminny/app
|
Added by
GitHub
GitHub
CircleCI
APP
Yesterday at 5:45:56 PM
5:45 PM
Deployment Successful! tada emoji
Deployment Successful!
Project
: app
When
: 05/20/2026 14:45:56
Tag
:
View Job
View Job
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Jump to date
New
GitHub
APP
Today at 10:44:15 AM
10:44 AM
6 new commits
6 new commits
pushed to
master
master
by
TodorStamatovJiminny
TodorStamatovJiminny
b6926974
b6926974
- JY-20947: fix twilio video downloads
f2f9ee6e
f2f9ee6e
- JY-20947: fix unit test, add constants
c73862ce
c73862ce
- JY-20947: fix tests
abf2f032
abf2f032
- JY-20947: add unit tests
e90ca7cd
e90ca7cd
- Merge branch 'master' into JY-20947-twilio-video-downloads
Show more
jiminny/app
jiminny/app
|
Added by
GitHub
GitHub
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Processing uploaded file… complete! Message ready to be sent.
Channel releases...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"happy_birthday","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tomov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Bookmarks","depth":17,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Bookmarks","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"GitHub","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"APP","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 5:20:09 PM","depth":22,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:20 PM","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"19 new commits","depth":22,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19 new commits","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"pushed to","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"master","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"master","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"by","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"nikolay-yankov","depth":22,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"nikolay-yankov","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"6fae8bb2","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6fae8bb2","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20613 support owner role on setup team","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"b7df5604","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"b7df5604","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20613 fix tests","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"2864624e","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2864624e","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20613 Add Owner Role field","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"d2d5ccca","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"d2d5ccca","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- Merge branch 'JY-20613-allow-owner-role-on-team-setup' of","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"github.com:jiminny/app","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"github.com:jiminny/app","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"into JY-20613-allow-owner-role-on-team-setup","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"190239df","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"190239df","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- Merge branch 'master' into JY-20613-allow-owner-role-on-team-setup","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Show more","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"jiminny/app","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"jiminny/app","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"|","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Added by","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"GitHub","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"GitHub","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"CircleCI","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"APP","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 5:45:56 PM","depth":22,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:45 PM","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"Deployment Successful! tada emoji","depth":22,"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"Deployment Successful!","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Project","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":": app","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"When","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":": 05/20/2026 14:45:56","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Tag","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":":","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"View Job","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"View Job","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"New","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"GitHub","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"APP","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 10:44:15 AM","depth":22,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:44 AM","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"6 new commits","depth":22,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6 new commits","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"pushed to","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"master","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"master","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"by","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"TodorStamatovJiminny","depth":22,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"TodorStamatovJiminny","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"b6926974","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"b6926974","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20947: fix twilio video downloads","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"f2f9ee6e","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"f2f9ee6e","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20947: fix unit test, add constants","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"c73862ce","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"c73862ce","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20947: fix tests","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"abf2f032","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"abf2f032","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20947: add unit tests","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"e90ca7cd","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"e90ca7cd","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- Merge branch 'master' into JY-20947-twilio-video-downloads","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Show more","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"jiminny/app","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"jiminny/app","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"|","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Added by","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"GitHub","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"GitHub","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":23,"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Processing uploaded file… complete! Message ready to be sent.","depth":11,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Channel releases","depth":11,"on_screen":true,"role_description":"text"}]...
|
2967908158313616818
|
7940291397176052831
|
idle
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
happy_birthday
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Nikolay Yankov
Aneliya Angelova
Stoyan Tanev
James Graham
Stefka Stoyanova
Galya Dimitrova
Vasil Vasilev
Stoyan Tomov
Todor Stamatov
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Files
Files
Bookmarks
Bookmarks
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
GitHub
APP
Yesterday at 5:20:09 PM
5:20 PM
19 new commits
19 new commits
pushed to
master
master
by
nikolay-yankov
nikolay-yankov
6fae8bb2
6fae8bb2
- JY-20613 support owner role on setup team
b7df5604
b7df5604
- JY-20613 fix tests
2864624e
2864624e
- JY-20613 Add Owner Role field
d2d5ccca
d2d5ccca
- Merge branch 'JY-20613-allow-owner-role-on-team-setup' of
github.com:jiminny/app
github.com:jiminny/app
into JY-20613-allow-owner-role-on-team-setup
190239df
190239df
- Merge branch 'master' into JY-20613-allow-owner-role-on-team-setup
Show more
jiminny/app
jiminny/app
|
Added by
GitHub
GitHub
CircleCI
APP
Yesterday at 5:45:56 PM
5:45 PM
Deployment Successful! tada emoji
Deployment Successful!
Project
: app
When
: 05/20/2026 14:45:56
Tag
:
View Job
View Job
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Jump to date
New
GitHub
APP
Today at 10:44:15 AM
10:44 AM
6 new commits
6 new commits
pushed to
master
master
by
TodorStamatovJiminny
TodorStamatovJiminny
b6926974
b6926974
- JY-20947: fix twilio video downloads
f2f9ee6e
f2f9ee6e
- JY-20947: fix unit test, add constants
c73862ce
c73862ce
- JY-20947: fix tests
abf2f032
abf2f032
- JY-20947: add unit tests
e90ca7cd
e90ca7cd
- Merge branch 'master' into JY-20947-twilio-video-downloads
Show more
jiminny/app
jiminny/app
|
Added by
GitHub
GitHub
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Processing uploaded file… complete! Message ready to be sent.
Channel releases
SlackFileEditViewGoHistoryWindowHelpscreelDOCKER0 81DEV (-zsh)₴2APP (-zsh)whisper_init_state:whisper_init_state:kv padsize=2.36 MBcompute buffer (conv)whisper_init_state: compute buffer (encode) =whisper_init_state: compute buffer (cross)=whisper_init_state:compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocatingwhisper_backend_init_gpu: device 0: Metal (type:1)whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)whisper_backend_init_gpu: using Metal backendggml_metal_init: allocatingggml_metal_init: found device: Apple M1ggml_metal_init: picking default device: Apple M1ggml_metal_init:use fusion= trueggml_metal_init:use concurrency= trueggml_metal_init: use graph optimizetruewhisper_backend_init: using BLAS backendwhisper_init_state: kv self size3.15 MBwhisper_init_state: kv cross size =9.44 MBwhisper_init_state: kv padsize =2.36 MBwhisper_init_state: compute buffer (conv)whisper_init_state: compute buffer (encode) =whisper_init_state: compute buffer (cross)=whisper_init_state: compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocatingwhisper_backend_init_gpu:device 0: Metal (type: 1)whisper_backend_init_gpu: found GPUdevice 0: Metal (type: 1, cnt: 0)whisper_backend_init_gpu: using Metal backendggml_metal_init: allocatingggml_metal_init: found device: Apple M1ggml_metal_init: picking default device: Apple M1ggml_metal_init:use fusion= trueggml_metal_init:use concurrencytrueggml_metal_init:use graph optimizetruewhisper_backend_init: using BLAS backendwhisper_init_state: kv self size3.15 MBwhisper_init_state: kv cross size =9.44 MBwhisper_init_state: kv padsize=2.36 MBwhisper_init_state: compute buffer (conv)whisper_init_state: compute buffer (encode) =whisper_init_state: compute buffer (cross)whisper_init_state: compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocating2026-05-21T10:13:41.913005ZINFO screenpipe_audio::audio_manager::manager: reconciliatior2026-05-21710:15:15.5768762INFO screenpipe_engine::event_driven_capture: content dedup:j Support Daily - in 4h 45 m100% С8• Thu 21 May 10:15:32•••EDQHomeDMsActivityFilesLater•••More+→Describe what you are looking forJiminny ...ThreadsC9 Unreadsà platform-inner-teamGalya Dimitrova, Nikolay Yankov, and youa ThreadsHuddles• Drafts & sentDirectories01External connections* Starred& jiminny-x-integrati...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# curiosity_lab# engineering# general# happy_birthday# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# supportLukas Kovalik 31 minutes agoдобро утро, тази страница не трябва ли да япоказваме само ако няма reportsCleanShot 2026-05-21 at [EMAIL] your questions into ongoing insightsGalya Dimitrova 23 minutes agoДа, би трябвалоLukas Kovalik 22 minutes agoче сега ми го показва и ако имам reportLukas Kovalik 21 minutes agoна neptuneNewNikolay Yankov 6 minutes agoвсичко е наредReply...Also send to à platform-inner-team+AaYou're up to date...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65514
|
2309
|
7
|
2026-05-21T07:45:17.549352+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349517549_m2.jpg...
|
Slack
|
releases (Channel) - Jiminny Inc - 4 new items - S releases (Channel) - Jiminny Inc - 4 new items - Slack...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
happy_birthday
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Nikolay Yankov
Aneliya Angelova
Stoyan Tanev
James Graham
Stefka Stoyanova
Galya Dimitrova
Vasil Vasilev
Stoyan Tomov
Todor Stamatov
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Files
Files
Bookmarks
Bookmarks
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
GitHub
APP
Yesterday at 5:20:09 PM
5:20 PM
19 new commits
19 new commits
pushed to
master
master
by
nikolay-yankov
nikolay-yankov
6fae8bb2
6fae8bb2
- JY-20613 support owner role on setup team
b7df5604
b7df5604
- JY-20613 fix tests
2864624e
2864624e
- JY-20613 Add Owner Role field
d2d5ccca
d2d5ccca
- Merge branch 'JY-20613-allow-owner-role-on-team-setup' of
github.com:jiminny/app
github.com:jiminny/app
into JY-20613-allow-owner-role-on-team-setup
190239df
190239df
- Merge branch 'master' into JY-20613-allow-owner-role-on-team-setup
Show more
jiminny/app
jiminny/app
|
Added by
GitHub
GitHub
CircleCI
APP
Yesterday at 5:45:56 PM
5:45 PM
Deployment Successful! tada emoji
Deployment Successful!
Project
: app
When
: 05/20/2026 14:45:56
Tag
:
View Job
View Job
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Jump to date
New
GitHub
APP
Today at 10:44:15 AM
10:44 AM
6 new commits
6 new commits
pushed to
master
master
by
TodorStamatovJiminny
TodorStamatovJiminny
b6926974
b6926974
- JY-20947: fix twilio video downloads
f2f9ee6e
f2f9ee6e
- JY-20947: fix unit test, add constants
c73862ce
c73862ce
- JY-20947: fix tests
abf2f032
abf2f032
- JY-20947: add unit tests
e90ca7cd
e90ca7cd
- Merge branch 'master' into JY-20947-twilio-video-downloads
Show more
jiminny/app
jiminny/app
|
Added by
GitHub
GitHub
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Processing uploaded file… complete! Message ready to be sent.
Channel releases...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.0056515955,"top":0.058260176,"width":0.011968086,"height":0.028731046},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"bounds":{"left":0.0029920214,"top":0.10055866,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"bounds":{"left":0.0066489363,"top":0.13806863,"width":0.009973404,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.0029920214,"top":0.15482841,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"bounds":{"left":0.0076462766,"top":0.19233839,"width":0.007978723,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.0029920214,"top":0.20909816,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"bounds":{"left":0.004986702,"top":0.24660814,"width":0.012965426,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.005319149,"top":0.24660814,"width":0.0026595744,"height":0.011173184}},{"char_start":1,"char_count":7,"bounds":{"left":0.0076462766,"top":0.24660814,"width":0.010638298,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.0029920214,"top":0.26336792,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"bounds":{"left":0.0076462766,"top":0.3008779,"width":0.0076462766,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.007978723,"top":0.3008779,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.009973404,"top":0.3008779,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.0029920214,"top":0.31763768,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"bounds":{"left":0.00731383,"top":0.35514766,"width":0.008643617,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.00731383,"top":0.35514766,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.00930851,"top":0.35514766,"width":0.0066489363,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.0029920214,"top":0.3719074,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"bounds":{"left":0.006981383,"top":0.4094174,"width":0.008976064,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.00731383,"top":0.4094174,"width":0.0033244682,"height":0.011173184}},{"char_start":1,"char_count":3,"bounds":{"left":0.010638298,"top":0.4094174,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.042220745,"top":0.09177973,"width":0.025598405,"height":0.003990423},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.042220745,"top":0.103751,"width":0.015957447,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.103751,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.04488032,"top":0.103751,"width":0.013297873,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"happy_birthday","depth":23,"bounds":{"left":0.042220745,"top":0.12609737,"width":0.033909574,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.12609737,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":13,"bounds":{"left":0.045212764,"top":0.12609737,"width":0.030917553,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.042220745,"top":0.14844373,"width":0.022938829,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.14844373,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.043550532,"top":0.14844373,"width":0.021609042,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.042220745,"top":0.1707901,"width":0.034906916,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.1707901,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.045212764,"top":0.1707901,"width":0.031914894,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.042220745,"top":0.19313647,"width":0.03856383,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.19313647,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.045212764,"top":0.19313647,"width":0.03557181,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.042220745,"top":0.21548285,"width":0.01662234,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.21548285,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":5,"bounds":{"left":0.044215426,"top":0.21548285,"width":0.014960106,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.042220745,"top":0.23782921,"width":0.01761968,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.23782921,"width":0.0016622341,"height":0.014365523}},{"char_start":1,"char_count":7,"bounds":{"left":0.043882977,"top":0.23782921,"width":0.015957447,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.042220745,"top":0.2601756,"width":0.024268618,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.2601756,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.04454787,"top":0.2601756,"width":0.021941489,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.042220745,"top":0.28252193,"width":0.016954787,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.28252193,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.04454787,"top":0.28252193,"width":0.01462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.042220745,"top":0.3048683,"width":0.024268618,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.3048683,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.044215426,"top":0.3048683,"width":0.022606382,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.042220745,"top":0.3272147,"width":0.04488032,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.3272147,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":20,"bounds":{"left":0.044215426,"top":0.3272147,"width":0.04720745,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"bounds":{"left":0.042220745,"top":0.37988827,"width":0.032912236,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.37988827,"width":0.0039893617,"height":0.014365523}},{"char_start":1,"char_count":13,"bounds":{"left":0.046210106,"top":0.37988827,"width":0.028922873,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.042220745,"top":0.40223464,"width":0.03756649,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.40223464,"width":0.0033244682,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.045545213,"top":0.40223464,"width":0.034242023,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.042220745,"top":0.424581,"width":0.028922873,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.424581,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.04488032,"top":0.424581,"width":0.026263298,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.042220745,"top":0.44692737,"width":0.031914894,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.44692737,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.044215426,"top":0.44692737,"width":0.029920213,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.042220745,"top":0.46927375,"width":0.03756649,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.46927375,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.04488032,"top":0.46927375,"width":0.03523936,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.042220745,"top":0.49162012,"width":0.034906916,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.49162012,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":14,"bounds":{"left":0.045877658,"top":0.49162012,"width":0.03158245,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.042220745,"top":0.5139665,"width":0.026263298,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.5139665,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.045212764,"top":0.5139665,"width":0.023271276,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tomov","depth":23,"bounds":{"left":0.042220745,"top":0.5363129,"width":0.030585106,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.5363129,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.04488032,"top":0.5363129,"width":0.027925532,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"bounds":{"left":0.042220745,"top":0.5586592,"width":0.034242023,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.5586592,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":13,"bounds":{"left":0.04454787,"top":0.5586592,"width":0.031914894,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.042220745,"top":0.5810056,"width":0.02925532,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.5810056,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.04488032,"top":0.5810056,"width":0.026928192,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.07413564,"top":0.5810056,"width":0.0063164895,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.07446808,"top":0.5810056,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":2,"bounds":{"left":0.07679521,"top":0.5810056,"width":0.0056515955,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.042220745,"top":0.63367915,"width":0.011968086,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.63367915,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":4,"bounds":{"left":0.04488032,"top":0.63367915,"width":0.009640957,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.042220745,"top":0.6560255,"width":0.021609042,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.6560255,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.044215426,"top":0.6560255,"width":0.019946808,"height":0.014365523}}],"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.10206117,"top":0.09177973,"width":0.030585106,"height":0.030327214},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"bounds":{"left":0.111369684,"top":0.10055866,"width":0.01861702,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.111369684,"top":0.10055866,"width":0.0039893617,"height":0.012769354}},{"char_start":1,"char_count":7,"bounds":{"left":0.115359046,"top":0.10055866,"width":0.014960106,"height":0.012769354}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.13397606,"top":0.09177973,"width":0.020944148,"height":0.030327214},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"bounds":{"left":0.14328457,"top":0.10055866,"width":0.008976064,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.14328457,"top":0.10055866,"width":0.0026595744,"height":0.012769354}},{"char_start":1,"char_count":4,"bounds":{"left":0.14594415,"top":0.10055866,"width":0.0063164895,"height":0.012769354}}],"role_description":"text"},{"role":"AXRadioButton","text":"Bookmarks","depth":17,"bounds":{"left":0.15591756,"top":0.09177973,"width":0.033909574,"height":0.030327214},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Bookmarks","depth":19,"bounds":{"left":0.16522606,"top":0.10055866,"width":0.021941489,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.16555852,"top":0.10055866,"width":0.0029920214,"height":0.012769354}},{"char_start":1,"char_count":8,"bounds":{"left":0.16821809,"top":0.10055866,"width":0.019281914,"height":0.012769354}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.19115691,"top":0.09177973,"width":0.010638298,"height":0.030327214},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"bounds":{"left":0.096409574,"top":0.0518755,"width":0.015625,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"bounds":{"left":0.096409574,"top":0.0518755,"width":0.0076462766,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"bounds":{"left":0.096409574,"top":0.0518755,"width":0.013962766,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"bounds":{"left":0.14228724,"top":0.12689546,"width":0.032579787,"height":0.022346368},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"GitHub","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"APP","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 5:20:09 PM","depth":22,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:20 PM","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"19 new commits","depth":22,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19 new commits","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"pushed to","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"master","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"master","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"by","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"nikolay-yankov","depth":22,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"nikolay-yankov","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"6fae8bb2","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6fae8bb2","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20613 support owner role on setup team","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"b7df5604","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"b7df5604","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20613 fix tests","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"2864624e","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2864624e","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20613 Add Owner Role field","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"d2d5ccca","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"d2d5ccca","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- Merge branch 'JY-20613-allow-owner-role-on-team-setup' of","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"github.com:jiminny/app","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"github.com:jiminny/app","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"into JY-20613-allow-owner-role-on-team-setup","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"190239df","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"190239df","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- Merge branch 'master' into JY-20613-allow-owner-role-on-team-setup","depth":24,"bounds":{"left":0.12333777,"top":0.11572227,"width":0.084773935,"height":0.008778931},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.14527926,"top":0.075019956,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":67,"bounds":{"left":0.12333777,"top":0.075019956,"width":0.084773935,"height":0.049481247}}],"role_description":"text"},{"role":"AXButton","text":"Show more","depth":24,"bounds":{"left":0.12333777,"top":0.12609737,"width":0.024601065,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"jiminny/app","depth":24,"bounds":{"left":0.1299867,"top":0.14764565,"width":0.020611702,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"jiminny/app","depth":25,"bounds":{"left":0.1299867,"top":0.14764565,"width":0.020611702,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.1299867,"top":0.14764565,"width":0.0009973404,"height":0.011971269}},{"char_start":1,"char_count":10,"bounds":{"left":0.13098404,"top":0.14764565,"width":0.019614361,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"|","depth":24,"bounds":{"left":0.15026596,"top":0.14764565,"width":0.0033244682,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Added by","depth":24,"bounds":{"left":0.15325798,"top":0.14764565,"width":0.017952127,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.15359043,"top":0.14764565,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":7,"bounds":{"left":0.15625,"top":0.14764565,"width":0.013962766,"height":0.011971269}}],"role_description":"text"},{"role":"AXLink","text":"GitHub","depth":24,"bounds":{"left":0.17087767,"top":0.14764565,"width":0.012965426,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"GitHub","depth":25,"bounds":{"left":0.17087767,"top":0.14764565,"width":0.012965426,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.17121011,"top":0.14764565,"width":0.0029920214,"height":0.011971269}},{"char_start":1,"char_count":5,"bounds":{"left":0.17386968,"top":0.14764565,"width":0.010305851,"height":0.011971269}}],"role_description":"text"},{"role":"AXButton","text":"CircleCI","depth":22,"bounds":{"left":0.11801862,"top":0.1707901,"width":0.01761968,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"APP","depth":22,"bounds":{"left":0.13796543,"top":0.17478053,"width":0.0066489363,"height":0.009577015},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.14527926,"top":0.17238627,"width":0.0026595744,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 5:45:56 PM","depth":22,"bounds":{"left":0.14793883,"top":0.17478053,"width":0.015292553,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:45 PM","depth":23,"bounds":{"left":0.14793883,"top":0.17478053,"width":0.015292553,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.14793883,"top":0.17478053,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":6,"bounds":{"left":0.15026596,"top":0.17478053,"width":0.012965426,"height":0.011971269}}],"role_description":"text"},{"role":"AXHeading","text":"Deployment Successful! tada emoji","depth":22,"bounds":{"left":0.11801862,"top":0.1915403,"width":0.095744684,"height":0.017557861},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"Deployment Successful!","depth":24,"bounds":{"left":0.11801862,"top":0.19313647,"width":0.054853722,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.11801862,"top":0.19313647,"width":0.0039893617,"height":0.014365523}},{"char_start":1,"char_count":21,"bounds":{"left":0.12200798,"top":0.19313647,"width":0.049867023,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Project","depth":23,"bounds":{"left":0.11801862,"top":0.22027135,"width":0.015957447,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.11801862,"top":0.22027135,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.12101064,"top":0.22027135,"width":0.012965426,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":": app","depth":23,"bounds":{"left":0.11801862,"top":0.22027135,"width":0.017287234,"height":0.031923383},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.13397606,"top":0.22027135,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":4,"bounds":{"left":0.11801862,"top":0.23782921,"width":0.00831117,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"When","depth":23,"bounds":{"left":0.14926861,"top":0.22027135,"width":0.013630319,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":": 05/20/2026 14:45:56","depth":23,"bounds":{"left":0.14926861,"top":0.22027135,"width":0.024601065,"height":0.049481247},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.16289894,"top":0.22027135,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":20,"bounds":{"left":0.14926861,"top":0.23782921,"width":0.024933511,"height":0.031923383}}],"role_description":"text"},{"role":"AXStaticText","text":"Tag","depth":23,"bounds":{"left":0.11801862,"top":0.27294493,"width":0.0076462766,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.11801862,"top":0.27294493,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":2,"bounds":{"left":0.120678194,"top":0.27294493,"width":0.004986702,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":":","depth":23,"bounds":{"left":0.12533244,"top":0.27294493,"width":0.0016622341,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"View Job","depth":23,"bounds":{"left":0.11801862,"top":0.30167598,"width":0.023271276,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"View Job","depth":25,"bounds":{"left":0.12101064,"top":0.3056664,"width":0.017287234,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.12101064,"top":0.3064645,"width":0.0029920214,"height":0.012769354}},{"char_start":1,"char_count":7,"bounds":{"left":0.12400266,"top":0.3064645,"width":0.01462766,"height":0.012769354}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.12865691,"top":0.15722266,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.1392952,"top":0.15722266,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.14993352,"top":0.15722266,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16057181,"top":0.15722266,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17121011,"top":0.15722266,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.1818484,"top":0.15722266,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.21476063,"top":0.15722266,"width":0.0003324468,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.21476063,"top":0.15722266,"width":0.0003324468,"height":0.025538707},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"bounds":{"left":0.14594415,"top":0.3415802,"width":0.025265958,"height":0.022346368},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"New","depth":21,"bounds":{"left":0.20478724,"top":0.34557062,"width":0.00930851,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"GitHub","depth":22,"bounds":{"left":0.11801862,"top":0.37270552,"width":0.016289894,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"APP","depth":22,"bounds":{"left":0.13663563,"top":0.37669593,"width":0.0066489363,"height":0.009577015},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.14394946,"top":0.37430167,"width":0.0026595744,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 10:44:15 AM","depth":22,"bounds":{"left":0.14660904,"top":0.37669593,"width":0.01761968,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:44 AM","depth":23,"bounds":{"left":0.14660904,"top":0.37669593,"width":0.01761968,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.14660904,"top":0.37669593,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":7,"bounds":{"left":0.14893617,"top":0.37669593,"width":0.015625,"height":0.011971269}}],"role_description":"text"},{"role":"AXLink","text":"6 new commits","depth":22,"bounds":{"left":0.11801862,"top":0.39185953,"width":0.03324468,"height":0.014365523},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6 new commits","depth":23,"bounds":{"left":0.11801862,"top":0.39185953,"width":0.03324468,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"pushed to","depth":22,"bounds":{"left":0.15093085,"top":0.39185953,"width":0.024601065,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"master","depth":23,"bounds":{"left":0.1768617,"top":0.3942538,"width":0.014295213,"height":0.011971269},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"master","depth":24,"bounds":{"left":0.1768617,"top":0.3942538,"width":0.014295213,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"by","depth":22,"bounds":{"left":0.1924867,"top":0.39185953,"width":0.0066489363,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"TodorStamatovJiminny","depth":22,"bounds":{"left":0.11801862,"top":0.4094174,"width":0.04920213,"height":0.014365523},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"TodorStamatovJiminny","depth":23,"bounds":{"left":0.11801862,"top":0.4094174,"width":0.04920213,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"b6926974","depth":25,"bounds":{"left":0.124667555,"top":0.43575418,"width":0.019281914,"height":0.011971269},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"b6926974","depth":26,"bounds":{"left":0.124667555,"top":0.43575418,"width":0.019281914,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20947: fix twilio video downloads","depth":24,"bounds":{"left":0.12333777,"top":0.43335995,"width":0.08178192,"height":0.031923383},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"f2f9ee6e","depth":25,"bounds":{"left":0.124667555,"top":0.4708699,"width":0.019281914,"height":0.011971269},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"f2f9ee6e","depth":26,"bounds":{"left":0.124667555,"top":0.4708699,"width":0.019281914,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20947: fix unit test, add constants","depth":24,"bounds":{"left":0.12333777,"top":0.46847567,"width":0.08510638,"height":0.031923383},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"c73862ce","depth":25,"bounds":{"left":0.124667555,"top":0.5059856,"width":0.019281914,"height":0.011971269},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"c73862ce","depth":26,"bounds":{"left":0.124667555,"top":0.5059856,"width":0.019281914,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20947: fix tests","depth":24,"bounds":{"left":0.14494681,"top":0.50359136,"width":0.045212764,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"abf2f032","depth":25,"bounds":{"left":0.124667555,"top":0.5235435,"width":0.019281914,"height":0.011971269},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"abf2f032","depth":26,"bounds":{"left":0.124667555,"top":0.5235435,"width":0.019281914,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20947: add unit tests","depth":24,"bounds":{"left":0.14494681,"top":0.5211492,"width":0.057845745,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"e90ca7cd","depth":25,"bounds":{"left":0.124667555,"top":0.54110134,"width":0.019281914,"height":0.011971269},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"e90ca7cd","depth":26,"bounds":{"left":0.124667555,"top":0.54110134,"width":0.019281914,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- Merge branch 'master' into JY-20947-twilio-video-downloads","depth":24,"bounds":{"left":0.12333777,"top":0.5387071,"width":0.084773935,"height":0.031923383},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Show more","depth":24,"bounds":{"left":0.12333777,"top":0.57222664,"width":0.024601065,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"jiminny/app","depth":24,"bounds":{"left":0.1299867,"top":0.5937749,"width":0.020611702,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"jiminny/app","depth":25,"bounds":{"left":0.1299867,"top":0.5937749,"width":0.020611702,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"|","depth":24,"bounds":{"left":0.15026596,"top":0.5937749,"width":0.0033244682,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Added by","depth":24,"bounds":{"left":0.15325798,"top":0.5937749,"width":0.017952127,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"GitHub","depth":24,"bounds":{"left":0.17087767,"top":0.5937749,"width":0.012965426,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"GitHub","depth":25,"bounds":{"left":0.17087767,"top":0.5937749,"width":0.012965426,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.12865691,"top":0.35913807,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.1392952,"top":0.35913807,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.14993352,"top":0.35913807,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16057181,"top":0.35913807,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17121011,"top":0.35913807,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.1818484,"top":0.35913807,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.21476063,"top":0.35913807,"width":0.0003324468,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.21476063,"top":0.35913807,"width":0.0003324468,"height":0.025538707},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":23,"bounds":{"left":0.10372341,"top":0.6272945,"width":0.109707445,"height":0.030327214},"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Processing uploaded file… complete! Message ready to be sent.","depth":11,"bounds":{"left":0.0,"top":0.7126895,"width":0.022606382,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Channel releases","depth":11,"bounds":{"left":0.0,"top":0.7126895,"width":0.017287234,"height":0.0007980846},"on_screen":true,"role_description":"text"}]...
|
2967908158313616818
|
7940291397176052831
|
idle
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
happy_birthday
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Nikolay Yankov
Aneliya Angelova
Stoyan Tanev
James Graham
Stefka Stoyanova
Galya Dimitrova
Vasil Vasilev
Stoyan Tomov
Todor Stamatov
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Files
Files
Bookmarks
Bookmarks
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
GitHub
APP
Yesterday at 5:20:09 PM
5:20 PM
19 new commits
19 new commits
pushed to
master
master
by
nikolay-yankov
nikolay-yankov
6fae8bb2
6fae8bb2
- JY-20613 support owner role on setup team
b7df5604
b7df5604
- JY-20613 fix tests
2864624e
2864624e
- JY-20613 Add Owner Role field
d2d5ccca
d2d5ccca
- Merge branch 'JY-20613-allow-owner-role-on-team-setup' of
github.com:jiminny/app
github.com:jiminny/app
into JY-20613-allow-owner-role-on-team-setup
190239df
190239df
- Merge branch 'master' into JY-20613-allow-owner-role-on-team-setup
Show more
jiminny/app
jiminny/app
|
Added by
GitHub
GitHub
CircleCI
APP
Yesterday at 5:45:56 PM
5:45 PM
Deployment Successful! tada emoji
Deployment Successful!
Project
: app
When
: 05/20/2026 14:45:56
Tag
:
View Job
View Job
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Jump to date
New
GitHub
APP
Today at 10:44:15 AM
10:44 AM
6 new commits
6 new commits
pushed to
master
master
by
TodorStamatovJiminny
TodorStamatovJiminny
b6926974
b6926974
- JY-20947: fix twilio video downloads
f2f9ee6e
f2f9ee6e
- JY-20947: fix unit test, add constants
c73862ce
c73862ce
- JY-20947: fix tests
abf2f032
abf2f032
- JY-20947: add unit tests
e90ca7cd
e90ca7cd
- Merge branch 'master' into JY-20947-twilio-video-downloads
Show more
jiminny/app
jiminny/app
|
Added by
GitHub
GitHub
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Processing uploaded file… complete! Message ready to be sent.
Channel releases
slackFV [EMAIL]=.phounit.result.cacheE .prettierignore= windsurtrulesphpde neloer.onophpide heloer_models.ohophp artisanM'CLAUDE.mdcomooser.isoncomooser.lockdependency-checker.json8 dev ison= ids tytl=infection.ison.distMLINSTAlI.mdMLINTERNAI WERHOOK SFTUP mdEjiminny_storageMiliconsos mdllM Makefile1рackace-lock. sonE phpstan.neon.dist= phostan-baseline.neon<> phpunit.xmlTe raw sal query.saM+ README.mdsô sonar-proiect propertiesE test.ov‹> Untitled Diaaram.xmliusvetur.confio.isM+ WEBHOOK FILTERING_IMPLEMENTATION.mo>1h External Librariesv =° Scratches and Consolesv batabase Consolesv AEU# console (EUlI DEAL RISKS (SU1A DITEUlA EU (EU]v Ajiminny@localhostA console (jiminny@localhost]# Di [liminny@localhostlA HS local [iiminny@localhostlA SF ['iiminny@localhost]& zoho dev [iiminny@localhost]V & PRODA console [PROD]& console 1 [PROD1LDIIPRODCActivityController.ong© ConvertLeadActivities.php= laravel.log4 SF jiminny@localhost]4 HS_local [jiminny@localhost]& console (PROD] X# console [euyLeadkepository.ong© PurgeLookupCache.php© SyncPlanhat.phpo synerorlannatpnpA console [STAGING]AcuivityLeadConverted.php© UserAutomatedreporscontroller.phpx© PlaybackController.php)Inteqrationapp/service.onoC) LeadConverted.ono570571C) CreateCommentedEvent.php(C) CreateSmsSentEvent.phpC) PlanhatActivityListener.php© AskAnythingPromptService.php572(C) AutomatedReportsRepositorv.php© AutomatedReportsCommand.phpphp api_v2.phpC) RequestGenerateReportJob.php573574© AutomatedReportResult.php(C) AutomatedReport.oho575use Jiminny \Services \Kiosk \AutomatedReports \ReportSortDirection;A1422 ^ v 576use Jiminny \Services\PlanhatService;use ectumtnace hutp kequestuse Inrowable,class UserAutomatedReportsController extends Controllenpublic const int RESULTS PER_ PAGE = 25:public const string SORT COLUMN = 'sort column':public const strina SORT DIRECTION = "sort direction':public function constructprivate readonly AutomatedReportsRepository $automatedReportsRepository.private readonly AutomatedRenortsService SautomatedRenortsServicelorivate readoni.v AniResponseService samiResponseServi.ce.orivate readoni.v Resnonse Sresnonse.private readonly PlanhatService $planhatService1...poST lanilv1lautomated-renorts/interest 1usadepublic function trackInterest(Request $request): JsonResponse(...}* Othnows ApplicationException58(09 >GET /api/v1/automated-reportspublic function list(Request Srequest): JsonResponse(...}125 0)DELETE/api/vl/automated-reports/kuuidpublic function delete(Request Srequest. string Suuid): JsonResponsef...} -609610--611612613616Tx: AutovSo jiminny vCONCAT(u.id, CASE WHEN U.id = t.owner_id THEN' (owner)' ELSE'' END) AS USEr_i041 A1 A40 V65 ^sa.*t.owner_id FROM social_accounts saNoun usens u on u.ide sa.sociablle 1diJOIN teams t 1..n<->1: on t.id = u.team_idWHERE u.team_id = 581 and sa.provider = 'salesforce';SELECT * FROM automated_report_results order by id desc;select * from features;select * from team_features where feature_id = 40;select * from teams where id = 556:select * trom automated reports:where id = 54: # 4fdd41f6-dcf0-30d0-b339-7345381b6044|"pat", "podcast"SELECT * FROM automated report results WHERE uuid to bin( '822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;select * from automated_report_results order by id desc;SELECT * FROMWHERE id = 1919:select * fromautomated report results WHERE report id = 54:select * from opportunities where id = 7594349:SELECT * FROM teams WHERE name LIKE '%Lesg': # 711. 692. [EMAIL] * from playbooks where team_id = 711; # event 226147SELEd * FROM Dlavbook catedonies WHERE Dlavbook 1d = 55151SELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event':SELECT * SROM eom fields WHEREI1d = 2261471SELECT * FROM crm_field_values WHERE crm_field_id = 226147;SELECT * FROM crm_configurations WHERE id = 692;SELSCTCONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '• END) AS user_id,v.emailsa.*,t.owner id FROM social accounts saJOIN users u on v.id = sa.sociable idJOIN teams t 1..n<->1: on t.id = u.team idWHERE U.team_id = 711 and sa.provider = 'salesforce";SELECT * FROM crm profiles cp JOIN users u 1..n<->1: on u.id = co.user id WHERE u.team_id = 711:select * from leadsselect * from calendarsSELECTS 0 hllsupoont Dally • In 4h 40m100% 52• Inu z1 May 10.10.34AskJiminnyReportActivityServiceTestvCascadePlaybook Categorie+0 ..connected. How isi. Can we vali eoneactivity tyee nith orit cabest aeeiewmane o, W dati anwsyggesinsingrow hohow to distinguishThoughts68 Fast Context How are playbook_categories populated and synced from crm_fields / crm_field_values... in 4.14s >Explored 4 files and searched 5 queriesRead ImportActivitvTypes.php #L95-104Searched olavbook cateaories in databaselmiarations (4) >egories|playbook_categories.*create in database/migrations (0)searched playoook_categor in database/migrations (<)Searched activity type in database/migrations (4)SurtingAsk anvthina (*4L)@ Codo Caudo Onue 17 ModiumNN Windeurf Toame 504.60...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65513
|
2308
|
5
|
2026-05-21T07:45:09.738361+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349509738_m1.jpg...
|
Slack
|
releases (Channel) - Jiminny Inc - 4 new items - S releases (Channel) - Jiminny Inc - 4 new items - Slack...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
happy_birthday
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Nikolay Yankov
Aneliya Angelova
Stoyan Tanev
James Graham
Stefka Stoyanova
Galya Dimitrova
Vasil Vasilev
Stoyan Tomov
Todor Stamatov
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Files
Files
Bookmarks
Bookmarks
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
GitHub
APP
Yesterday at 5:20:09 PM
5:20 PM
19 new commits
19 new commits
pushed to
master
master
by
nikolay-yankov
nikolay-yankov
6fae8bb2
6fae8bb2
- JY-20613 support owner role on setup team
b7df5604
b7df5604
- JY-20613 fix tests
2864624e
2864624e
- JY-20613 Add Owner Role field
d2d5ccca
d2d5ccca
- Merge branch 'JY-20613-allow-owner-role-on-team-setup' of
github.com:jiminny/app
github.com:jiminny/app
into JY-20613-allow-owner-role-on-team-setup
190239df
190239df
- Merge branch 'master' into JY-20613-allow-owner-role-on-team-setup
Show more
jiminny/app
jiminny/app
|
Added by
GitHub
GitHub
CircleCI
APP
Yesterday at 5:45:56 PM
5:45 PM
Deployment Successful! tada emoji
Deployment Successful!
Project
: app
When
: 05/20/2026 14:45:56
Tag
:
View Job
View Job
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Jump to date
New
GitHub
APP
Today at 10:44:15 AM
10:44 AM
6 new commits
6 new commits
pushed to
master
master
by
TodorStamatovJiminny
TodorStamatovJiminny
b6926974
b6926974
- JY-20947: fix twilio video downloads
f2f9ee6e
f2f9ee6e
- JY-20947: fix unit test, add constants
c73862ce
c73862ce
- JY-20947: fix tests
abf2f032
abf2f032
- JY-20947: add unit tests
e90ca7cd
e90ca7cd
- Merge branch 'master' into JY-20947-twilio-video-downloads
Show more
jiminny/app
jiminny/app
|
Added by
GitHub
GitHub
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Processing uploaded file… complete! Message ready to be sent.
Channel releases...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"happy_birthday","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tomov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Bookmarks","depth":17,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Bookmarks","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"GitHub","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"APP","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 5:20:09 PM","depth":22,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:20 PM","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"19 new commits","depth":22,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"19 new commits","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"pushed to","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"master","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"master","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"by","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"nikolay-yankov","depth":22,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"nikolay-yankov","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"6fae8bb2","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6fae8bb2","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20613 support owner role on setup team","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"b7df5604","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"b7df5604","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20613 fix tests","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"2864624e","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2864624e","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20613 Add Owner Role field","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"d2d5ccca","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"d2d5ccca","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- Merge branch 'JY-20613-allow-owner-role-on-team-setup' of","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"github.com:jiminny/app","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"github.com:jiminny/app","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"into JY-20613-allow-owner-role-on-team-setup","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"190239df","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"190239df","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"- Merge branch 'master' into JY-20613-allow-owner-role-on-team-setup","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Show more","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"jiminny/app","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"jiminny/app","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"|","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Added by","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"GitHub","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"GitHub","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"CircleCI","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"APP","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 5:45:56 PM","depth":22,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:45 PM","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"Deployment Successful! tada emoji","depth":22,"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"Deployment Successful!","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Project","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":": app","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"When","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":": 05/20/2026 14:45:56","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Tag","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":":","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"View Job","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"View Job","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"New","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"GitHub","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"APP","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 10:44:15 AM","depth":22,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:44 AM","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"6 new commits","depth":22,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6 new commits","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"pushed to","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"master","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"master","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"by","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"TodorStamatovJiminny","depth":22,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"TodorStamatovJiminny","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"b6926974","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"b6926974","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20947: fix twilio video downloads","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"f2f9ee6e","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"f2f9ee6e","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20947: fix unit test, add constants","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"c73862ce","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"c73862ce","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20947: fix tests","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"abf2f032","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"abf2f032","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- JY-20947: add unit tests","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"e90ca7cd","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"e90ca7cd","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"- Merge branch 'master' into JY-20947-twilio-video-downloads","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Show more","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"jiminny/app","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"jiminny/app","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"|","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Added by","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"GitHub","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"GitHub","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":23,"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Processing uploaded file… complete! Message ready to be sent.","depth":11,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Channel releases","depth":11,"on_screen":true,"role_description":"text"}]...
|
2967908158313616818
|
7940291397176052831
|
click
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
happy_birthday
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Nikolay Yankov
Aneliya Angelova
Stoyan Tanev
James Graham
Stefka Stoyanova
Galya Dimitrova
Vasil Vasilev
Stoyan Tomov
Todor Stamatov
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Files
Files
Bookmarks
Bookmarks
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
GitHub
APP
Yesterday at 5:20:09 PM
5:20 PM
19 new commits
19 new commits
pushed to
master
master
by
nikolay-yankov
nikolay-yankov
6fae8bb2
6fae8bb2
- JY-20613 support owner role on setup team
b7df5604
b7df5604
- JY-20613 fix tests
2864624e
2864624e
- JY-20613 Add Owner Role field
d2d5ccca
d2d5ccca
- Merge branch 'JY-20613-allow-owner-role-on-team-setup' of
github.com:jiminny/app
github.com:jiminny/app
into JY-20613-allow-owner-role-on-team-setup
190239df
190239df
- Merge branch 'master' into JY-20613-allow-owner-role-on-team-setup
Show more
jiminny/app
jiminny/app
|
Added by
GitHub
GitHub
CircleCI
APP
Yesterday at 5:45:56 PM
5:45 PM
Deployment Successful! tada emoji
Deployment Successful!
Project
: app
When
: 05/20/2026 14:45:56
Tag
:
View Job
View Job
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Jump to date
New
GitHub
APP
Today at 10:44:15 AM
10:44 AM
6 new commits
6 new commits
pushed to
master
master
by
TodorStamatovJiminny
TodorStamatovJiminny
b6926974
b6926974
- JY-20947: fix twilio video downloads
f2f9ee6e
f2f9ee6e
- JY-20947: fix unit test, add constants
c73862ce
c73862ce
- JY-20947: fix tests
abf2f032
abf2f032
- JY-20947: add unit tests
e90ca7cd
e90ca7cd
- Merge branch 'master' into JY-20947-twilio-video-downloads
Show more
jiminny/app
jiminny/app
|
Added by
GitHub
GitHub
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Processing uploaded file… complete! Message ready to be sent.
Channel releases
SlackFileEditViewGoHistoryWindowHelpscreelDOCKER0 81DEV (-zsh)₴2APP (-zsh)whisper_init_state:whisper_init_state:kv padsize=2.36 MBcompute buffer (conv)whisper_init_state: compute buffer (encode) =whisper_init_state: compute buffer (cross)=whisper_init_state:compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocatingwhisper_backend_init_gpu: device 0: Metal (type:1)whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)whisper_backend_init_gpu: using Metal backendggml_metal_init: allocatingggml_metal_init: found device: Apple M1ggml_metal_init: picking default device: Apple M1ggml_metal_init:use fusion= trueggml_metal_init:use concurrency= trueggml_metal_init: use graph optimizetruewhisper_backend_init: using BLAS backendwhisper_init_state: kv self size3.15 MBwhisper_init_state: kv cross size =9.44 MBwhisper_init_state: kv padsize =2.36 MBwhisper_init_state: compute buffer (conv)whisper_init_state: compute buffer (encode) =whisper_init_state: compute buffer (cross)=whisper_init_state: compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocatingwhisper_backend_init_gpu:device 0: Metal (type: 1)whisper_backend_init_gpu: found GPUdevice 0: Metal (type: 1, cnt: 0)whisper_backend_init_gpu: using Metal backendggml_metal_init: allocatingggml_metal_init: found device: Apple M1ggml_metal_init: picking default device: Apple M1ggml_metal_init:use fusion= trueggml_metal_init:use concurrencytrueggml_metal_init:use graph optimizetruewhisper_backend_init: using BLAS backendwhisper_init_state: kv self size3.15 MBwhisper_init_state: kv cross size =9.44 MBwhisper_init_state: kv padsize=2.36 MBwhisper_init_state: compute buffer (conv)whisper_init_state: compute buffer (encode) =whisper_init_state: compute buffer (cross)whisper_init_state: compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocating2026-05-21T10:13:41.913005ZINFO screenpipe_audio::audio_manager::manager: reconciliatior2026-05-21710:15:15.5768762INFO screenpipe_engine::event_driven_capture: content dedup:j Support Daily - in 4h 45 m100% С8• Thu 21 May 10:15:32•••EDQHomeDMsActivityFilesLater•••More+→Describe what you are looking forJiminny ...ThreadsC9 Unreadsà platform-inner-teamGalya Dimitrova, Nikolay Yankov, and youa ThreadsHuddles• Drafts & sentDirectories01External connections* Starred& jiminny-x-integrati...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# curiosity_lab# engineering# general# happy_birthday# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# supportLukas Kovalik 31 minutes agoдобро утро, тази страница не трябва ли да япоказваме само ако няма reportsCleanShot 2026-05-21 at [EMAIL] your questions into ongoing insightsGalya Dimitrova 23 minutes agoДа, би трябвалоLukas Kovalik 22 minutes agoче сега ми го показва и ако имам reportLukas Kovalik 21 minutes agoна neptuneNewNikolay Yankov 6 minutes agoвсичко е наредReply...Also send to à platform-inner-team+AaYou're up to date...
|
65510
|
NULL
|
NULL
|
NULL
|
|
65512
|
2309
|
6
|
2026-05-21T07:44:45.508811+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349485508_m2.jpg...
|
Slack
|
Jira Cloud (DM) - Jiminny Inc - 4 new items - Slac Jira Cloud (DM) - Jiminny Inc - 4 new items - Slack...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
happy_birthday
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Nikolay Yankov
Aneliya Angelova
Stoyan Tanev
James Graham
Stefka Stoyanova
Galya Dimitrova
Vasil Vasilev
Stoyan Tomov
Todor Stamatov
Lukas Kovalik
you
Toast
Jira Cloud
Home
Messages
Messages
About
Jump to date
Yesterday at 5:24:08 PM
5:24
Nikolay Yankov transitioned a Story you are assigned to from
Code Review
⟶
Ready for QA
JY-20676 Notify the user if a Panorama prompts is deleted but is used in AJ …
JY-20676 Notify the user if a Panorama prompts is deleted but is used in AJ …
Status:
Ready for QA
Type:
Story
Assignee:
Lukas
Kovalik
Priority:
Medium
Comment
Comment
More actions...
Yesterday at 5:24:10 PM
5:24
Nikolay Yankov transitioned a Story you are assigned to from
Code Review
⟶
Ready for QA
JY-20615 Notify the user if a SS is deleted but is used in AJ Report
JY-20615 Notify the user if a SS is deleted but is used in AJ Report
Status:
Ready for QA
Type:
Story
Assignee:
Lukas
Kovalik
Priority:
Medium
Comment
Comment
More actions...
Yesterday at 5:24:38 PM
5:24
@Galya Dimitrova
@Galya Dimitrova
updated the description of a Story you are assigned to
JY-20613 Allow owner's role to be selected when setting up a trial
JY-20613 Allow owner's role to be selected when setting up a trial
Status:
Deployed
Type:
Story
Assignee:
Lukas
Kovalik
Priority:
Medium
Comment
Comment
Transition
Transition
More actions...
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Jump to date
New
Jira Cloud
APP
Today at 10:27:35 AM
10:27 AM
You just
shared
shared
a Jira link
@Andrea Zlatanova
@Andrea Zlatanova
needs access to
Jira
to view and respond to the ticket.
Do you want to invite them?
Add to Jira
Add to Jira
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Processing uploaded file… complete! Message ready to be sent.
Channel...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.0056515955,"top":0.058260176,"width":0.011968086,"height":0.028731046},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"bounds":{"left":0.0029920214,"top":0.10055866,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"bounds":{"left":0.0066489363,"top":0.13806863,"width":0.009973404,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.0029920214,"top":0.15482841,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"bounds":{"left":0.0076462766,"top":0.19233839,"width":0.007978723,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.0029920214,"top":0.20909816,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"bounds":{"left":0.004986702,"top":0.24660814,"width":0.012965426,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.005319149,"top":0.24660814,"width":0.0026595744,"height":0.011173184}},{"char_start":1,"char_count":7,"bounds":{"left":0.0076462766,"top":0.24660814,"width":0.010638298,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.0029920214,"top":0.26336792,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"bounds":{"left":0.0076462766,"top":0.3008779,"width":0.0076462766,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.007978723,"top":0.3008779,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.009973404,"top":0.3008779,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.0029920214,"top":0.31763768,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"bounds":{"left":0.00731383,"top":0.35514766,"width":0.008643617,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.00731383,"top":0.35514766,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.00930851,"top":0.35514766,"width":0.0066489363,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.0029920214,"top":0.3719074,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"bounds":{"left":0.006981383,"top":0.4094174,"width":0.008976064,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.00731383,"top":0.4094174,"width":0.0033244682,"height":0.011173184}},{"char_start":1,"char_count":3,"bounds":{"left":0.010638298,"top":0.4094174,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.042220745,"top":0.09177973,"width":0.025598405,"height":0.003990423},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.042220745,"top":0.103751,"width":0.015957447,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.103751,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.04488032,"top":0.103751,"width":0.013297873,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"happy_birthday","depth":23,"bounds":{"left":0.042220745,"top":0.12609737,"width":0.033909574,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.12609737,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":13,"bounds":{"left":0.045212764,"top":0.12609737,"width":0.030917553,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.042220745,"top":0.14844373,"width":0.022938829,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.14844373,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.043550532,"top":0.14844373,"width":0.021609042,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.042220745,"top":0.1707901,"width":0.034906916,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.1707901,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.045212764,"top":0.1707901,"width":0.031914894,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.042220745,"top":0.19313647,"width":0.03856383,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.19313647,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.045212764,"top":0.19313647,"width":0.03557181,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.042220745,"top":0.21548285,"width":0.01662234,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.21548285,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":5,"bounds":{"left":0.044215426,"top":0.21548285,"width":0.014960106,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.042220745,"top":0.23782921,"width":0.018284574,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.23782921,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":7,"bounds":{"left":0.044215426,"top":0.23782921,"width":0.016289894,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.042220745,"top":0.2601756,"width":0.024268618,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.2601756,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.04454787,"top":0.2601756,"width":0.021941489,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.042220745,"top":0.28252193,"width":0.016954787,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.28252193,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.04454787,"top":0.28252193,"width":0.01462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.042220745,"top":0.3048683,"width":0.024268618,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.3048683,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.044215426,"top":0.3048683,"width":0.022606382,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.042220745,"top":0.3272147,"width":0.04488032,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.3272147,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":20,"bounds":{"left":0.044215426,"top":0.3272147,"width":0.04720745,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"bounds":{"left":0.042220745,"top":0.37988827,"width":0.032912236,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.37988827,"width":0.0039893617,"height":0.014365523}},{"char_start":1,"char_count":13,"bounds":{"left":0.046210106,"top":0.37988827,"width":0.028922873,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.042220745,"top":0.40223464,"width":0.03756649,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.40223464,"width":0.0033244682,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.045545213,"top":0.40223464,"width":0.034242023,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.042220745,"top":0.424581,"width":0.028922873,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.424581,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.04488032,"top":0.424581,"width":0.026263298,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.042220745,"top":0.44692737,"width":0.031914894,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.44692737,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.044215426,"top":0.44692737,"width":0.029920213,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.042220745,"top":0.46927375,"width":0.03756649,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.46927375,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.04488032,"top":0.46927375,"width":0.03523936,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.042220745,"top":0.49162012,"width":0.034906916,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.49162012,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":14,"bounds":{"left":0.045877658,"top":0.49162012,"width":0.03158245,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.042220745,"top":0.5139665,"width":0.026263298,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.5139665,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.045212764,"top":0.5139665,"width":0.023271276,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tomov","depth":23,"bounds":{"left":0.042220745,"top":0.5363129,"width":0.030585106,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.5363129,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.04488032,"top":0.5363129,"width":0.027925532,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"bounds":{"left":0.042220745,"top":0.5586592,"width":0.034242023,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.5586592,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":13,"bounds":{"left":0.04454787,"top":0.5586592,"width":0.031914894,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.042220745,"top":0.5810056,"width":0.02925532,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.5810056,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.04488032,"top":0.5810056,"width":0.026928192,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.07413564,"top":0.5810056,"width":0.0063164895,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.07446808,"top":0.5810056,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":2,"bounds":{"left":0.07679521,"top":0.5810056,"width":0.0056515955,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.042220745,"top":0.63367915,"width":0.011968086,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.63367915,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":4,"bounds":{"left":0.04488032,"top":0.63367915,"width":0.009640957,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":24,"bounds":{"left":0.042220745,"top":0.6560255,"width":0.021609042,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.6560255,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.044215426,"top":0.6560255,"width":0.019946808,"height":0.014365523}}],"role_description":"text"},{"role":"AXRadioButton","text":"Home","depth":17,"bounds":{"left":0.10472074,"top":0.09177973,"width":0.011635638,"height":0.028731046},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.12566489,"top":0.09177973,"width":0.018949468,"height":0.028731046},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"bounds":{"left":0.12566489,"top":0.09976058,"width":0.018949468,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.12566489,"top":0.10055866,"width":0.0043218085,"height":0.012769354}},{"char_start":1,"char_count":7,"bounds":{"left":0.12965426,"top":0.10055866,"width":0.014960106,"height":0.012769354}}],"role_description":"text"},{"role":"AXRadioButton","text":"About","depth":17,"bounds":{"left":0.15359043,"top":0.09177973,"width":0.012300532,"height":0.028731046},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":24,"bounds":{"left":0.14228724,"top":0.12609737,"width":0.032579787,"height":0.022346368},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Yesterday at 5:24:08 PM","depth":26,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:24","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov transitioned a Story you are assigned to from","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Code Review","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"⟶","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Ready for QA","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"JY-20676 Notify the user if a Panorama prompts is deleted but is used in AJ …","depth":26,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"JY-20676 Notify the user if a Panorama prompts is deleted but is used in AJ …","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Status:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Ready for QA","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Type:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Story","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Assignee:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Lukas","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kovalik","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Priority:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Medium","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Comment","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Comment","depth":28,"on_screen":false,"role_description":"text"},{"role":"AXComboBox","text":"More actions...","depth":27,"on_screen":false,"placeholder":"More actions...","role_description":"combo box","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Yesterday at 5:24:10 PM","depth":26,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:24","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov transitioned a Story you are assigned to from","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Code Review","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"⟶","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Ready for QA","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"JY-20615 Notify the user if a SS is deleted but is used in AJ Report","depth":26,"bounds":{"left":0.11801862,"top":0.114924185,"width":0.0930851,"height":0.022346368},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"JY-20615 Notify the user if a SS is deleted but is used in AJ Report","depth":27,"bounds":{"left":0.11801862,"top":0.114924185,"width":0.0930851,"height":0.022346368},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.11801862,"top":0.105347164,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":67,"bounds":{"left":0.11801862,"top":0.105347164,"width":0.0930851,"height":0.031923383}}],"role_description":"text"},{"role":"AXStaticText","text":"Status:","depth":26,"bounds":{"left":0.11801862,"top":0.14844373,"width":0.013962766,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.11801862,"top":0.14844373,"width":0.0023271276,"height":0.012769354}},{"char_start":1,"char_count":6,"bounds":{"left":0.12034574,"top":0.14844373,"width":0.010638298,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"Ready for QA","depth":26,"bounds":{"left":0.13164894,"top":0.14844373,"width":0.025930852,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.13198139,"top":0.14844373,"width":0.0026595744,"height":0.012769354}},{"char_start":1,"char_count":11,"bounds":{"left":0.13464096,"top":0.14844373,"width":0.023271276,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"Type:","depth":26,"bounds":{"left":0.17087767,"top":0.14844373,"width":0.011303191,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.17087767,"top":0.14844373,"width":0.0023271276,"height":0.012769354}},{"char_start":1,"char_count":4,"bounds":{"left":0.1732048,"top":0.14844373,"width":0.007978723,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"Story","depth":26,"bounds":{"left":0.18218085,"top":0.14844373,"width":0.010305851,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.18218085,"top":0.14844373,"width":0.0026595744,"height":0.012769354}},{"char_start":1,"char_count":4,"bounds":{"left":0.18450798,"top":0.14844373,"width":0.00831117,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"Assignee:","depth":26,"bounds":{"left":0.11801862,"top":0.16839585,"width":0.018949468,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.11801862,"top":0.16839585,"width":0.0029920214,"height":0.012769354}},{"char_start":1,"char_count":8,"bounds":{"left":0.12101064,"top":0.16839585,"width":0.014960106,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"Lukas","depth":26,"bounds":{"left":0.13696809,"top":0.16839585,"width":0.011303191,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.13730054,"top":0.16839585,"width":0.0019946808,"height":0.012769354}},{"char_start":1,"char_count":4,"bounds":{"left":0.1392952,"top":0.16839585,"width":0.008976064,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.14793883,"top":0.16839585,"width":0.0013297872,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Kovalik","depth":26,"bounds":{"left":0.14893617,"top":0.16839585,"width":0.014295213,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.14926861,"top":0.16839585,"width":0.0029920214,"height":0.012769354}},{"char_start":1,"char_count":6,"bounds":{"left":0.15192819,"top":0.16839585,"width":0.011635638,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"Priority:","depth":26,"bounds":{"left":0.11801862,"top":0.18834797,"width":0.016289894,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.11801862,"top":0.18834797,"width":0.0026595744,"height":0.012769354}},{"char_start":1,"char_count":8,"bounds":{"left":0.120678194,"top":0.18834797,"width":0.012632979,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"Medium","depth":26,"bounds":{"left":0.13397606,"top":0.18834797,"width":0.016289894,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.13430852,"top":0.18834797,"width":0.0039893617,"height":0.012769354}},{"char_start":1,"char_count":5,"bounds":{"left":0.13829787,"top":0.18834797,"width":0.011968086,"height":0.012769354}}],"role_description":"text"},{"role":"AXButton","text":"Comment","depth":26,"bounds":{"left":0.11801862,"top":0.2122905,"width":0.024933511,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Comment","depth":28,"bounds":{"left":0.12101064,"top":0.21628092,"width":0.018949468,"height":0.012769354},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.12101064,"top":0.21707901,"width":0.0029920214,"height":0.012769354}},{"char_start":1,"char_count":6,"bounds":{"left":0.12400266,"top":0.21707901,"width":0.015957447,"height":0.012769354}}],"role_description":"text"},{"role":"AXComboBox","text":"More actions...","depth":27,"bounds":{"left":0.14527926,"top":0.2122905,"width":0.06349734,"height":0.022346368},"on_screen":true,"placeholder":"More actions...","role_description":"combo box","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Yesterday at 5:24:38 PM","depth":26,"bounds":{"left":0.107380316,"top":0.2482043,"width":0.007978723,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:24","depth":27,"bounds":{"left":0.107380316,"top":0.2482043,"width":0.007978723,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.107380316,"top":0.2482043,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":3,"bounds":{"left":0.109707445,"top":0.2482043,"width":0.005984043,"height":0.011971269}}],"role_description":"text"},{"role":"AXLink","text":"@Galya Dimitrova","depth":26,"bounds":{"left":0.1263298,"top":0.24501197,"width":0.04155585,"height":0.015961692},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"@Galya Dimitrova","depth":27,"bounds":{"left":0.12699468,"top":0.24581006,"width":0.040226065,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.12732713,"top":0.24581006,"width":0.0043218085,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.13131648,"top":0.24581006,"width":0.035904255,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"updated the description of a Story you are assigned to","depth":26,"bounds":{"left":0.11801862,"top":0.24581006,"width":0.091090426,"height":0.031923383},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.16788563,"top":0.24581006,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":53,"bounds":{"left":0.11801862,"top":0.24581006,"width":0.08809841,"height":0.031923383}}],"role_description":"text"},{"role":"AXLink","text":"JY-20613 Allow owner's role to be selected when setting up a trial","depth":26,"bounds":{"left":0.11801862,"top":0.28092578,"width":0.095744684,"height":0.031923383},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"JY-20613 Allow owner's role to be selected when setting up a trial","depth":27,"bounds":{"left":0.11801862,"top":0.28092578,"width":0.095744684,"height":0.031923383},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Status:","depth":26,"bounds":{"left":0.11801862,"top":0.32402235,"width":0.013962766,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Deployed","depth":26,"bounds":{"left":0.13164894,"top":0.32402235,"width":0.01861702,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Type:","depth":26,"bounds":{"left":0.16356383,"top":0.32402235,"width":0.011303191,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Story","depth":26,"bounds":{"left":0.17486702,"top":0.32402235,"width":0.010305851,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Assignee:","depth":26,"bounds":{"left":0.11801862,"top":0.34397447,"width":0.018949468,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas","depth":26,"bounds":{"left":0.13696809,"top":0.34397447,"width":0.011303191,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.14793883,"top":0.34397447,"width":0.0013297872,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Kovalik","depth":26,"bounds":{"left":0.14893617,"top":0.34397447,"width":0.014295213,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Priority:","depth":26,"bounds":{"left":0.11801862,"top":0.3639266,"width":0.016289894,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Medium","depth":26,"bounds":{"left":0.13397606,"top":0.3639266,"width":0.016289894,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Comment","depth":26,"bounds":{"left":0.11801862,"top":0.38786912,"width":0.024933511,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Comment","depth":28,"bounds":{"left":0.12101064,"top":0.39185953,"width":0.018949468,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Transition","depth":26,"bounds":{"left":0.14527926,"top":0.38786912,"width":0.025265958,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Transition","depth":28,"bounds":{"left":0.14827128,"top":0.39185953,"width":0.019281914,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXComboBox","text":"More actions...","depth":27,"bounds":{"left":0.11801862,"top":0.41660017,"width":0.0631649,"height":0.022346368},"on_screen":true,"placeholder":"More actions...","role_description":"combo box","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with white_check_mark","depth":27,"bounds":{"left":0.12865691,"top":0.22106944,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":27,"bounds":{"left":0.1392952,"top":0.22106944,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":27,"bounds":{"left":0.14993352,"top":0.22106944,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":27,"bounds":{"left":0.16057181,"top":0.22106944,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":27,"bounds":{"left":0.17121011,"top":0.22106944,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":27,"bounds":{"left":0.1818484,"top":0.22106944,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":27,"bounds":{"left":0.21476063,"top":0.22106944,"width":0.0003324468,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":27,"bounds":{"left":0.21476063,"top":0.22106944,"width":0.0003324468,"height":0.025538707},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":24,"bounds":{"left":0.14594415,"top":0.45650437,"width":0.025265958,"height":0.022346368},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"New","depth":24,"bounds":{"left":0.20478724,"top":0.46049482,"width":0.00930851,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Jira Cloud","depth":25,"bounds":{"left":0.11801862,"top":0.48762968,"width":0.022273935,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"APP","depth":25,"bounds":{"left":0.14228724,"top":0.49162012,"width":0.0066489363,"height":0.009577015},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":25,"bounds":{"left":0.14993352,"top":0.48922586,"width":0.0026595744,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 10:27:35 AM","depth":25,"bounds":{"left":0.15226063,"top":0.49162012,"width":0.017952127,"height":0.011173184},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:27 AM","depth":26,"bounds":{"left":0.15226063,"top":0.49162012,"width":0.017952127,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"You just","depth":26,"bounds":{"left":0.12533244,"top":0.5067837,"width":0.019946808,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"shared","depth":26,"bounds":{"left":0.14494681,"top":0.5067837,"width":0.014960106,"height":0.014365523},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"shared","depth":27,"bounds":{"left":0.14494681,"top":0.5067837,"width":0.014960106,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"a Jira link","depth":26,"bounds":{"left":0.15990691,"top":0.5067837,"width":0.021941489,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"@Andrea Zlatanova","depth":26,"bounds":{"left":0.11801862,"top":0.5235435,"width":0.043882977,"height":0.015961692},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"@Andrea Zlatanova","depth":27,"bounds":{"left":0.11868351,"top":0.5243416,"width":0.04255319,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"needs access to","depth":26,"bounds":{"left":0.1619016,"top":0.5243416,"width":0.036901597,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira","depth":26,"bounds":{"left":0.19847074,"top":0.5243416,"width":0.007978723,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"to view and respond to the ticket.","depth":26,"bounds":{"left":0.11801862,"top":0.5243416,"width":0.0944149,"height":0.031923383},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Do you want to invite them?","depth":26,"bounds":{"left":0.11801862,"top":0.5594573,"width":0.061835106,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Add to Jira","depth":26,"bounds":{"left":0.11801862,"top":0.584996,"width":0.025930852,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add to Jira","depth":28,"bounds":{"left":0.120678194,"top":0.58898646,"width":0.020611702,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":27,"bounds":{"left":0.12865691,"top":0.47406226,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":27,"bounds":{"left":0.1392952,"top":0.47406226,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":27,"bounds":{"left":0.14993352,"top":0.47406226,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":27,"bounds":{"left":0.16057181,"top":0.47406226,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":27,"bounds":{"left":0.17121011,"top":0.47406226,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":27,"bounds":{"left":0.1818484,"top":0.47406226,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":27,"bounds":{"left":0.21476063,"top":0.47406226,"width":0.0003324468,"height":0.025538707},"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":27,"bounds":{"left":0.21476063,"top":0.47406226,"width":0.0003324468,"height":0.025538707},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":24,"bounds":{"left":0.10372341,"top":0.6272945,"width":0.109707445,"height":0.030327214},"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Processing uploaded file… complete! Message ready to be sent.","depth":11,"bounds":{"left":0.0,"top":0.7126895,"width":0.022606382,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Channel","depth":11,"bounds":{"left":0.0,"top":0.7126895,"width":0.017287234,"height":0.0007980846},"on_screen":true,"role_description":"text"}]...
|
800871989120662043
|
-2216956622577302281
|
click
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
happy_birthday
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Nikolay Yankov
Aneliya Angelova
Stoyan Tanev
James Graham
Stefka Stoyanova
Galya Dimitrova
Vasil Vasilev
Stoyan Tomov
Todor Stamatov
Lukas Kovalik
you
Toast
Jira Cloud
Home
Messages
Messages
About
Jump to date
Yesterday at 5:24:08 PM
5:24
Nikolay Yankov transitioned a Story you are assigned to from
Code Review
⟶
Ready for QA
JY-20676 Notify the user if a Panorama prompts is deleted but is used in AJ …
JY-20676 Notify the user if a Panorama prompts is deleted but is used in AJ …
Status:
Ready for QA
Type:
Story
Assignee:
Lukas
Kovalik
Priority:
Medium
Comment
Comment
More actions...
Yesterday at 5:24:10 PM
5:24
Nikolay Yankov transitioned a Story you are assigned to from
Code Review
⟶
Ready for QA
JY-20615 Notify the user if a SS is deleted but is used in AJ Report
JY-20615 Notify the user if a SS is deleted but is used in AJ Report
Status:
Ready for QA
Type:
Story
Assignee:
Lukas
Kovalik
Priority:
Medium
Comment
Comment
More actions...
Yesterday at 5:24:38 PM
5:24
@Galya Dimitrova
@Galya Dimitrova
updated the description of a Story you are assigned to
JY-20613 Allow owner's role to be selected when setting up a trial
JY-20613 Allow owner's role to be selected when setting up a trial
Status:
Deployed
Type:
Story
Assignee:
Lukas
Kovalik
Priority:
Medium
Comment
Comment
Transition
Transition
More actions...
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Jump to date
New
Jira Cloud
APP
Today at 10:27:35 AM
10:27 AM
You just
shared
shared
a Jira link
@Andrea Zlatanova
@Andrea Zlatanova
needs access to
Jira
to view and respond to the ticket.
Do you want to invite them?
Add to Jira
Add to Jira
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Processing uploaded file… complete! Message ready to be sent.
Channel
slackFV [EMAIL]=.phounit.result.cacheE .prettierignore= windsurtrulesphpde neloer.onophpide heloer_models.ohophp artisanM'CLAUDE.mdcomooser.isoncomooser.lockdependency-checker.json8 dev ison= ids tytl=infection.ison.distMLINSTAlI.mdMLINTERNAI WERHOOK SFTUP mdEjiminny_storageMiliconsos mdllM Makefile1рackace-lock. sonE phpstan.neon.dist= phostan-baseline.neon<> phpunit.xmlTe raw sal query.saM+ README.mdsô sonar-proiect propertiesE test.ov‹> Untitled Diaaram.xmliusvetur.confio.isM+ WEBHOOK FILTERING_IMPLEMENTATION.mo>1h External Librariesv =° Scratches and Consolesv batabase Consolesv AEU# console (EUlI DEAL RISKS (SU1A DITEUlA EU (EU]v Ajiminny@localhostA console (jiminny@localhost]# Di [liminny@localhostlA HS local [iiminny@localhostlA SF ['iiminny@localhost]& zoho dev [iiminny@localhost]V & PRODA console [PROD]& console 1 [PROD1LDIIPRODCActivityController.ong© ConvertLeadActivities.php= laravel.log4 SF jiminny@localhost]4 HS_local [jiminny@localhost]& console (PROD] X# console [euyLeadkepository.ong© PurgeLookupCache.php© SyncPlanhat.phpo synerorlannatpnpA console [STAGING]AcuivityLeadConverted.php© UserAutomatedreporscontroller.phpx© PlaybackController.php)Inteqrationapp/service.onoC) LeadConverted.ono570571C) CreateCommentedEvent.php(C) CreateSmsSentEvent.phpC) PlanhatActivityListener.php© AskAnythingPromptService.php572(C) AutomatedReportsRepositorv.php© AutomatedReportsCommand.phpphp api_v2.phpC) RequestGenerateReportJob.php573574© AutomatedReportResult.php(C) AutomatedReport.oho575use Jiminny \Services \Kiosk \AutomatedReports \ReportSortDirection;A1422 ^ v 576use Jiminny \Services\PlanhatService;use ectumtnace hutp kequestuse Inrowable,class UserAutomatedReportsController extends Controllenpublic const int RESULTS PER_ PAGE = 25:public const string SORT COLUMN = 'sort column':public const strina SORT DIRECTION = "sort direction':public function constructprivate readonly AutomatedReportsRepository $automatedReportsRepository.private readonly AutomatedRenortsService SautomatedRenortsServicelorivate readoni.v AniResponseService samiResponseServi.ce.orivate readoni.v Resnonse Sresnonse.private readonly PlanhatService $planhatService1...poST lanilv1lautomated-renorts/interest 1usadepublic function trackInterest(Request $request): JsonResponse(...}* Othnows ApplicationException58(09 >GET /api/v1/automated-reportspublic function list(Request Srequest): JsonResponse(...}125 0)DELETE/api/vl/automated-reports/kuuidpublic function delete(Request Srequest. string Suuid): JsonResponsef...} -609610--611612613616Tx: AutovSo jiminny vCONCAT(u.id, CASE WHEN U.id = t.owner_id THEN' (owner)' ELSE'' END) AS USEr_i041 A1 A40 V65 ^sa.*t.owner_id FROM social_accounts saNoun usens u on u.ide sa.sociablle 1diJOIN teams t 1..n<->1: on t.id = u.team_idWHERE u.team_id = 581 and sa.provider = 'salesforce';SELECT * FROM automated_report_results order by id desc;select * from features;select * from team_features where feature_id = 40;select * from teams where id = 556:select * trom automated reports:where id = 54: # 4fdd41f6-dcf0-30d0-b339-7345381b6044|"pat", "podcast"SELECT * FROM automated report results WHERE uuid to bin( '822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;select * from automated_report_results order by id desc;SELECT * FROMWHERE id = 1919:select * fromautomated report results WHERE report id = 54:select * from opportunities where id = 7594349:SELECT * FROM teams WHERE name LIKE '%Lesg': # 711. 692. [EMAIL] * from playbooks where team_id = 711; # event 226147SELEd * FROM Dlavbook catedonies WHERE Dlavbook 1d = 55151SELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event':SELECT * SROM eom fields WHEREI1d = 2261471SELECT * FROM crm_field_values WHERE crm_field_id = 226147;SELECT * FROM crm_configurations WHERE id = 692;SELSCTCONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '• END) AS user_id,v.emailsa.*,t.owner id FROM social accounts saJOIN users u on v.id = sa.sociable idJOIN teams t 1..n<->1: on t.id = u.team idWHERE U.team_id = 711 and sa.provider = 'salesforce";SELECT * FROM crm profiles cp JOIN users u 1..n<->1: on u.id = co.user id WHERE u.team_id = 711:select * from leadsselect * from calendarsSELECTS 0 hllsupoont Dally • In 4h 40m100% 52• Inu z1 May 10.10.34AskJiminnyReportActivityServiceTestvCascadePlaybook Categorie+0 ..connected. How isi. Can we vali eoneactivity tyee nith orit cabest aeeiewmane o, W dati anwsyggesinsingrow hohow to distinguishThoughts68 Fast Context How are playbook_categories populated and synced from crm_fields / crm_field_values... in 4.14s >Explored 4 files and searched 5 queriesRead ImportActivitvTypes.php #L95-104Searched olavbook cateaories in databaselmiarations (4) >egories|playbook_categories.*create in database/migrations (0)searched playoook_categor in database/migrations (<)Searched activity type in database/migrations (4)SurtingAsk anvthina (*4L)@ Codo Caudo Onue 17 ModiumNN Windeurf Toame 504.60...
|
65511
|
NULL
|
NULL
|
NULL
|
|
65511
|
2309
|
5
|
2026-05-21T07:44:40.961810+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349480961_m2.jpg...
|
Slack
|
platform-inner-team (Channel) - Jiminny Inc - 5 ne platform-inner-team (Channel) - Jiminny Inc - 5 new items - Slack...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
happy_birthday
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Nikolay Yankov
Aneliya Angelova
Stoyan Tanev
James Graham
Stefka Stoyanova
Galya Dimitrova
Vasil Vasilev
Stoyan Tomov
Todor Stamatov
Lukas Kovalik
you
Jira Cloud
Toast
Unread mentions
Enable users to use their new activity types
Enable users to use their new activity types
Open in Jira Cloud
Jira Cloud
Details
Conversations 1
Description
Currently when customers create new activity types in their CRM, we ask them to create a new Playbook in order to fetch them. However now with the activity type automations that we have - this means they need to copy all of their prompts again. Which takes a huge amount of time.
For SF, Hubspot, Copper, Bullhorn, Close and Pipedrive (anything apart from Zoho)
when a new activity type is created in the CRM and fetched in Jiminny - add the activity type (in disabled state) to all the playbooks where activity type field is changed.
◦ this happens on the regular crm_field_metadata_sync
◦ introduce a button for the user on Playbooks page to trigger the sync synchronously - when a sync is done we s
…
Show more
Status
Backlog
Assignee
None
Reporter
Galya Dimitrova
Work Type
Story
Priority
Medium
Components
Platform
Sprint
Platform Sprint 5 Q2
Story point estimate
None
Fix versions
None
Days
None
Need QA
Yes
Labels
None
Sub-Product
None
Story Points
None
Environment
None
Updated just now
Open in Jira
✨ Summarize
More actions
Processing uploaded file… complete! Message ready to be sent.
loading…...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.0056515955,"top":0.058260176,"width":0.011968086,"height":0.028731046},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"bounds":{"left":0.0029920214,"top":0.10055866,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"bounds":{"left":0.0066489363,"top":0.13806863,"width":0.009973404,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.0029920214,"top":0.15482841,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"bounds":{"left":0.0076462766,"top":0.19233839,"width":0.007978723,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.0029920214,"top":0.20909816,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"bounds":{"left":0.004986702,"top":0.24660814,"width":0.012965426,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.005319149,"top":0.24660814,"width":0.0026595744,"height":0.011173184}},{"char_start":1,"char_count":7,"bounds":{"left":0.0076462766,"top":0.24660814,"width":0.010638298,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.0029920214,"top":0.26336792,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"bounds":{"left":0.0076462766,"top":0.3008779,"width":0.0076462766,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.007978723,"top":0.3008779,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.009973404,"top":0.3008779,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.0029920214,"top":0.31763768,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"bounds":{"left":0.00731383,"top":0.35514766,"width":0.008643617,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.00731383,"top":0.35514766,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.00930851,"top":0.35514766,"width":0.0066489363,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.0029920214,"top":0.3719074,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"bounds":{"left":0.006981383,"top":0.4094174,"width":0.008976064,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.00731383,"top":0.4094174,"width":0.0033244682,"height":0.011173184}},{"char_start":1,"char_count":3,"bounds":{"left":0.010638298,"top":0.4094174,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.036901597,"top":0.10055866,"width":0.01861702,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.036901597,"top":0.10055866,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.04055851,"top":0.10055866,"width":0.015292553,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.036901597,"top":0.12290503,"width":0.01761968,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.036901597,"top":0.12290503,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.039893616,"top":0.12290503,"width":0.01462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.036901597,"top":0.1452514,"width":0.017952127,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.036901597,"top":0.1452514,"width":0.0039893617,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.04089096,"top":0.1452514,"width":0.014295213,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.036901597,"top":0.16759777,"width":0.028922873,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.036901597,"top":0.16759777,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.04055851,"top":0.16759777,"width":0.025265958,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.08843085,"top":0.16839585,"width":0.0026595744,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.036901597,"top":0.18994413,"width":0.023936171,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.036901597,"top":0.18994413,"width":0.0039893617,"height":0.014365523}},{"char_start":1,"char_count":10,"bounds":{"left":0.04089096,"top":0.18994413,"width":0.020279255,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.042220745,"top":0.28411812,"width":0.043882977,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.28411812,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":24,"bounds":{"left":0.043550532,"top":0.28411812,"width":0.05418883,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.042220745,"top":0.3064645,"width":0.044215426,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.3064645,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":18,"bounds":{"left":0.045212764,"top":0.3064645,"width":0.04155585,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.042220745,"top":0.35913807,"width":0.022273935,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.35913807,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.04488032,"top":0.35913807,"width":0.019614361,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.042220745,"top":0.38148445,"width":0.011968086,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.38148445,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":5,"bounds":{"left":0.04488032,"top":0.38148445,"width":0.00930851,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.042220745,"top":0.4038308,"width":0.018284574,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.4038308,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.045212764,"top":0.4038308,"width":0.015292553,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.042220745,"top":0.42617717,"width":0.010305851,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.42617717,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":3,"bounds":{"left":0.045212764,"top":0.42617717,"width":0.00731383,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.042220745,"top":0.44852355,"width":0.034242023,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.44852355,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.04454787,"top":0.44852355,"width":0.032247342,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.042220745,"top":0.4708699,"width":0.027593086,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.4708699,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.04454787,"top":0.4708699,"width":0.025265958,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.042220745,"top":0.49321628,"width":0.025598405,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.49321628,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":10,"bounds":{"left":0.04488032,"top":0.49321628,"width":0.022938829,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.042220745,"top":0.51556265,"width":0.015957447,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.51556265,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.04488032,"top":0.51556265,"width":0.013297873,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"happy_birthday","depth":23,"bounds":{"left":0.042220745,"top":0.53790903,"width":0.033909574,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.53790903,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":13,"bounds":{"left":0.045212764,"top":0.53790903,"width":0.030917553,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.042220745,"top":0.5602554,"width":0.022938829,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.5602554,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.043550532,"top":0.5602554,"width":0.021609042,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.042220745,"top":0.5826017,"width":0.034906916,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.5826017,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.045212764,"top":0.5826017,"width":0.031914894,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.042220745,"top":0.6049481,"width":0.03856383,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.6049481,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.045212764,"top":0.6049481,"width":0.03557181,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.042220745,"top":0.6272945,"width":0.01662234,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.6272945,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":5,"bounds":{"left":0.044215426,"top":0.6272945,"width":0.014960106,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.042220745,"top":0.64964086,"width":0.018284574,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.64964086,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":7,"bounds":{"left":0.044215426,"top":0.64964086,"width":0.016289894,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.042220745,"top":0.67198724,"width":0.024268618,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.67198724,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.04454787,"top":0.67198724,"width":0.021941489,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.042220745,"top":0.6943336,"width":0.016954787,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.6943336,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.04454787,"top":0.6943336,"width":0.01462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.024268618,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.04488032,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.032912236,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.03756649,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.028922873,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.031914894,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.03756649,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.034906916,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.026263298,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tomov","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.030585106,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.034242023,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.02925532,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.07413564,"top":0.7086991,"width":0.0063164895,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.022273935,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.011968086,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Unread mentions","depth":17,"bounds":{"left":0.035904255,"top":0.68076617,"width":0.048204787,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Enable users to use their new activity types","depth":18,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Enable users to use their new activity types","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Open in Jira Cloud","depth":18,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jira Cloud","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXRadioButton","text":"Details","depth":19,"on_screen":false,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXRadioButton","text":"Conversations 1","depth":19,"on_screen":false,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Description","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Currently when customers create new activity types in their CRM, we ask them to create a new Playbook in order to fetch them. However now with the activity type automations that we have - this means they need to copy all of their prompts again. Which takes a huge amount of time.","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"For SF, Hubspot, Copper, Bullhorn, Close and Pipedrive (anything apart from Zoho)","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"when a new activity type is created in the CRM and fetched in Jiminny - add the activity type (in disabled state) to all the playbooks where activity type field is changed.","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"◦ this happens on the regular crm_field_metadata_sync","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"◦ introduce a button for the user on Playbooks page to trigger the sync synchronously - when a sync is done we s","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"…","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Show more","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Status","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Backlog","depth":20,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Assignee","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Reporter","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":20,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Work Type","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Story","depth":20,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Priority","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Medium","depth":20,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Components","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Platform","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sprint","depth":19,"bounds":{"left":0.10372341,"top":0.06943336,"width":0.012965426,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.06943336,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":5,"bounds":{"left":0.10638298,"top":0.06943336,"width":0.010305851,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Platform Sprint 5 Q2","depth":19,"bounds":{"left":0.10372341,"top":0.0933759,"width":0.045212764,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.0933759,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":19,"bounds":{"left":0.106715426,"top":0.0933759,"width":0.042220745,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Story point estimate","depth":19,"bounds":{"left":0.10372341,"top":0.12689546,"width":0.044215426,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.12689546,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":19,"bounds":{"left":0.10638298,"top":0.12689546,"width":0.04155585,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"None","depth":21,"bounds":{"left":0.10372341,"top":0.15642458,"width":0.010970744,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.15642458,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":3,"bounds":{"left":0.107380316,"top":0.15642458,"width":0.0076462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Fix versions","depth":19,"bounds":{"left":0.10372341,"top":0.19553073,"width":0.025598405,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.19553073,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.106715426,"top":0.19553073,"width":0.022938829,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"None","depth":20,"bounds":{"left":0.10372341,"top":0.21947326,"width":0.010970744,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.21947326,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":3,"bounds":{"left":0.107380316,"top":0.21947326,"width":0.0076462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Days","depth":19,"bounds":{"left":0.10372341,"top":0.2529928,"width":0.010970744,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.2529928,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":3,"bounds":{"left":0.107380316,"top":0.2529928,"width":0.00731383,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"None","depth":21,"bounds":{"left":0.10372341,"top":0.28252193,"width":0.010970744,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.28252193,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":3,"bounds":{"left":0.107380316,"top":0.28252193,"width":0.0076462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Need QA","depth":19,"bounds":{"left":0.10372341,"top":0.3216281,"width":0.020279255,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.3216281,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.107380316,"top":0.3216281,"width":0.01662234,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Yes","depth":20,"bounds":{"left":0.10372341,"top":0.35115722,"width":0.00731383,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.35115722,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":2,"bounds":{"left":0.10638298,"top":0.35115722,"width":0.004654255,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Labels","depth":19,"bounds":{"left":0.10372341,"top":0.39026338,"width":0.013962766,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.39026338,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":5,"bounds":{"left":0.10638298,"top":0.39026338,"width":0.011303191,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"None","depth":20,"bounds":{"left":0.10372341,"top":0.4142059,"width":0.010970744,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.4142059,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":3,"bounds":{"left":0.107380316,"top":0.4142059,"width":0.0076462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Sub-Product","depth":19,"bounds":{"left":0.10372341,"top":0.44772545,"width":0.027260639,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.44772545,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":10,"bounds":{"left":0.10638298,"top":0.44772545,"width":0.024601065,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"None","depth":20,"bounds":{"left":0.10372341,"top":0.471668,"width":0.010970744,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.471668,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":3,"bounds":{"left":0.107380316,"top":0.471668,"width":0.0076462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Story Points","depth":19,"bounds":{"left":0.10372341,"top":0.5051876,"width":0.026263298,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.5051876,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.10638298,"top":0.5051876,"width":0.023603724,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"None","depth":21,"bounds":{"left":0.10372341,"top":0.53471667,"width":0.010970744,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.53471667,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":3,"bounds":{"left":0.107380316,"top":0.53471667,"width":0.0076462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Environment","depth":19,"bounds":{"left":0.10372341,"top":0.5738228,"width":0.027925532,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.5738228,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":10,"bounds":{"left":0.106715426,"top":0.5738228,"width":0.024933511,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"None","depth":20,"bounds":{"left":0.10372341,"top":0.5977654,"width":0.010970744,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.5977654,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":3,"bounds":{"left":0.107380316,"top":0.5977654,"width":0.0076462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Updated just now","depth":20,"bounds":{"left":0.10372341,"top":0.6408619,"width":0.03357713,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Open in Jira","depth":16,"bounds":{"left":0.10372341,"top":0.6679968,"width":0.045877658,"height":0.028731046},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"✨ Summarize","depth":16,"bounds":{"left":0.15226063,"top":0.6679968,"width":0.046875,"height":0.028731046},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More actions","depth":16,"bounds":{"left":0.2017952,"top":0.6679968,"width":0.011968086,"height":0.028731046},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Processing uploaded file… complete! Message ready to be sent.","depth":11,"bounds":{"left":0.0,"top":0.7126895,"width":0.022606382,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"loading…","depth":11,"bounds":{"left":0.0,"top":0.7126895,"width":0.018949468,"height":0.0007980846},"on_screen":true,"role_description":"text"}]...
|
-8908168981360887910
|
-8125028145509691922
|
click
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
happy_birthday
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Nikolay Yankov
Aneliya Angelova
Stoyan Tanev
James Graham
Stefka Stoyanova
Galya Dimitrova
Vasil Vasilev
Stoyan Tomov
Todor Stamatov
Lukas Kovalik
you
Jira Cloud
Toast
Unread mentions
Enable users to use their new activity types
Enable users to use their new activity types
Open in Jira Cloud
Jira Cloud
Details
Conversations 1
Description
Currently when customers create new activity types in their CRM, we ask them to create a new Playbook in order to fetch them. However now with the activity type automations that we have - this means they need to copy all of their prompts again. Which takes a huge amount of time.
For SF, Hubspot, Copper, Bullhorn, Close and Pipedrive (anything apart from Zoho)
when a new activity type is created in the CRM and fetched in Jiminny - add the activity type (in disabled state) to all the playbooks where activity type field is changed.
◦ this happens on the regular crm_field_metadata_sync
◦ introduce a button for the user on Playbooks page to trigger the sync synchronously - when a sync is done we s
…
Show more
Status
Backlog
Assignee
None
Reporter
Galya Dimitrova
Work Type
Story
Priority
Medium
Components
Platform
Sprint
Platform Sprint 5 Q2
Story point estimate
None
Fix versions
None
Days
None
Need QA
Yes
Labels
None
Sub-Product
None
Story Points
None
Environment
None
Updated just now
Open in Jira
✨ Summarize
More actions
Processing uploaded file… complete! Message ready to be sent.
loading…
slackFV [EMAIL]=.phounit.result.cacheE .prettierignore= windsurtrulesphpde neloer.onophpide heloer_models.ohophp artisanM'CLAUDE.mdcomooser.isoncomooser.lockdependency-checker.json8 dev ison= ids tytl=infection.ison.distMLINSTAlI.mdMLINTERNAI WERHOOK SFTUP mdEjiminny_storageMiliconsos mdllM Makefile1рackace-lock. sonE phpstan.neon.dist= phostan-baseline.neon<> phpunit.xmlTe raw sal query.saM+ README.mdsô sonar-proiect propertiesE test.ov‹> Untitled Diaaram.xmliusvetur.confio.isM+ WEBHOOK FILTERING_IMPLEMENTATION.mo>1h External Librariesv =° Scratches and Consolesv batabase Consolesv AEU# console (EUlI DEAL RISKS (SU1A DITEUlA EU (EU]v Ajiminny@localhostA console (jiminny@localhost]# Di [liminny@localhostlA HS local [iiminny@localhostlA SF ['iiminny@localhost]& zoho dev [iiminny@localhost]V & PRODA console [PROD]& console 1 [PROD1LDIIPRODCActivityController.ong© ConvertLeadActivities.php= laravel.log4 SF jiminny@localhost]4 HS_local [jiminny@localhost]& console (PROD] X# console [euyLeadkepository.ong© PurgeLookupCache.php© SyncPlanhat.phpo synerorlannatpnpA console [STAGING]AcuivityLeadConverted.php© UserAutomatedreporscontroller.phpx© PlaybackController.php)Inteqrationapp/service.onoC) LeadConverted.ono570571C) CreateCommentedEvent.php(C) CreateSmsSentEvent.phpC) PlanhatActivityListener.php© AskAnythingPromptService.php572(C) AutomatedReportsRepositorv.php© AutomatedReportsCommand.phpphp api_v2.phpC) RequestGenerateReportJob.php573574© AutomatedReportResult.php(C) AutomatedReport.oho575use Jiminny \Services \Kiosk \AutomatedReports \ReportSortDirection;A1422 ^ v 576use Jiminny \Services\PlanhatService;use ectumtnace hutp kequestuse Inrowable,class UserAutomatedReportsController extends Controllenpublic const int RESULTS PER_ PAGE = 25:public const string SORT COLUMN = 'sort column':public const strina SORT DIRECTION = "sort direction':public function constructprivate readonly AutomatedReportsRepository $automatedReportsRepository.private readonly AutomatedRenortsService SautomatedRenortsServicelorivate readoni.v AniResponseService samiResponseServi.ce.orivate readoni.v Resnonse Sresnonse.private readonly PlanhatService $planhatService1...poST lanilv1lautomated-renorts/interest 1usadepublic function trackInterest(Request $request): JsonResponse(...}* Othnows ApplicationException58(09 >GET /api/v1/automated-reportspublic function list(Request Srequest): JsonResponse(...}125 0)DELETE/api/vl/automated-reports/kuuidpublic function delete(Request Srequest. string Suuid): JsonResponsef...} -609610--611612613616Tx: AutovSo jiminny vCONCAT(u.id, CASE WHEN U.id = t.owner_id THEN' (owner)' ELSE'' END) AS USEr_i041 A1 A40 V65 ^sa.*t.owner_id FROM social_accounts saNoun usens u on u.ide sa.sociablle 1diJOIN teams t 1..n<->1: on t.id = u.team_idWHERE u.team_id = 581 and sa.provider = 'salesforce';SELECT * FROM automated_report_results order by id desc;select * from features;select * from team_features where feature_id = 40;select * from teams where id = 556:select * trom automated reports:where id = 54: # 4fdd41f6-dcf0-30d0-b339-7345381b6044|"pat", "podcast"SELECT * FROM automated report results WHERE uuid to bin( '822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;select * from automated_report_results order by id desc;SELECT * FROMWHERE id = 1919:select * fromautomated report results WHERE report id = 54:select * from opportunities where id = 7594349:SELECT * FROM teams WHERE name LIKE '%Lesg': # 711. 692. [EMAIL] * from playbooks where team_id = 711; # event 226147SELEd * FROM Dlavbook catedonies WHERE Dlavbook 1d = 55151SELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event':SELECT * SROM eom fields WHEREI1d = 2261471SELECT * FROM crm_field_values WHERE crm_field_id = 226147;SELECT * FROM crm_configurations WHERE id = 692;SELSCTCONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '• END) AS user_id,v.emailsa.*,t.owner id FROM social accounts saJOIN users u on v.id = sa.sociable idJOIN teams t 1..n<->1: on t.id = u.team idWHERE U.team_id = 711 and sa.provider = 'salesforce";SELECT * FROM crm profiles cp JOIN users u 1..n<->1: on u.id = co.user id WHERE u.team_id = 711:select * from leadsselect * from calendarsSELECTS 0 hllsupoont Dally • In 4h 40m100% 52• Inu z1 May 10.10.34AskJiminnyReportActivityServiceTestvCascadePlaybook Categorie+0 ..connected. How isi. Can we vali eoneactivity tyee nith orit cabest aeeiewmane o, W dati anwsyggesinsingrow hohow to distinguishThoughts68 Fast Context How are playbook_categories populated and synced from crm_fields / crm_field_values... in 4.14s >Explored 4 files and searched 5 queriesRead ImportActivitvTypes.php #L95-104Searched olavbook cateaories in databaselmiarations (4) >egories|playbook_categories.*create in database/migrations (0)searched playoook_categor in database/migrations (<)Searched activity type in database/migrations (4)SurtingAsk anvthina (*4L)@ Codo Caudo Onue 17 ModiumNN Windeurf Toame 504.60...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65510
|
2308
|
4
|
2026-05-21T07:44:40.925803+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349480925_m1.jpg...
|
Slack
|
platform-inner-team (Channel) - Jiminny Inc - 5 ne platform-inner-team (Channel) - Jiminny Inc - 5 new items - Slack...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
happy_birthday
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Nikolay Yankov
Aneliya Angelova
Stoyan Tanev
James Graham
Stefka Stoyanova
Galya Dimitrova
Vasil Vasilev
Stoyan Tomov
Todor Stamatov
Lukas Kovalik
you
Jira Cloud
Toast
Unread mentions
Enable users to use their new activity types
Enable users to use their new activity types
Open in Jira Cloud
Jira Cloud
Details
Conversations 1
Description
Currently when customers create new activity types in their CRM, we ask them to create a new Playbook in order to fetch them. However now with the activity type automations that we have - this means they need to copy all of their prompts again. Which takes a huge amount of time.
For SF, Hubspot, Copper, Bullhorn, Close and Pipedrive (anything apart from Zoho)
when a new activity type is created in the CRM and fetched in Jiminny - add the activity type (in disabled state) to all the playbooks where activity type field is changed.
◦ this happens on the regular crm_field_metadata_sync
◦ introduce a button for the user on Playbooks page to trigger the sync synchronously - when a sync is done we s
…
Show more
Status
Backlog
Assignee
None
Reporter
Galya Dimitrova
Work Type
Story
Priority
Medium
Components
Platform
Sprint
Platform Sprint 5 Q2
Story point estimate
None
Fix versions
None
Days
None
Need QA
Yes
Labels
None
Sub-Product
None
Story Points
None
Environment
None
Updated just now
Open in Jira
✨ Summarize
More actions
Processing uploaded file… complete! Message ready to be sent.
loading…...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"happy_birthday","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tomov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Unread mentions","depth":17,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Enable users to use their new activity types","depth":18,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Enable users to use their new activity types","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Open in Jira Cloud","depth":18,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jira Cloud","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXRadioButton","text":"Details","depth":19,"on_screen":false,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXRadioButton","text":"Conversations 1","depth":19,"on_screen":false,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Description","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Currently when customers create new activity types in their CRM, we ask them to create a new Playbook in order to fetch them. However now with the activity type automations that we have - this means they need to copy all of their prompts again. Which takes a huge amount of time.","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"For SF, Hubspot, Copper, Bullhorn, Close and Pipedrive (anything apart from Zoho)","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"when a new activity type is created in the CRM and fetched in Jiminny - add the activity type (in disabled state) to all the playbooks where activity type field is changed.","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"◦ this happens on the regular crm_field_metadata_sync","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"◦ introduce a button for the user on Playbooks page to trigger the sync synchronously - when a sync is done we s","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"…","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Show more","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Status","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Backlog","depth":20,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Assignee","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Reporter","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":20,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Work Type","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Story","depth":20,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Priority","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Medium","depth":20,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Components","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Platform","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sprint","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Platform Sprint 5 Q2","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Story point estimate","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Fix versions","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Days","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Need QA","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Yes","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Labels","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sub-Product","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Story Points","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Environment","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Updated just now","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Open in Jira","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"✨ Summarize","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More actions","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Processing uploaded file… complete! Message ready to be sent.","depth":11,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"loading…","depth":11,"on_screen":true,"role_description":"text"}]...
|
-8908168981360887910
|
-8125028145509691922
|
click
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
happy_birthday
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Nikolay Yankov
Aneliya Angelova
Stoyan Tanev
James Graham
Stefka Stoyanova
Galya Dimitrova
Vasil Vasilev
Stoyan Tomov
Todor Stamatov
Lukas Kovalik
you
Jira Cloud
Toast
Unread mentions
Enable users to use their new activity types
Enable users to use their new activity types
Open in Jira Cloud
Jira Cloud
Details
Conversations 1
Description
Currently when customers create new activity types in their CRM, we ask them to create a new Playbook in order to fetch them. However now with the activity type automations that we have - this means they need to copy all of their prompts again. Which takes a huge amount of time.
For SF, Hubspot, Copper, Bullhorn, Close and Pipedrive (anything apart from Zoho)
when a new activity type is created in the CRM and fetched in Jiminny - add the activity type (in disabled state) to all the playbooks where activity type field is changed.
◦ this happens on the regular crm_field_metadata_sync
◦ introduce a button for the user on Playbooks page to trigger the sync synchronously - when a sync is done we s
…
Show more
Status
Backlog
Assignee
None
Reporter
Galya Dimitrova
Work Type
Story
Priority
Medium
Components
Platform
Sprint
Platform Sprint 5 Q2
Story point estimate
None
Fix versions
None
Days
None
Need QA
Yes
Labels
None
Sub-Product
None
Story Points
None
Environment
None
Updated just now
Open in Jira
✨ Summarize
More actions
Processing uploaded file… complete! Message ready to be sent.
loading…
SlackFileEditViewGoHistoryWindowHelpscreelDOCKER0 81DEV (-zsh)₴2APP (-zsh)whisper_init_state:whisper_init_state:kv padsize=2.36 MBcompute buffer (conv)whisper_init_state: compute buffer (encode) =whisper_init_state: compute buffer (cross)=whisper_init_state:compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocatingwhisper_backend_init_gpu: device 0: Metal (type:1)whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)whisper_backend_init_gpu: using Metal backendggml_metal_init: allocatingggml_metal_init: found device: Apple M1ggml_metal_init: picking default device: Apple M1ggml_metal_init:use fusion= trueggml_metal_init:use concurrency= trueggml_metal_init: use graph optimizetruewhisper_backend_init: using BLAS backendwhisper_init_state: kv self size3.15 MBwhisper_init_state: kv cross size =9.44 MBwhisper_init_state: kv padsize =2.36 MBwhisper_init_state: compute buffer (conv)whisper_init_state: compute buffer (encode) =whisper_init_state: compute buffer (cross)=whisper_init_state: compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocatingwhisper_backend_init_gpu:device 0: Metal (type: 1)whisper_backend_init_gpu: found GPUdevice 0: Metal (type: 1, cnt: 0)whisper_backend_init_gpu: using Metal backendggml_metal_init: allocatingggml_metal_init: found device: Apple M1ggml_metal_init: picking default device: Apple M1ggml_metal_init:use fusion= trueggml_metal_init:use concurrencytrueggml_metal_init:use graph optimizetruewhisper_backend_init: using BLAS backendwhisper_init_state: kv self size3.15 MBwhisper_init_state: kv cross size =9.44 MBwhisper_init_state: kv padsize=2.36 MBwhisper_init_state: compute buffer (conv)whisper_init_state: compute buffer (encode) =whisper_init_state: compute buffer (cross)whisper_init_state: compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocating2026-05-21T10:13:41.913005ZINFO screenpipe_audio::audio_manager::manager: reconciliatior2026-05-21710:15:15.5768762INFO screenpipe_engine::event_driven_capture: content dedup:j Support Daily - in 4h 45 m100% С8• Thu 21 May 10:15:32•••EDQHomeDMsActivityFilesLater•••More+→Describe what you are looking forJiminny ...ThreadsC9 Unreadsà platform-inner-teamGalya Dimitrova, Nikolay Yankov, and youa ThreadsHuddles• Drafts & sentDirectories01External connections* Starred& jiminny-x-integrati...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# curiosity_lab# engineering# general# happy_birthday# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# supportLukas Kovalik 31 minutes agoдобро утро, тази страница не трябва ли да япоказваме само ако няма reportsCleanShot 2026-05-21 at [EMAIL] your questions into ongoing insightsGalya Dimitrova 23 minutes agoДа, би трябвалоLukas Kovalik 22 minutes agoче сега ми го показва и ако имам reportLukas Kovalik 21 minutes agoна neptuneNewNikolay Yankov 6 minutes agoвсичко е наредReply...Also send to à platform-inner-team+AaYou're up to date...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65509
|
2309
|
4
|
2026-05-21T07:44:39.614794+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349479614_m2.jpg...
|
Slack
|
platform-inner-team (Channel) - Jiminny Inc - 5 ne platform-inner-team (Channel) - Jiminny Inc - 5 new items - Slack...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
happy_birthday
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Nikolay Yankov
Aneliya Angelova
Stoyan Tanev
James Graham
Stefka Stoyanova
Galya Dimitrova
Vasil Vasilev
Stoyan Tomov
Todor Stamatov
Lukas Kovalik
you
Jira Cloud
Toast
Unread mentions
Enable users to use their new activity types
Enable users to use their new activity types
Open in Jira Cloud
Jira Cloud
Details
Conversations 1
Description
Currently when customers create new activity types in their CRM, we ask them to create a new Playbook in order to fetch them. However now with the activity type automations that we have - this means they need to copy all of their prompts again. Which takes a huge amount of time.
For SF, Hubspot, Copper, Bullhorn, Close and Pipedrive (anything apart from Zoho)
when a new activity type is created in the CRM and fetched in Jiminny - add the activity type (in disabled state) to all the playbooks where activity type field is changed.
◦ this happens on the regular crm_field_metadata_sync
◦ introduce a button for the user on Playbooks page to trigger the sync synchronously - when a sync is done we s
…
Show more
Status
Backlog
Assignee
None
Reporter
Galya Dimitrova
Work Type
Story
Priority
Medium
Components
Platform
Sprint
Platform Sprint 5 Q2
Story point estimate
None
Fix versions
None
Days
None
Need QA
Yes
Labels
None
Sub-Product
None
Story Points
None
Environment
None
Updated just now
Open in Jira
✨ Summarize
More actions
Processing uploaded file… complete! Message ready to be sent.
loading…...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.0056515955,"top":0.058260176,"width":0.011968086,"height":0.028731046},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"bounds":{"left":0.0029920214,"top":0.10055866,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"bounds":{"left":0.0066489363,"top":0.13806863,"width":0.009973404,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.0029920214,"top":0.15482841,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"bounds":{"left":0.0076462766,"top":0.19233839,"width":0.007978723,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.0029920214,"top":0.20909816,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"bounds":{"left":0.004986702,"top":0.24660814,"width":0.012965426,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.005319149,"top":0.24660814,"width":0.0026595744,"height":0.011173184}},{"char_start":1,"char_count":7,"bounds":{"left":0.0076462766,"top":0.24660814,"width":0.010638298,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.0029920214,"top":0.26336792,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"bounds":{"left":0.0076462766,"top":0.3008779,"width":0.0076462766,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.007978723,"top":0.3008779,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.009973404,"top":0.3008779,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.0029920214,"top":0.31763768,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"bounds":{"left":0.00731383,"top":0.35514766,"width":0.008643617,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.00731383,"top":0.35514766,"width":0.0019946808,"height":0.011173184}},{"char_start":1,"char_count":4,"bounds":{"left":0.00930851,"top":0.35514766,"width":0.0066489363,"height":0.011173184}}],"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.0029920214,"top":0.3719074,"width":0.017287234,"height":0.054269753},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"bounds":{"left":0.006981383,"top":0.4094174,"width":0.008976064,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.00731383,"top":0.4094174,"width":0.0033244682,"height":0.011173184}},{"char_start":1,"char_count":3,"bounds":{"left":0.010638298,"top":0.4094174,"width":0.0056515955,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.036901597,"top":0.10055866,"width":0.01861702,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.036901597,"top":0.10055866,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.04055851,"top":0.10055866,"width":0.015292553,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.036901597,"top":0.12290503,"width":0.01761968,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.036901597,"top":0.12290503,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.039893616,"top":0.12290503,"width":0.01462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.036901597,"top":0.1452514,"width":0.017952127,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.036901597,"top":0.1452514,"width":0.0039893617,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.04089096,"top":0.1452514,"width":0.014295213,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.036901597,"top":0.16759777,"width":0.028922873,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.036901597,"top":0.16759777,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.04055851,"top":0.16759777,"width":0.025265958,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.08843085,"top":0.16839585,"width":0.0026595744,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.036901597,"top":0.18994413,"width":0.023936171,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.036901597,"top":0.18994413,"width":0.0039893617,"height":0.014365523}},{"char_start":1,"char_count":10,"bounds":{"left":0.04089096,"top":0.18994413,"width":0.020279255,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.042220745,"top":0.28411812,"width":0.043882977,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.28411812,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":24,"bounds":{"left":0.043550532,"top":0.28411812,"width":0.05418883,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.042220745,"top":0.3064645,"width":0.044215426,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.3064645,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":18,"bounds":{"left":0.045212764,"top":0.3064645,"width":0.04155585,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.042220745,"top":0.35913807,"width":0.022273935,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.35913807,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.04488032,"top":0.35913807,"width":0.019614361,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.042220745,"top":0.38148445,"width":0.011968086,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.38148445,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":5,"bounds":{"left":0.04488032,"top":0.38148445,"width":0.00930851,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.042220745,"top":0.4038308,"width":0.018284574,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.4038308,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.045212764,"top":0.4038308,"width":0.015292553,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.042220745,"top":0.42617717,"width":0.010305851,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.42617717,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":3,"bounds":{"left":0.045212764,"top":0.42617717,"width":0.00731383,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.042220745,"top":0.44852355,"width":0.034242023,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.44852355,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.04454787,"top":0.44852355,"width":0.032247342,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.042220745,"top":0.4708699,"width":0.027593086,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.4708699,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":12,"bounds":{"left":0.04454787,"top":0.4708699,"width":0.025265958,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.042220745,"top":0.49321628,"width":0.025598405,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.49321628,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":10,"bounds":{"left":0.04488032,"top":0.49321628,"width":0.022938829,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.042220745,"top":0.51556265,"width":0.015957447,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.51556265,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.04488032,"top":0.51556265,"width":0.013297873,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"happy_birthday","depth":23,"bounds":{"left":0.042220745,"top":0.53790903,"width":0.033909574,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.53790903,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":13,"bounds":{"left":0.045212764,"top":0.53790903,"width":0.030917553,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.042220745,"top":0.5602554,"width":0.022938829,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.5602554,"width":0.0013297872,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.043550532,"top":0.5602554,"width":0.021609042,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.042220745,"top":0.5826017,"width":0.034906916,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.5826017,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.045212764,"top":0.5826017,"width":0.031914894,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.042220745,"top":0.6049481,"width":0.03856383,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.6049481,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":15,"bounds":{"left":0.045212764,"top":0.6049481,"width":0.03557181,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.042220745,"top":0.6272945,"width":0.01662234,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.6272945,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":5,"bounds":{"left":0.044215426,"top":0.6272945,"width":0.014960106,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.042220745,"top":0.64964086,"width":0.018284574,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.64964086,"width":0.0019946808,"height":0.014365523}},{"char_start":1,"char_count":7,"bounds":{"left":0.044215426,"top":0.64964086,"width":0.016289894,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.042220745,"top":0.67198724,"width":0.024268618,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.67198724,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.04454787,"top":0.67198724,"width":0.021941489,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.042220745,"top":0.6943336,"width":0.016954787,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.042220745,"top":0.6943336,"width":0.0023271276,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.04454787,"top":0.6943336,"width":0.01462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.024268618,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.04488032,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.032912236,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.03756649,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.028922873,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.031914894,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.03756649,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.034906916,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.026263298,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tomov","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.030585106,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.034242023,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.02925532,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.07413564,"top":0.7086991,"width":0.0063164895,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.022273935,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.011968086,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Unread mentions","depth":17,"bounds":{"left":0.035904255,"top":0.68076617,"width":0.048204787,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Enable users to use their new activity types","depth":18,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Enable users to use their new activity types","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Open in Jira Cloud","depth":18,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jira Cloud","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXRadioButton","text":"Details","depth":19,"on_screen":false,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXRadioButton","text":"Conversations 1","depth":19,"on_screen":false,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Description","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Currently when customers create new activity types in their CRM, we ask them to create a new Playbook in order to fetch them. However now with the activity type automations that we have - this means they need to copy all of their prompts again. Which takes a huge amount of time.","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"For SF, Hubspot, Copper, Bullhorn, Close and Pipedrive (anything apart from Zoho)","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"when a new activity type is created in the CRM and fetched in Jiminny - add the activity type (in disabled state) to all the playbooks where activity type field is changed.","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"◦ this happens on the regular crm_field_metadata_sync","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"◦ introduce a button for the user on Playbooks page to trigger the sync synchronously - when a sync is done we s","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"…","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Show more","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Status","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Backlog","depth":20,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Assignee","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"None","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Reporter","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":20,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Work Type","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Story","depth":20,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Priority","depth":19,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Medium","depth":20,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Components","depth":19,"bounds":{"left":0.10372341,"top":0.0518755,"width":0.027925532,"height":0.003990423},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Platform","depth":19,"bounds":{"left":0.10372341,"top":0.065442935,"width":0.01861702,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.06624102,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":7,"bounds":{"left":0.106715426,"top":0.06624102,"width":0.015625,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Sprint","depth":19,"bounds":{"left":0.10372341,"top":0.09896249,"width":0.012965426,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.09976058,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":5,"bounds":{"left":0.10638298,"top":0.09976058,"width":0.010305851,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Platform Sprint 5 Q2","depth":19,"bounds":{"left":0.10372341,"top":0.12290503,"width":0.045212764,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.123703115,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":19,"bounds":{"left":0.106715426,"top":0.123703115,"width":0.042220745,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Story point estimate","depth":19,"bounds":{"left":0.10372341,"top":0.15642458,"width":0.044215426,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.15722266,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":19,"bounds":{"left":0.10638298,"top":0.15722266,"width":0.04155585,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"None","depth":21,"bounds":{"left":0.10372341,"top":0.1859537,"width":0.010970744,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.1867518,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":3,"bounds":{"left":0.107380316,"top":0.1867518,"width":0.0076462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Fix versions","depth":19,"bounds":{"left":0.10372341,"top":0.22505985,"width":0.025598405,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.22585794,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.106715426,"top":0.22585794,"width":0.022938829,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"None","depth":20,"bounds":{"left":0.10372341,"top":0.2490024,"width":0.010970744,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.24980047,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":3,"bounds":{"left":0.107380316,"top":0.24980047,"width":0.0076462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Days","depth":19,"bounds":{"left":0.10372341,"top":0.28252193,"width":0.010970744,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.28332004,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":3,"bounds":{"left":0.107380316,"top":0.28332004,"width":0.00731383,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"None","depth":21,"bounds":{"left":0.10372341,"top":0.3120511,"width":0.010970744,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.31284916,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":3,"bounds":{"left":0.107380316,"top":0.31284916,"width":0.0076462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Need QA","depth":19,"bounds":{"left":0.10372341,"top":0.35115722,"width":0.020279255,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.3519553,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":6,"bounds":{"left":0.107380316,"top":0.3519553,"width":0.01662234,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Yes","depth":20,"bounds":{"left":0.10372341,"top":0.38068634,"width":0.00731383,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.38148445,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":2,"bounds":{"left":0.10638298,"top":0.38148445,"width":0.004654255,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Labels","depth":19,"bounds":{"left":0.10372341,"top":0.4197925,"width":0.013962766,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.42059058,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":5,"bounds":{"left":0.10638298,"top":0.42059058,"width":0.011303191,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"None","depth":20,"bounds":{"left":0.10372341,"top":0.44373503,"width":0.010970744,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.4445331,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":3,"bounds":{"left":0.107380316,"top":0.4445331,"width":0.0076462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Sub-Product","depth":19,"bounds":{"left":0.10372341,"top":0.4772546,"width":0.027260639,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.47805268,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":10,"bounds":{"left":0.10638298,"top":0.47805268,"width":0.024601065,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"None","depth":20,"bounds":{"left":0.10372341,"top":0.5011971,"width":0.010970744,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.5019952,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":3,"bounds":{"left":0.107380316,"top":0.5019952,"width":0.0076462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Story Points","depth":19,"bounds":{"left":0.10372341,"top":0.53471667,"width":0.026263298,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.5355148,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":11,"bounds":{"left":0.10638298,"top":0.5355148,"width":0.023603724,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"None","depth":21,"bounds":{"left":0.10372341,"top":0.5642458,"width":0.010970744,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.56504387,"width":0.003656915,"height":0.014365523}},{"char_start":1,"char_count":3,"bounds":{"left":0.107380316,"top":0.56504387,"width":0.0076462766,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"Environment","depth":19,"bounds":{"left":0.10372341,"top":0.60335195,"width":0.027925532,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.60415006,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":10,"bounds":{"left":0.106715426,"top":0.60415006,"width":0.024933511,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"None","depth":20,"bounds":{"left":0.10372341,"top":0.6272945,"width":0.010970744,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Updated just now","depth":20,"bounds":{"left":0.10372341,"top":0.6703911,"width":0.03357713,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Open in Jira","depth":16,"bounds":{"left":0.10372341,"top":0.6679968,"width":0.045877658,"height":0.028731046},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"✨ Summarize","depth":16,"bounds":{"left":0.15226063,"top":0.6679968,"width":0.046875,"height":0.028731046},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More actions","depth":16,"bounds":{"left":0.2017952,"top":0.6679968,"width":0.011968086,"height":0.028731046},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Processing uploaded file… complete! Message ready to be sent.","depth":11,"bounds":{"left":0.0,"top":0.7126895,"width":0.022606382,"height":0.0007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"loading…","depth":11,"bounds":{"left":0.0,"top":0.7126895,"width":0.018949468,"height":0.0007980846},"on_screen":true,"role_description":"text"}]...
|
-8908168981360887910
|
-8125028145509691922
|
click
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
happy_birthday
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Nikolay Yankov
Aneliya Angelova
Stoyan Tanev
James Graham
Stefka Stoyanova
Galya Dimitrova
Vasil Vasilev
Stoyan Tomov
Todor Stamatov
Lukas Kovalik
you
Jira Cloud
Toast
Unread mentions
Enable users to use their new activity types
Enable users to use their new activity types
Open in Jira Cloud
Jira Cloud
Details
Conversations 1
Description
Currently when customers create new activity types in their CRM, we ask them to create a new Playbook in order to fetch them. However now with the activity type automations that we have - this means they need to copy all of their prompts again. Which takes a huge amount of time.
For SF, Hubspot, Copper, Bullhorn, Close and Pipedrive (anything apart from Zoho)
when a new activity type is created in the CRM and fetched in Jiminny - add the activity type (in disabled state) to all the playbooks where activity type field is changed.
◦ this happens on the regular crm_field_metadata_sync
◦ introduce a button for the user on Playbooks page to trigger the sync synchronously - when a sync is done we s
…
Show more
Status
Backlog
Assignee
None
Reporter
Galya Dimitrova
Work Type
Story
Priority
Medium
Components
Platform
Sprint
Platform Sprint 5 Q2
Story point estimate
None
Fix versions
None
Days
None
Need QA
Yes
Labels
None
Sub-Product
None
Story Points
None
Environment
None
Updated just now
Open in Jira
✨ Summarize
More actions
Processing uploaded file… complete! Message ready to be sent.
loading…
slackFV [EMAIL]=.phounit.result.cacheE .prettierignore= windsurtrulesphpde neloer.onophpide heloer_models.ohophp artisanM'CLAUDE.mdcomooser.isoncomooser.lockdependency-checker.json8 dev ison= ids tytl=infection.ison.distMLINSTAlI.mdMLINTERNAI WERHOOK SFTUP mdEjiminny_storageMiliconsos mdllM Makefile1рackace-lock. sonE phpstan.neon.dist= phostan-baseline.neon<> phpunit.xmlTe raw sal query.saM+ README.mdsô sonar-proiect propertiesE test.ov‹> Untitled Diaaram.xmliusvetur.confio.isM+ WEBHOOK FILTERING_IMPLEMENTATION.mo>1h External Librariesv =° Scratches and Consolesv batabase Consolesv AEU# console (EUlI DEAL RISKS (SU1A DITEUlA EU (EU]v Ajiminny@localhostA console (jiminny@localhost]# Di [liminny@localhostlA HS local [iiminny@localhostlA SF ['iiminny@localhost]& zoho dev [iiminny@localhost]V & PRODA console [PROD]& console 1 [PROD1LDIIPRODCActivityController.ong© ConvertLeadActivities.php= laravel.log4 SF jiminny@localhost]4 HS_local [jiminny@localhost]& console (PROD] X# console [euyLeadkepository.ong© PurgeLookupCache.php© SyncPlanhat.phpo synerorlannatpnpA console [STAGING]AcuivityLeadConverted.php© UserAutomatedreporscontroller.phpx© PlaybackController.php)Inteqrationapp/service.onoC) LeadConverted.ono570571C) CreateCommentedEvent.php(C) CreateSmsSentEvent.phpC) PlanhatActivityListener.php© AskAnythingPromptService.php572(C) AutomatedReportsRepositorv.php© AutomatedReportsCommand.phpphp api_v2.phpC) RequestGenerateReportJob.php573574© AutomatedReportResult.php(C) AutomatedReport.oho575use Jiminny \Services \Kiosk \AutomatedReports \ReportSortDirection;A1422 ^ v 576use Jiminny \Services\PlanhatService;use ectumtnace hutp kequestuse Inrowable,class UserAutomatedReportsController extends Controllenpublic const int RESULTS PER_ PAGE = 25:public const string SORT COLUMN = 'sort column':public const strina SORT DIRECTION = "sort direction':public function constructprivate readonly AutomatedReportsRepository $automatedReportsRepository.private readonly AutomatedRenortsService SautomatedRenortsServicelorivate readoni.v AniResponseService samiResponseServi.ce.orivate readoni.v Resnonse Sresnonse.private readonly PlanhatService $planhatService1...poST lanilv1lautomated-renorts/interest 1usadepublic function trackInterest(Request $request): JsonResponse(...}* Othnows ApplicationException58(09 >GET /api/v1/automated-reportspublic function list(Request Srequest): JsonResponse(...}125 0)DELETE/api/vl/automated-reports/kuuidpublic function delete(Request Srequest. string Suuid): JsonResponsef...} -609610--611612613616Tx: AutovSo jiminny vCONCAT(u.id, CASE WHEN U.id = t.owner_id THEN' (owner)' ELSE'' END) AS USEr_i041 A1 A40 V65 ^sa.*t.owner_id FROM social_accounts saNoun usens u on u.ide sa.sociablle 1diJOIN teams t 1..n<->1: on t.id = u.team_idWHERE u.team_id = 581 and sa.provider = 'salesforce';SELECT * FROM automated_report_results order by id desc;select * from features;select * from team_features where feature_id = 40;select * from teams where id = 556:select * trom automated reports:where id = 54: # 4fdd41f6-dcf0-30d0-b339-7345381b6044|"pat", "podcast"SELECT * FROM automated report results WHERE uuid to bin( '822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;select * from automated_report_results order by id desc;SELECT * FROMWHERE id = 1919:select * fromautomated report results WHERE report id = 54:select * from opportunities where id = 7594349:SELECT * FROM teams WHERE name LIKE '%Lesg': # 711. 692. [EMAIL] * from playbooks where team_id = 711; # event 226147SELEd * FROM Dlavbook catedonies WHERE Dlavbook 1d = 55151SELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event':SELECT * SROM eom fields WHEREI1d = 2261471SELECT * FROM crm_field_values WHERE crm_field_id = 226147;SELECT * FROM crm_configurations WHERE id = 692;SELSCTCONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '• END) AS user_id,v.emailsa.*,t.owner id FROM social accounts saJOIN users u on v.id = sa.sociable idJOIN teams t 1..n<->1: on t.id = u.team idWHERE U.team_id = 711 and sa.provider = 'salesforce";SELECT * FROM crm profiles cp JOIN users u 1..n<->1: on u.id = co.user id WHERE u.team_id = 711:select * from leadsselect * from calendarsSELECTS 0 hllsupoont Dally • In 4h 40m100% 52• Inu z1 May 10.10.34AskJiminnyReportActivityServiceTestvCascadePlaybook Categorie+0 ..connected. How isi. Can we vali eoneactivity tyee nith orit cabest aeeiewmane o, W dati anwsyggesinsingrow hohow to distinguishThoughts68 Fast Context How are playbook_categories populated and synced from crm_fields / crm_field_values... in 4.14s >Explored 4 files and searched 5 queriesRead ImportActivitvTypes.php #L95-104Searched olavbook cateaories in databaselmiarations (4) >egories|playbook_categories.*create in database/migrations (0)searched playoook_categor in database/migrations (<)Searched activity type in database/migrations (4)SurtingAsk anvthina (*4L)@ Codo Caudo Onue 17 ModiumNN Windeurf Toame 504.60...
|
65508
|
NULL
|
NULL
|
NULL
|
|
65507
|
2308
|
3
|
2026-05-21T07:44:36.323661+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349476323_m1.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"}]...
|
-6151875786856534370
|
-8717591544076362732
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65508
|
2309
|
3
|
2026-05-21T07:44:36.296703+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349476296_m2.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"bounds":{"left":0.15990691,"top":0.007980846,"width":0.2662899,"height":0.98324025},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"bounds":{"left":0.44547874,"top":0.09736632,"width":0.29022607,"height":0.8818835},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-1052979189915093189
|
-8141130793920488428
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65506
|
2309
|
2
|
2026-05-21T07:44:21.034497+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349461034_m2.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php
CleanDuplicateFieldDataCommand.php
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php
SetupActivityTypeForFollowUp.php
SetupCloseCrm.php
SetupCopperCrm.php
SetupCrmCommand.php
SetupLayouts.php
SyncAccount.php
SyncContact.php
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class
SyncProfileMetadata.php, class
SyncTeamMetadata.php, class
UpdateOpportunitySpecifications.php, class
DealInsights, folder
Dev, folder
Dialers, folder
DTOs
Elasticsearch
EngagementStats
GeckoExport
Livestream
Mailboxes, folder
Migrate
PlaybackThemes
Playbooks
Playlists, folder
Postmark, folder
ProphetAi, folder
Reports, folder
AutomatedReportsCommand.php
AutomatedReportsRetentionPolicyCommand.php
AutomatedReportsSendCommand.php
CreateMockAskJiminnyReportResultCommand.php
DeleteReportCommand.php
GenerateMarketingReport.php, class
Team.php, class
Usage.php, class
Slack
Teams
Tracks
Transcription
Twilio
Users
Vocabulary
Zoom
Command.php, class
CreateDatabaseUsers.php, class
DatabaseTableCount.php, class
DeleteOldAiCrmNotesCommand.php, class
DeleteS3LeftoversCommand.php, class
DevPostmanCommand.php, final class
DiarizeViaAiParticipantIdentificationCommand.php, class
EncryptTokensCommand.php, class
EngagementStatsRegenerateCommand.php, class
FeatureFlagsHelper.php
FixCrossTenantIssues.php, class
FlushRolesPermissionsCache.php, class
GenerateInternalWebhookToken.php, class
GroupSetDefaultLanguageCommand.php, final class
HelperTruncateCoachingTables.php, class
HubspotJournalPollingCommand.php, class
HubspotWebhookServiceCommand.php, class
ImportRecording.php, class
ImportUsersFromCsvFile.php, final class
IssueMcpTokenCommand.php, class
IterateUsersCommand.php
JiminnyCacheClearCommand.php
JiminnyDebugCommand.php, class
JiminnySetEncryptedTokenManagerModeCommand.php, class
JiminnyTokenInfoCommand.php, class
MakeSlackLiveCoachingChatNotesOn.php, class
ManageScimForTeam.php, class
MarkBranchForEnvironmentPipelineCommand.php, class
MuteOrganizerChannel.php, class
PhpApm.php, class
PropagateCoachingFeedbackCreatedAtToSectionFeedbacks.php, class
PurgeConferences.php, class
PurgeSoftDeletedOpportunitiesCommand.php, class
PurgeSyncBatchesCommand.php, class
RecalculateDealRisksCommand.php, class
RemoveDeleteMarkersCommand.php, class
RemoveExpiredNudgesCommand.php, class
RemoveUnusedParticipantSpeechesCommand.php, class
ResetElasticSearch.php, class
RestoreActivityCrmProviderIdCommand.php, class
RestoreActivityTypeCommand.php, class
RunAiCallScoringForUntypedActivitiesCommand.php
SeedActivities.php
SendNudgeExpirationWarningsCommand.php
SyncActivity.php
TrackImported.php
WhichWorkerIsWorkingOnWhichJob.php
Scheduling, folder...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"bounds":{"left":0.15990691,"top":0.007980846,"width":0.2662899,"height":0.98324025},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"bounds":{"left":0.44547874,"top":0.09736632,"width":0.29022607,"height":0.8818835},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackPage","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlist","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Prophet","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProsperWorks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Queue","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Router","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Saml2","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SCIM","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Seeder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sentry","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Serializer","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Settings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sidekick","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Slack","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TimeMemoryMapper","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Transcription","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TranscriptionSummary, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Twilio, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uploader, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UrlGenerator, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Utility, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uuid, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Waveform, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Webhooks, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Workflow, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Configuration","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Console","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Commands, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activities","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Analytics","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Calendars","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Crm","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Hubspot","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IntegrationApp","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Traits","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AddLayoutEntities.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutologDelayedCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BackfillOpportunityUserFromAccountCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornCommandAbstract.php, abstract class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornPingCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSearchCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSessionCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CheckActivityLoggableCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CleanDuplicateFieldDataCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FullSyncOpportunityCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LogActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ManageSyncStrategyCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchCrmObjectsCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchOpportunityActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MigrateProvider.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProcessHubspotObjectsSyncBatches.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PurgeDeletedOpportunitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ResetGovernorLimits.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SendNotLogged.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupActivityTypeForFollowUp.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCloseCrm.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCopperCrm.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCrmCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupLayouts.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncAccount.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncContact.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncFieldMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotActiveDeals.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncLead.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunitiesMissingFieldDataCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunity.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncProfileMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncTeamMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UpdateOpportunitySpecifications.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dev, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dialers, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DTOs","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Elasticsearch","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"EngagementStats","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GeckoExport","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Livestream","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Mailboxes, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Migrate","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackThemes","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playbooks","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlists, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Postmark, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Reports, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutomatedReportsCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutomatedReportsRetentionPolicyCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutomatedReportsSendCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CreateMockAskJiminnyReportResultCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DeleteReportCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GenerateMarketingReport.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Team.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Usage.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Slack","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Teams","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Tracks","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Transcription","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Twilio","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Users","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Vocabulary","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Zoom","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Command.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CreateDatabaseUsers.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DatabaseTableCount.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DeleteOldAiCrmNotesCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DeleteS3LeftoversCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DevPostmanCommand.php, final class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DiarizeViaAiParticipantIdentificationCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"EncryptTokensCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"EngagementStatsRegenerateCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlagsHelper.php","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FixCrossTenantIssues.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FlushRolesPermissionsCache.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GenerateInternalWebhookToken.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GroupSetDefaultLanguageCommand.php, final class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HelperTruncateCoachingTables.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HubspotJournalPollingCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HubspotWebhookServiceCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ImportRecording.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ImportUsersFromCsvFile.php, final class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IssueMcpTokenCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IterateUsersCommand.php","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"JiminnyCacheClearCommand.php","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"JiminnyDebugCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"JiminnySetEncryptedTokenManagerModeCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"JiminnyTokenInfoCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MakeSlackLiveCoachingChatNotesOn.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ManageScimForTeam.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MarkBranchForEnvironmentPipelineCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MuteOrganizerChannel.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PhpApm.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PropagateCoachingFeedbackCreatedAtToSectionFeedbacks.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PurgeConferences.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PurgeSoftDeletedOpportunitiesCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PurgeSyncBatchesCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"RecalculateDealRisksCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"RemoveDeleteMarkersCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"RemoveExpiredNudgesCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"RemoveUnusedParticipantSpeechesCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ResetElasticSearch.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"RestoreActivityCrmProviderIdCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"RestoreActivityTypeCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"RunAiCallScoringForUntypedActivitiesCommand.php","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SeedActivities.php","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SendNudgeExpirationWarningsCommand.php","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncActivity.php","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TrackImported.php","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"WhichWorkerIsWorkingOnWhichJob.php","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Scheduling, folder","depth":9,"on_screen":false,"role_description":"text"}]...
|
4125655130040039617
|
-6409497318090846956
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php
CleanDuplicateFieldDataCommand.php
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php
SetupActivityTypeForFollowUp.php
SetupCloseCrm.php
SetupCopperCrm.php
SetupCrmCommand.php
SetupLayouts.php
SyncAccount.php
SyncContact.php
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class
SyncProfileMetadata.php, class
SyncTeamMetadata.php, class
UpdateOpportunitySpecifications.php, class
DealInsights, folder
Dev, folder
Dialers, folder
DTOs
Elasticsearch
EngagementStats
GeckoExport
Livestream
Mailboxes, folder
Migrate
PlaybackThemes
Playbooks
Playlists, folder
Postmark, folder
ProphetAi, folder
Reports, folder
AutomatedReportsCommand.php
AutomatedReportsRetentionPolicyCommand.php
AutomatedReportsSendCommand.php
CreateMockAskJiminnyReportResultCommand.php
DeleteReportCommand.php
GenerateMarketingReport.php, class
Team.php, class
Usage.php, class
Slack
Teams
Tracks
Transcription
Twilio
Users
Vocabulary
Zoom
Command.php, class
CreateDatabaseUsers.php, class
DatabaseTableCount.php, class
DeleteOldAiCrmNotesCommand.php, class
DeleteS3LeftoversCommand.php, class
DevPostmanCommand.php, final class
DiarizeViaAiParticipantIdentificationCommand.php, class
EncryptTokensCommand.php, class
EngagementStatsRegenerateCommand.php, class
FeatureFlagsHelper.php
FixCrossTenantIssues.php, class
FlushRolesPermissionsCache.php, class
GenerateInternalWebhookToken.php, class
GroupSetDefaultLanguageCommand.php, final class
HelperTruncateCoachingTables.php, class
HubspotJournalPollingCommand.php, class
HubspotWebhookServiceCommand.php, class
ImportRecording.php, class
ImportUsersFromCsvFile.php, final class
IssueMcpTokenCommand.php, class
IterateUsersCommand.php
JiminnyCacheClearCommand.php
JiminnyDebugCommand.php, class
JiminnySetEncryptedTokenManagerModeCommand.php, class
JiminnyTokenInfoCommand.php, class
MakeSlackLiveCoachingChatNotesOn.php, class
ManageScimForTeam.php, class
MarkBranchForEnvironmentPipelineCommand.php, class
MuteOrganizerChannel.php, class
PhpApm.php, class
PropagateCoachingFeedbackCreatedAtToSectionFeedbacks.php, class
PurgeConferences.php, class
PurgeSoftDeletedOpportunitiesCommand.php, class
PurgeSyncBatchesCommand.php, class
RecalculateDealRisksCommand.php, class
RemoveDeleteMarkersCommand.php, class
RemoveExpiredNudgesCommand.php, class
RemoveUnusedParticipantSpeechesCommand.php, class
ResetElasticSearch.php, class
RestoreActivityCrmProviderIdCommand.php, class
RestoreActivityTypeCommand.php, class
RunAiCallScoringForUntypedActivitiesCommand.php
SeedActivities.php
SendNudgeExpirationWarningsCommand.php
SyncActivity.php
TrackImported.php
WhichWorkerIsWorkingOnWhichJob.php
Scheduling, folder...
|
65504
|
NULL
|
NULL
|
NULL
|
|
65505
|
2308
|
2
|
2026-05-21T07:44:20.853701+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349460853_m1.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php
CleanDuplicateFieldDataCommand.php
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php
SetupActivityTypeForFollowUp.php
SetupCloseCrm.php
SetupCopperCrm.php
SetupCrmCommand.php
SetupLayouts.php
SyncAccount.php
SyncContact.php
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class
SyncProfileMetadata.php, class
SyncTeamMetadata.php, class
UpdateOpportunitySpecifications.php, class
DealInsights, folder
Dev, folder
Dialers, folder
DTOs
Elasticsearch
EngagementStats
GeckoExport
Livestream
Mailboxes, folder
Migrate
PlaybackThemes...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackPage","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlist","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Prophet","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProsperWorks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Queue","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Router","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Saml2","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SCIM","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Seeder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sentry","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Serializer","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Settings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sidekick","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Slack","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TimeMemoryMapper","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Transcription","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TranscriptionSummary, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Twilio, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uploader, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UrlGenerator, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Utility, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uuid, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Waveform, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Webhooks, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Workflow, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Configuration","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Console","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Commands, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activities","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Analytics","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Calendars","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Crm","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Hubspot","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IntegrationApp","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Traits","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AddLayoutEntities.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutologDelayedCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BackfillOpportunityUserFromAccountCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornCommandAbstract.php, abstract class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornPingCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSearchCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSessionCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CheckActivityLoggableCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CleanDuplicateFieldDataCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FullSyncOpportunityCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LogActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ManageSyncStrategyCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchCrmObjectsCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchOpportunityActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MigrateProvider.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProcessHubspotObjectsSyncBatches.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PurgeDeletedOpportunitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ResetGovernorLimits.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SendNotLogged.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupActivityTypeForFollowUp.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCloseCrm.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCopperCrm.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCrmCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupLayouts.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncAccount.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncContact.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncFieldMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotActiveDeals.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncLead.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunitiesMissingFieldDataCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunity.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncProfileMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncTeamMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UpdateOpportunitySpecifications.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dev, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dialers, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DTOs","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Elasticsearch","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"EngagementStats","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GeckoExport","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Livestream","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Mailboxes, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Migrate","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackThemes","depth":10,"on_screen":false,"role_description":"text"}]...
|
-9223056471733185465
|
-8717589928094988012
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php
CleanDuplicateFieldDataCommand.php
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php
SetupActivityTypeForFollowUp.php
SetupCloseCrm.php
SetupCopperCrm.php
SetupCrmCommand.php
SetupLayouts.php
SyncAccount.php
SyncContact.php
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class
SyncProfileMetadata.php, class
SyncTeamMetadata.php, class
UpdateOpportunitySpecifications.php, class
DealInsights, folder
Dev, folder
Dialers, folder
DTOs
Elasticsearch
EngagementStats
GeckoExport
Livestream
Mailboxes, folder
Migrate
PlaybackThemes...
|
65503
|
NULL
|
NULL
|
NULL
|
|
65504
|
2309
|
1
|
2026-05-21T07:43:50.657371+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349430657_m2.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"bounds":{"left":0.15990691,"top":0.007980846,"width":0.2662899,"height":0.98324025},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false}]...
|
8830251352522217365
|
-8708584105377178620
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65503
|
2308
|
1
|
2026-05-21T07:43:50.471601+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349430471_m1.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php
CleanDuplicateFieldDataCommand.php
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php
SetupActivityTypeForFollowUp.php
SetupCloseCrm.php
SetupCopperCrm.php
SetupCrmCommand.php
SetupLayouts.php
SyncAccount.php
SyncContact.php
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class
SyncProfileMetadata.php, class
SyncTeamMetadata.php, class
UpdateOpportunitySpecifications.php, class
DealInsights, folder
Dev, folder
Dialers, folder
DTOs
Elasticsearch
EngagementStats
GeckoExport
Livestream
Mailboxes, folder
Migrate
PlaybackThemes
Playbooks
Playlists, folder
Postmark, folder
ProphetAi, folder
Reports, folder
AutomatedReportsCommand.php
AutomatedReportsRetentionPolicyCommand.php
AutomatedReportsSendCommand.php
CreateMockAskJiminnyReportResultCommand.php
DeleteReportCommand.php
GenerateMarketingReport.php, class
Team.php, class...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackPage","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlist","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Prophet","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProsperWorks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Queue","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Router","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Saml2","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SCIM","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Seeder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sentry","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Serializer","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Settings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sidekick","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Slack","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TimeMemoryMapper","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Transcription","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TranscriptionSummary, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Twilio, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uploader, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UrlGenerator, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Utility, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uuid, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Waveform, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Webhooks, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Workflow, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Configuration","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Console","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Commands, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activities","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Analytics","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Calendars","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Crm","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Hubspot","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IntegrationApp","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Traits","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AddLayoutEntities.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutologDelayedCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BackfillOpportunityUserFromAccountCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornCommandAbstract.php, abstract class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornPingCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSearchCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSessionCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CheckActivityLoggableCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CleanDuplicateFieldDataCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FullSyncOpportunityCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LogActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ManageSyncStrategyCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchCrmObjectsCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchOpportunityActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MigrateProvider.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProcessHubspotObjectsSyncBatches.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PurgeDeletedOpportunitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ResetGovernorLimits.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SendNotLogged.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupActivityTypeForFollowUp.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCloseCrm.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCopperCrm.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCrmCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupLayouts.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncAccount.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncContact.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncFieldMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotActiveDeals.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncLead.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunitiesMissingFieldDataCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunity.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncProfileMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncTeamMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UpdateOpportunitySpecifications.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dev, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dialers, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DTOs","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Elasticsearch","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"EngagementStats","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GeckoExport","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Livestream","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Mailboxes, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Migrate","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackThemes","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playbooks","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlists, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Postmark, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Reports, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutomatedReportsCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutomatedReportsRetentionPolicyCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutomatedReportsSendCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CreateMockAskJiminnyReportResultCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DeleteReportCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GenerateMarketingReport.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Team.php, class","depth":11,"on_screen":false,"role_description":"text"}]...
|
-4331963242933399359
|
-8715337578525487852
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php
CleanDuplicateFieldDataCommand.php
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php
SetupActivityTypeForFollowUp.php
SetupCloseCrm.php
SetupCopperCrm.php
SetupCrmCommand.php
SetupLayouts.php
SyncAccount.php
SyncContact.php
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class
SyncProfileMetadata.php, class
SyncTeamMetadata.php, class
UpdateOpportunitySpecifications.php, class
DealInsights, folder
Dev, folder
Dialers, folder
DTOs
Elasticsearch
EngagementStats
GeckoExport
Livestream
Mailboxes, folder
Migrate
PlaybackThemes
Playbooks
Playlists, folder
Postmark, folder
ProphetAi, folder
Reports, folder
AutomatedReportsCommand.php
AutomatedReportsRetentionPolicyCommand.php
AutomatedReportsSendCommand.php
CreateMockAskJiminnyReportResultCommand.php
DeleteReportCommand.php
GenerateMarketingReport.php, class
Team.php, class...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65502
|
2309
|
0
|
2026-05-21T07:43:20.284617+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349400284_m2.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php
CleanDuplicateFieldDataCommand.php
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php
SetupActivityTypeForFollowUp.php
SetupCloseCrm.php
SetupCopperCrm.php
SetupCrmCommand.php
SetupLayouts.php
SyncAccount.php
SyncContact.php
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class
SyncProfileMetadata.php, class
SyncTeamMetadata.php, class
UpdateOpportunitySpecifications.php, class
DealInsights, folder
Dev, folder
Dialers, folder
DTOs
Elasticsearch
EngagementStats
GeckoExport
Livestream
Mailboxes, folder
Migrate
PlaybackThemes
Playbooks
Playlists, folder
Postmark, folder
ProphetAi, folder
Reports, folder
AutomatedReportsCommand.php
AutomatedReportsRetentionPolicyCommand.php
AutomatedReportsSendCommand.php
CreateMockAskJiminnyReportResultCommand.php
DeleteReportCommand.php
GenerateMarketingReport.php, class
Team.php, class
Usage.php, class
Slack
Teams
Tracks
Transcription
Twilio
Users
Vocabulary
Zoom
Command.php, class
CreateDatabaseUsers.php, class
DatabaseTableCount.php, class
DeleteOldAiCrmNotesCommand.php, class
DeleteS3LeftoversCommand.php, class
DevPostmanCommand.php, final class
DiarizeViaAiParticipantIdentificationCommand.php, class
EncryptTokensCommand.php, class
EngagementStatsRegenerateCommand.php, class
FeatureFlagsHelper.php
FixCrossTenantIssues.php, class
FlushRolesPermissionsCache.php, class
GenerateInternalWebhookToken.php, class
GroupSetDefaultLanguageCommand.php, final class
HelperTruncateCoachingTables.php, class
HubspotJournalPollingCommand.php, class
HubspotWebhookServiceCommand.php, class
ImportRecording.php, class...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"bounds":{"left":0.15990691,"top":0.007980846,"width":0.2662899,"height":0.98324025},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"bounds":{"left":0.44547874,"top":0.09736632,"width":0.29022607,"height":0.8818835},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackPage","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlist","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Prophet","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProsperWorks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Queue","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Router","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Saml2","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SCIM","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Seeder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sentry","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Serializer","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Settings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sidekick","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Slack","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TimeMemoryMapper","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Transcription","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TranscriptionSummary, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Twilio, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uploader, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UrlGenerator, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Utility, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uuid, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Waveform, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Webhooks, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Workflow, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Configuration","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Console","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Commands, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activities","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Analytics","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Calendars","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Crm","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Hubspot","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IntegrationApp","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Traits","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AddLayoutEntities.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutologDelayedCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BackfillOpportunityUserFromAccountCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornCommandAbstract.php, abstract class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornPingCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSearchCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSessionCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CheckActivityLoggableCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CleanDuplicateFieldDataCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FullSyncOpportunityCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LogActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ManageSyncStrategyCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchCrmObjectsCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchOpportunityActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MigrateProvider.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProcessHubspotObjectsSyncBatches.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PurgeDeletedOpportunitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ResetGovernorLimits.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SendNotLogged.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupActivityTypeForFollowUp.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCloseCrm.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCopperCrm.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCrmCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupLayouts.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncAccount.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncContact.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncFieldMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotActiveDeals.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncLead.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunitiesMissingFieldDataCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunity.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncProfileMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncTeamMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UpdateOpportunitySpecifications.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dev, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dialers, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DTOs","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Elasticsearch","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"EngagementStats","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GeckoExport","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Livestream","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Mailboxes, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Migrate","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackThemes","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playbooks","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlists, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Postmark, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Reports, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutomatedReportsCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutomatedReportsRetentionPolicyCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutomatedReportsSendCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CreateMockAskJiminnyReportResultCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DeleteReportCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GenerateMarketingReport.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Team.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Usage.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Slack","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Teams","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Tracks","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Transcription","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Twilio","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Users","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Vocabulary","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Zoom","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Command.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CreateDatabaseUsers.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DatabaseTableCount.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DeleteOldAiCrmNotesCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DeleteS3LeftoversCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DevPostmanCommand.php, final class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DiarizeViaAiParticipantIdentificationCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"EncryptTokensCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"EngagementStatsRegenerateCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlagsHelper.php","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FixCrossTenantIssues.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FlushRolesPermissionsCache.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GenerateInternalWebhookToken.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GroupSetDefaultLanguageCommand.php, final class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HelperTruncateCoachingTables.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HubspotJournalPollingCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HubspotWebhookServiceCommand.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ImportRecording.php, class","depth":10,"on_screen":false,"role_description":"text"}]...
|
-5269841006065165550
|
-6409495119067591404
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php
CleanDuplicateFieldDataCommand.php
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php
SetupActivityTypeForFollowUp.php
SetupCloseCrm.php
SetupCopperCrm.php
SetupCrmCommand.php
SetupLayouts.php
SyncAccount.php
SyncContact.php
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class
SyncProfileMetadata.php, class
SyncTeamMetadata.php, class
UpdateOpportunitySpecifications.php, class
DealInsights, folder
Dev, folder
Dialers, folder
DTOs
Elasticsearch
EngagementStats
GeckoExport
Livestream
Mailboxes, folder
Migrate
PlaybackThemes
Playbooks
Playlists, folder
Postmark, folder
ProphetAi, folder
Reports, folder
AutomatedReportsCommand.php
AutomatedReportsRetentionPolicyCommand.php
AutomatedReportsSendCommand.php
CreateMockAskJiminnyReportResultCommand.php
DeleteReportCommand.php
GenerateMarketingReport.php, class
Team.php, class
Usage.php, class
Slack
Teams
Tracks
Transcription
Twilio
Users
Vocabulary
Zoom
Command.php, class
CreateDatabaseUsers.php, class
DatabaseTableCount.php, class
DeleteOldAiCrmNotesCommand.php, class
DeleteS3LeftoversCommand.php, class
DevPostmanCommand.php, final class
DiarizeViaAiParticipantIdentificationCommand.php, class
EncryptTokensCommand.php, class
EngagementStatsRegenerateCommand.php, class
FeatureFlagsHelper.php
FixCrossTenantIssues.php, class
FlushRolesPermissionsCache.php, class
GenerateInternalWebhookToken.php, class
GroupSetDefaultLanguageCommand.php, final class
HelperTruncateCoachingTables.php, class
HubspotJournalPollingCommand.php, class
HubspotWebhookServiceCommand.php, class
ImportRecording.php, class...
|
65500
|
NULL
|
NULL
|
NULL
|
|
65501
|
2308
|
0
|
2026-05-21T07:43:20.152555+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349400152_m1.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php
CleanDuplicateFieldDataCommand.php
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php
SetupActivityTypeForFollowUp.php
SetupCloseCrm.php
SetupCopperCrm.php
SetupCrmCommand.php
SetupLayouts.php
SyncAccount.php
SyncContact.php
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class
SyncProfileMetadata.php, class
SyncTeamMetadata.php, class
UpdateOpportunitySpecifications.php, class
DealInsights, folder
Dev, folder
Dialers, folder
DTOs
Elasticsearch
EngagementStats
GeckoExport
Livestream
Mailboxes, folder
Migrate
PlaybackThemes
Playbooks
Playlists, folder
Postmark, folder
ProphetAi, folder
Reports, folder
AutomatedReportsCommand.php
AutomatedReportsRetentionPolicyCommand.php
AutomatedReportsSendCommand.php
CreateMockAskJiminnyReportResultCommand.php
DeleteReportCommand.php
GenerateMarketingReport.php, class
Team.php, class...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackPage","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlist","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Prophet","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProsperWorks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Queue","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Router","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Saml2","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SCIM","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Seeder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sentry","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Serializer","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Settings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sidekick","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Slack","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TimeMemoryMapper","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Transcription","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TranscriptionSummary, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Twilio, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uploader, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UrlGenerator, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Utility, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uuid, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Waveform, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Webhooks, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Workflow, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Configuration","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Console","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Commands, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activities","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Analytics","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Calendars","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Crm","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Hubspot","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IntegrationApp","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Traits","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AddLayoutEntities.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutologDelayedCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BackfillOpportunityUserFromAccountCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornCommandAbstract.php, abstract class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornPingCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSearchCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSessionCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CheckActivityLoggableCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CleanDuplicateFieldDataCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FullSyncOpportunityCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LogActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ManageSyncStrategyCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchCrmObjectsCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchOpportunityActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MigrateProvider.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProcessHubspotObjectsSyncBatches.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PurgeDeletedOpportunitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ResetGovernorLimits.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SendNotLogged.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupActivityTypeForFollowUp.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCloseCrm.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCopperCrm.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCrmCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupLayouts.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncAccount.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncContact.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncFieldMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotActiveDeals.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncLead.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunitiesMissingFieldDataCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunity.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncProfileMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncTeamMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UpdateOpportunitySpecifications.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dev, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dialers, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DTOs","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Elasticsearch","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"EngagementStats","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GeckoExport","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Livestream","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Mailboxes, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Migrate","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackThemes","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playbooks","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlists, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Postmark, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Reports, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutomatedReportsCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutomatedReportsRetentionPolicyCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutomatedReportsSendCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CreateMockAskJiminnyReportResultCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DeleteReportCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GenerateMarketingReport.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Team.php, class","depth":11,"on_screen":false,"role_description":"text"}]...
|
-4331963242933399359
|
-8715337578525487852
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php
CleanDuplicateFieldDataCommand.php
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php
SetupActivityTypeForFollowUp.php
SetupCloseCrm.php
SetupCopperCrm.php
SetupCrmCommand.php
SetupLayouts.php
SyncAccount.php
SyncContact.php
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class
SyncProfileMetadata.php, class
SyncTeamMetadata.php, class
UpdateOpportunitySpecifications.php, class
DealInsights, folder
Dev, folder
Dialers, folder
DTOs
Elasticsearch
EngagementStats
GeckoExport
Livestream
Mailboxes, folder
Migrate
PlaybackThemes
Playbooks
Playlists, folder
Postmark, folder
ProphetAi, folder
Reports, folder
AutomatedReportsCommand.php
AutomatedReportsRetentionPolicyCommand.php
AutomatedReportsSendCommand.php
CreateMockAskJiminnyReportResultCommand.php
DeleteReportCommand.php
GenerateMarketingReport.php, class
Team.php, class...
|
65499
|
NULL
|
NULL
|
NULL
|
|
65500
|
NULL
|
0
|
2026-05-21T07:42:49.907216+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349369907_m2.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php
CleanDuplicateFieldDataCommand.php
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php
SetupActivityTypeForFollowUp.php
SetupCloseCrm.php
SetupCopperCrm.php
SetupCrmCommand.php
SetupLayouts.php
SyncAccount.php
SyncContact.php
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class
SyncProfileMetadata.php, class
SyncTeamMetadata.php, class
UpdateOpportunitySpecifications.php, class
DealInsights, folder
Dev, folder
Dialers, folder
DTOs
Elasticsearch
EngagementStats
GeckoExport
Livestream
Mailboxes, folder
Migrate
PlaybackThemes
Playbooks
Playlists, folder
Postmark, folder...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"bounds":{"left":0.15990691,"top":0.007980846,"width":0.2662899,"height":0.98324025},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"bounds":{"left":0.44547874,"top":0.09736632,"width":0.29022607,"height":0.8818835},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackPage","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlist","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Prophet","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProsperWorks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Queue","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Router","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Saml2","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SCIM","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Seeder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sentry","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Serializer","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Settings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sidekick","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Slack","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TimeMemoryMapper","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Transcription","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TranscriptionSummary, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Twilio, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uploader, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UrlGenerator, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Utility, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uuid, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Waveform, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Webhooks, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Workflow, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Configuration","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Console","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Commands, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activities","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Analytics","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Calendars","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Crm","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Hubspot","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IntegrationApp","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Traits","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AddLayoutEntities.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutologDelayedCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BackfillOpportunityUserFromAccountCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornCommandAbstract.php, abstract class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornPingCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSearchCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSessionCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CheckActivityLoggableCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CleanDuplicateFieldDataCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FullSyncOpportunityCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LogActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ManageSyncStrategyCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchCrmObjectsCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchOpportunityActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MigrateProvider.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProcessHubspotObjectsSyncBatches.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PurgeDeletedOpportunitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ResetGovernorLimits.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SendNotLogged.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupActivityTypeForFollowUp.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCloseCrm.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCopperCrm.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCrmCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupLayouts.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncAccount.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncContact.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncFieldMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotActiveDeals.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncLead.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunitiesMissingFieldDataCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunity.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncProfileMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncTeamMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UpdateOpportunitySpecifications.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dev, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dialers, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DTOs","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Elasticsearch","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"EngagementStats","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GeckoExport","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Livestream","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Mailboxes, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Migrate","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackThemes","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playbooks","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlists, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Postmark, folder","depth":10,"on_screen":false,"role_description":"text"}]...
|
-2571589278577124073
|
-8717589928094986988
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php
CleanDuplicateFieldDataCommand.php
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php
SetupActivityTypeForFollowUp.php
SetupCloseCrm.php
SetupCopperCrm.php
SetupCrmCommand.php
SetupLayouts.php
SyncAccount.php
SyncContact.php
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class
SyncProfileMetadata.php, class
SyncTeamMetadata.php, class
UpdateOpportunitySpecifications.php, class
DealInsights, folder
Dev, folder
Dialers, folder
DTOs
Elasticsearch
EngagementStats
GeckoExport
Livestream
Mailboxes, folder
Migrate
PlaybackThemes
Playbooks
Playlists, folder
Postmark, folder...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65499
|
NULL
|
0
|
2026-05-21T07:42:49.824470+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349369824_m1.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php
CleanDuplicateFieldDataCommand.php
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php
SetupActivityTypeForFollowUp.php
SetupCloseCrm.php
SetupCopperCrm.php
SetupCrmCommand.php
SetupLayouts.php
SyncAccount.php
SyncContact.php
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class
SyncProfileMetadata.php, class
SyncTeamMetadata.php, class
UpdateOpportunitySpecifications.php, class
DealInsights, folder
Dev, folder
Dialers, folder
DTOs
Elasticsearch
EngagementStats
GeckoExport
Livestream
Mailboxes, folder
Migrate
PlaybackThemes
Playbooks
Playlists, folder
Postmark, folder
ProphetAi, folder
Reports, folder
AutomatedReportsCommand.php
AutomatedReportsRetentionPolicyCommand.php
AutomatedReportsSendCommand.php
CreateMockAskJiminnyReportResultCommand.php
DeleteReportCommand.php
GenerateMarketingReport.php, class
Team.php, class
Usage.php, class...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackPage","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlist","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Prophet","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProsperWorks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Queue","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Router","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Saml2","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SCIM","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Seeder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sentry","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Serializer","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Settings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sidekick","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Slack","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TimeMemoryMapper","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Transcription","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TranscriptionSummary, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Twilio, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uploader, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UrlGenerator, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Utility, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uuid, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Waveform, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Webhooks, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Workflow, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Configuration","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Console","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Commands, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activities","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Analytics","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Calendars","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Crm","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Hubspot","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IntegrationApp","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Traits","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AddLayoutEntities.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutologDelayedCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BackfillOpportunityUserFromAccountCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornCommandAbstract.php, abstract class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornPingCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSearchCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSessionCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CheckActivityLoggableCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CleanDuplicateFieldDataCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FullSyncOpportunityCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LogActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ManageSyncStrategyCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchCrmObjectsCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchOpportunityActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MigrateProvider.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProcessHubspotObjectsSyncBatches.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PurgeDeletedOpportunitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ResetGovernorLimits.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SendNotLogged.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupActivityTypeForFollowUp.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCloseCrm.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCopperCrm.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCrmCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupLayouts.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncAccount.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncContact.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncFieldMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotActiveDeals.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncLead.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunitiesMissingFieldDataCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunity.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncProfileMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncTeamMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UpdateOpportunitySpecifications.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dev, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dialers, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DTOs","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Elasticsearch","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"EngagementStats","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GeckoExport","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Livestream","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Mailboxes, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Migrate","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackThemes","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playbooks","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlists, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Postmark, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Reports, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutomatedReportsCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutomatedReportsRetentionPolicyCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutomatedReportsSendCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CreateMockAskJiminnyReportResultCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DeleteReportCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GenerateMarketingReport.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Team.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Usage.php, class","depth":11,"on_screen":false,"role_description":"text"}]...
|
4668560580297988277
|
-8715337578525488876
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php
CleanDuplicateFieldDataCommand.php
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php
SetupActivityTypeForFollowUp.php
SetupCloseCrm.php
SetupCopperCrm.php
SetupCrmCommand.php
SetupLayouts.php
SyncAccount.php
SyncContact.php
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class
SyncProfileMetadata.php, class
SyncTeamMetadata.php, class
UpdateOpportunitySpecifications.php, class
DealInsights, folder
Dev, folder
Dialers, folder
DTOs
Elasticsearch
EngagementStats
GeckoExport
Livestream
Mailboxes, folder
Migrate
PlaybackThemes
Playbooks
Playlists, folder
Postmark, folder
ProphetAi, folder
Reports, folder
AutomatedReportsCommand.php
AutomatedReportsRetentionPolicyCommand.php
AutomatedReportsSendCommand.php
CreateMockAskJiminnyReportResultCommand.php
DeleteReportCommand.php
GenerateMarketingReport.php, class
Team.php, class
Usage.php, class...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65498
|
2307
|
24
|
2026-05-21T07:42:19.478300+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349339478_m2.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"bounds":{"left":0.15990691,"top":0.007980846,"width":0.2662899,"height":0.98324025},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"bounds":{"left":0.44547874,"top":0.09736632,"width":0.29022607,"height":0.8818835},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"}]...
|
-6432662851748720335
|
-8132123592518247404
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf...
|
65496
|
NULL
|
NULL
|
NULL
|
|
65497
|
2306
|
30
|
2026-05-21T07:42:19.478269+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349339478_m1.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"}]...
|
5177837308458605725
|
-8717730082541445868
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags...
|
65495
|
NULL
|
NULL
|
NULL
|
|
65496
|
2307
|
23
|
2026-05-21T07:42:16.285834+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349336285_m2.jpg...
|
PhpStorm
|
faVsco.js – MetadataProcessor.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Close\Processor;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Exceptions\RuntimeException;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmConfigurationRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\UserRepository;
use Jiminny\Services\Crm\Metadata\FieldMetadata;
use Jiminny\Services\Crm\Metadata\OrganisationMetadata;
use Jiminny\Services\Crm\Metadata\PipelineMetadata;
use Jiminny\Services\Crm\Metadata\ProfileMetadata;
class MetadataProcessor
{
private ?Configuration $crm = null;
private TeamRepository $teamRepository;
private UserRepository $userRepository;
private CrmConfigurationRepository $crmConfigurationRepository;
private FieldRepository $fieldRepository;
public function __construct(
TeamRepository $teamRepository,
UserRepository $userRepository,
CrmConfigurationRepository $crmConfigurationRepository,
FieldRepository $fieldRepository
) {
$this->teamRepository = $teamRepository;
$this->userRepository = $userRepository;
$this->crmConfigurationRepository = $crmConfigurationRepository;
$this->fieldRepository = $fieldRepository;
}
public function setConfiguration(Configuration $crm): void
{
$this->crm = $crm;
}
/**
* @throws RuntimeException
*/
private function getConfiguration(): Configuration
{
if (! $this->crm instanceof Configuration) {
throw new RuntimeException('Configuration not set');
}
return $this->crm;
}
public function syncOrganisation(OrganisationMetadata $organisationMetadata): void
{
$this->crmConfigurationRepository->updateConfiguration($this->getConfiguration(), $organisationMetadata);
}
public function syncPipeline(PipelineMetadata $pipelineMetadata): ?BusinessProcess
{
$businessProcess = $this->crmConfigurationRepository
->updateOrCreatePipeline($this->getConfiguration(), $pipelineMetadata);
// A record type connects an opportunity to a business process (pipeline)
$this->syncRecordType($pipelineMetadata, $businessProcess);
$this->syncPipelineStages($businessProcess, $pipelineMetadata);
return $businessProcess;
}
public function syncProfile(ProfileMetadata $profileMetadata): ?Profile
{
$user = $this->teamRepository->findActiveTeamMemberByEmail(
$this->getConfiguration()->getTeam(),
$profileMetadata->getEmail()
);
if (! $user instanceof User) {
return null;
}
return $this->userRepository->updateOrCreateCrmProfile($user, $profileMetadata->getId());
}
public function syncField(FieldMetadata $fieldMetadata): Field
{
$field = $this->crmConfigurationRepository->updateOrCreateField($this->getConfiguration(), $fieldMetadata);
if ($fieldMetadata->getType() === Field::TYPE_PICKLIST) {
$this->fieldRepository->updatePicklistValues($field, $fieldMetadata->getOptions());
}
return $field;
}
private function syncPipelineStages(BusinessProcess $pipeline, PipelineMetadata $pipelineMetadata): void
{
$this->crmConfigurationRepository->updateOrCreatePipelineStages($pipeline, $pipelineMetadata->getStages());
}
private function syncRecordType(
PipelineMetadata $pipelineMetadata,
?BusinessProcess $pipeline
): void {
$this->crmConfigurationRepository->updateOrCreateRecordType(
$this->getConfiguration(),
$pipelineMetadata,
$pipeline
);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Close\\Processor;\n\nuse Jiminny\\Contracts\\Repositories\\TeamRepository;\nuse Jiminny\\Exceptions\\RuntimeException;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmConfigurationRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse Jiminny\\Services\\Crm\\Metadata\\FieldMetadata;\nuse Jiminny\\Services\\Crm\\Metadata\\OrganisationMetadata;\nuse Jiminny\\Services\\Crm\\Metadata\\PipelineMetadata;\nuse Jiminny\\Services\\Crm\\Metadata\\ProfileMetadata;\n\nclass MetadataProcessor\n{\n private ?Configuration $crm = null;\n private TeamRepository $teamRepository;\n private UserRepository $userRepository;\n private CrmConfigurationRepository $crmConfigurationRepository;\n private FieldRepository $fieldRepository;\n\n public function __construct(\n TeamRepository $teamRepository,\n UserRepository $userRepository,\n CrmConfigurationRepository $crmConfigurationRepository,\n FieldRepository $fieldRepository\n ) {\n $this->teamRepository = $teamRepository;\n $this->userRepository = $userRepository;\n $this->crmConfigurationRepository = $crmConfigurationRepository;\n $this->fieldRepository = $fieldRepository;\n }\n\n public function setConfiguration(Configuration $crm): void\n {\n $this->crm = $crm;\n }\n\n /**\n * @throws RuntimeException\n */\n private function getConfiguration(): Configuration\n {\n if (! $this->crm instanceof Configuration) {\n throw new RuntimeException('Configuration not set');\n }\n\n return $this->crm;\n }\n\n public function syncOrganisation(OrganisationMetadata $organisationMetadata): void\n {\n $this->crmConfigurationRepository->updateConfiguration($this->getConfiguration(), $organisationMetadata);\n }\n\n public function syncPipeline(PipelineMetadata $pipelineMetadata): ?BusinessProcess\n {\n $businessProcess = $this->crmConfigurationRepository\n ->updateOrCreatePipeline($this->getConfiguration(), $pipelineMetadata);\n\n // A record type connects an opportunity to a business process (pipeline)\n $this->syncRecordType($pipelineMetadata, $businessProcess);\n\n $this->syncPipelineStages($businessProcess, $pipelineMetadata);\n\n return $businessProcess;\n }\n\n public function syncProfile(ProfileMetadata $profileMetadata): ?Profile\n {\n $user = $this->teamRepository->findActiveTeamMemberByEmail(\n $this->getConfiguration()->getTeam(),\n $profileMetadata->getEmail()\n );\n\n if (! $user instanceof User) {\n return null;\n }\n\n return $this->userRepository->updateOrCreateCrmProfile($user, $profileMetadata->getId());\n }\n\n public function syncField(FieldMetadata $fieldMetadata): Field\n {\n $field = $this->crmConfigurationRepository->updateOrCreateField($this->getConfiguration(), $fieldMetadata);\n\n if ($fieldMetadata->getType() === Field::TYPE_PICKLIST) {\n $this->fieldRepository->updatePicklistValues($field, $fieldMetadata->getOptions());\n }\n\n return $field;\n }\n\n private function syncPipelineStages(BusinessProcess $pipeline, PipelineMetadata $pipelineMetadata): void\n {\n $this->crmConfigurationRepository->updateOrCreatePipelineStages($pipeline, $pipelineMetadata->getStages());\n }\n\n private function syncRecordType(\n PipelineMetadata $pipelineMetadata,\n ?BusinessProcess $pipeline\n ): void {\n $this->crmConfigurationRepository->updateOrCreateRecordType(\n $this->getConfiguration(),\n $pipelineMetadata,\n $pipeline\n );\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Close\\Processor;\n\nuse Jiminny\\Contracts\\Repositories\\TeamRepository;\nuse Jiminny\\Exceptions\\RuntimeException;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmConfigurationRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse Jiminny\\Services\\Crm\\Metadata\\FieldMetadata;\nuse Jiminny\\Services\\Crm\\Metadata\\OrganisationMetadata;\nuse Jiminny\\Services\\Crm\\Metadata\\PipelineMetadata;\nuse Jiminny\\Services\\Crm\\Metadata\\ProfileMetadata;\n\nclass MetadataProcessor\n{\n private ?Configuration $crm = null;\n private TeamRepository $teamRepository;\n private UserRepository $userRepository;\n private CrmConfigurationRepository $crmConfigurationRepository;\n private FieldRepository $fieldRepository;\n\n public function __construct(\n TeamRepository $teamRepository,\n UserRepository $userRepository,\n CrmConfigurationRepository $crmConfigurationRepository,\n FieldRepository $fieldRepository\n ) {\n $this->teamRepository = $teamRepository;\n $this->userRepository = $userRepository;\n $this->crmConfigurationRepository = $crmConfigurationRepository;\n $this->fieldRepository = $fieldRepository;\n }\n\n public function setConfiguration(Configuration $crm): void\n {\n $this->crm = $crm;\n }\n\n /**\n * @throws RuntimeException\n */\n private function getConfiguration(): Configuration\n {\n if (! $this->crm instanceof Configuration) {\n throw new RuntimeException('Configuration not set');\n }\n\n return $this->crm;\n }\n\n public function syncOrganisation(OrganisationMetadata $organisationMetadata): void\n {\n $this->crmConfigurationRepository->updateConfiguration($this->getConfiguration(), $organisationMetadata);\n }\n\n public function syncPipeline(PipelineMetadata $pipelineMetadata): ?BusinessProcess\n {\n $businessProcess = $this->crmConfigurationRepository\n ->updateOrCreatePipeline($this->getConfiguration(), $pipelineMetadata);\n\n // A record type connects an opportunity to a business process (pipeline)\n $this->syncRecordType($pipelineMetadata, $businessProcess);\n\n $this->syncPipelineStages($businessProcess, $pipelineMetadata);\n\n return $businessProcess;\n }\n\n public function syncProfile(ProfileMetadata $profileMetadata): ?Profile\n {\n $user = $this->teamRepository->findActiveTeamMemberByEmail(\n $this->getConfiguration()->getTeam(),\n $profileMetadata->getEmail()\n );\n\n if (! $user instanceof User) {\n return null;\n }\n\n return $this->userRepository->updateOrCreateCrmProfile($user, $profileMetadata->getId());\n }\n\n public function syncField(FieldMetadata $fieldMetadata): Field\n {\n $field = $this->crmConfigurationRepository->updateOrCreateField($this->getConfiguration(), $fieldMetadata);\n\n if ($fieldMetadata->getType() === Field::TYPE_PICKLIST) {\n $this->fieldRepository->updatePicklistValues($field, $fieldMetadata->getOptions());\n }\n\n return $field;\n }\n\n private function syncPipelineStages(BusinessProcess $pipeline, PipelineMetadata $pipelineMetadata): void\n {\n $this->crmConfigurationRepository->updateOrCreatePipelineStages($pipeline, $pipelineMetadata->getStages());\n }\n\n private function syncRecordType(\n PipelineMetadata $pipelineMetadata,\n ?BusinessProcess $pipeline\n ): void {\n $this->crmConfigurationRepository->updateOrCreateRecordType(\n $this->getConfiguration(),\n $pipelineMetadata,\n $pipeline\n );\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"bounds":{"left":0.44547874,"top":0.09736632,"width":0.29022607,"height":0.8818835},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-6095796380002900138
|
-4382727891022868675
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Close\Processor;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Exceptions\RuntimeException;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmConfigurationRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\UserRepository;
use Jiminny\Services\Crm\Metadata\FieldMetadata;
use Jiminny\Services\Crm\Metadata\OrganisationMetadata;
use Jiminny\Services\Crm\Metadata\PipelineMetadata;
use Jiminny\Services\Crm\Metadata\ProfileMetadata;
class MetadataProcessor
{
private ?Configuration $crm = null;
private TeamRepository $teamRepository;
private UserRepository $userRepository;
private CrmConfigurationRepository $crmConfigurationRepository;
private FieldRepository $fieldRepository;
public function __construct(
TeamRepository $teamRepository,
UserRepository $userRepository,
CrmConfigurationRepository $crmConfigurationRepository,
FieldRepository $fieldRepository
) {
$this->teamRepository = $teamRepository;
$this->userRepository = $userRepository;
$this->crmConfigurationRepository = $crmConfigurationRepository;
$this->fieldRepository = $fieldRepository;
}
public function setConfiguration(Configuration $crm): void
{
$this->crm = $crm;
}
/**
* @throws RuntimeException
*/
private function getConfiguration(): Configuration
{
if (! $this->crm instanceof Configuration) {
throw new RuntimeException('Configuration not set');
}
return $this->crm;
}
public function syncOrganisation(OrganisationMetadata $organisationMetadata): void
{
$this->crmConfigurationRepository->updateConfiguration($this->getConfiguration(), $organisationMetadata);
}
public function syncPipeline(PipelineMetadata $pipelineMetadata): ?BusinessProcess
{
$businessProcess = $this->crmConfigurationRepository
->updateOrCreatePipeline($this->getConfiguration(), $pipelineMetadata);
// A record type connects an opportunity to a business process (pipeline)
$this->syncRecordType($pipelineMetadata, $businessProcess);
$this->syncPipelineStages($businessProcess, $pipelineMetadata);
return $businessProcess;
}
public function syncProfile(ProfileMetadata $profileMetadata): ?Profile
{
$user = $this->teamRepository->findActiveTeamMemberByEmail(
$this->getConfiguration()->getTeam(),
$profileMetadata->getEmail()
);
if (! $user instanceof User) {
return null;
}
return $this->userRepository->updateOrCreateCrmProfile($user, $profileMetadata->getId());
}
public function syncField(FieldMetadata $fieldMetadata): Field
{
$field = $this->crmConfigurationRepository->updateOrCreateField($this->getConfiguration(), $fieldMetadata);
if ($fieldMetadata->getType() === Field::TYPE_PICKLIST) {
$this->fieldRepository->updatePicklistValues($field, $fieldMetadata->getOptions());
}
return $field;
}
private function syncPipelineStages(BusinessProcess $pipeline, PipelineMetadata $pipelineMetadata): void
{
$this->crmConfigurationRepository->updateOrCreatePipelineStages($pipeline, $pipelineMetadata->getStages());
}
private function syncRecordType(
PipelineMetadata $pipelineMetadata,
?BusinessProcess $pipeline
): void {
$this->crmConfigurationRepository->updateOrCreateRecordType(
$this->getConfiguration(),
$pipelineMetadata,
$pipeline
);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65495
|
2306
|
29
|
2026-05-21T07:42:16.285823+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349336285_m1.jpg...
|
PhpStorm
|
faVsco.js – MetadataProcessor.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Close\Processor;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Exceptions\RuntimeException;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmConfigurationRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\UserRepository;
use Jiminny\Services\Crm\Metadata\FieldMetadata;
use Jiminny\Services\Crm\Metadata\OrganisationMetadata;
use Jiminny\Services\Crm\Metadata\PipelineMetadata;
use Jiminny\Services\Crm\Metadata\ProfileMetadata;
class MetadataProcessor
{
private ?Configuration $crm = null;
private TeamRepository $teamRepository;
private UserRepository $userRepository;
private CrmConfigurationRepository $crmConfigurationRepository;
private FieldRepository $fieldRepository;
public function __construct(
TeamRepository $teamRepository,
UserRepository $userRepository,
CrmConfigurationRepository $crmConfigurationRepository,
FieldRepository $fieldRepository
) {
$this->teamRepository = $teamRepository;
$this->userRepository = $userRepository;
$this->crmConfigurationRepository = $crmConfigurationRepository;
$this->fieldRepository = $fieldRepository;
}
public function setConfiguration(Configuration $crm): void
{
$this->crm = $crm;
}
/**
* @throws RuntimeException
*/
private function getConfiguration(): Configuration
{
if (! $this->crm instanceof Configuration) {
throw new RuntimeException('Configuration not set');
}
return $this->crm;
}
public function syncOrganisation(OrganisationMetadata $organisationMetadata): void
{
$this->crmConfigurationRepository->updateConfiguration($this->getConfiguration(), $organisationMetadata);
}
public function syncPipeline(PipelineMetadata $pipelineMetadata): ?BusinessProcess
{
$businessProcess = $this->crmConfigurationRepository
->updateOrCreatePipeline($this->getConfiguration(), $pipelineMetadata);
// A record type connects an opportunity to a business process (pipeline)
$this->syncRecordType($pipelineMetadata, $businessProcess);
$this->syncPipelineStages($businessProcess, $pipelineMetadata);
return $businessProcess;
}
public function syncProfile(ProfileMetadata $profileMetadata): ?Profile
{
$user = $this->teamRepository->findActiveTeamMemberByEmail(
$this->getConfiguration()->getTeam(),
$profileMetadata->getEmail()
);
if (! $user instanceof User) {
return null;
}
return $this->userRepository->updateOrCreateCrmProfile($user, $profileMetadata->getId());
}
public function syncField(FieldMetadata $fieldMetadata): Field
{
$field = $this->crmConfigurationRepository->updateOrCreateField($this->getConfiguration(), $fieldMetadata);
if ($fieldMetadata->getType() === Field::TYPE_PICKLIST) {
$this->fieldRepository->updatePicklistValues($field, $fieldMetadata->getOptions());
}
return $field;
}
private function syncPipelineStages(BusinessProcess $pipeline, PipelineMetadata $pipelineMetadata): void
{
$this->crmConfigurationRepository->updateOrCreatePipelineStages($pipeline, $pipelineMetadata->getStages());
}
private function syncRecordType(
PipelineMetadata $pipelineMetadata,
?BusinessProcess $pipeline
): void {
$this->crmConfigurationRepository->updateOrCreateRecordType(
$this->getConfiguration(),
$pipelineMetadata,
$pipeline
);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Close\\Processor;\n\nuse Jiminny\\Contracts\\Repositories\\TeamRepository;\nuse Jiminny\\Exceptions\\RuntimeException;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmConfigurationRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse Jiminny\\Services\\Crm\\Metadata\\FieldMetadata;\nuse Jiminny\\Services\\Crm\\Metadata\\OrganisationMetadata;\nuse Jiminny\\Services\\Crm\\Metadata\\PipelineMetadata;\nuse Jiminny\\Services\\Crm\\Metadata\\ProfileMetadata;\n\nclass MetadataProcessor\n{\n private ?Configuration $crm = null;\n private TeamRepository $teamRepository;\n private UserRepository $userRepository;\n private CrmConfigurationRepository $crmConfigurationRepository;\n private FieldRepository $fieldRepository;\n\n public function __construct(\n TeamRepository $teamRepository,\n UserRepository $userRepository,\n CrmConfigurationRepository $crmConfigurationRepository,\n FieldRepository $fieldRepository\n ) {\n $this->teamRepository = $teamRepository;\n $this->userRepository = $userRepository;\n $this->crmConfigurationRepository = $crmConfigurationRepository;\n $this->fieldRepository = $fieldRepository;\n }\n\n public function setConfiguration(Configuration $crm): void\n {\n $this->crm = $crm;\n }\n\n /**\n * @throws RuntimeException\n */\n private function getConfiguration(): Configuration\n {\n if (! $this->crm instanceof Configuration) {\n throw new RuntimeException('Configuration not set');\n }\n\n return $this->crm;\n }\n\n public function syncOrganisation(OrganisationMetadata $organisationMetadata): void\n {\n $this->crmConfigurationRepository->updateConfiguration($this->getConfiguration(), $organisationMetadata);\n }\n\n public function syncPipeline(PipelineMetadata $pipelineMetadata): ?BusinessProcess\n {\n $businessProcess = $this->crmConfigurationRepository\n ->updateOrCreatePipeline($this->getConfiguration(), $pipelineMetadata);\n\n // A record type connects an opportunity to a business process (pipeline)\n $this->syncRecordType($pipelineMetadata, $businessProcess);\n\n $this->syncPipelineStages($businessProcess, $pipelineMetadata);\n\n return $businessProcess;\n }\n\n public function syncProfile(ProfileMetadata $profileMetadata): ?Profile\n {\n $user = $this->teamRepository->findActiveTeamMemberByEmail(\n $this->getConfiguration()->getTeam(),\n $profileMetadata->getEmail()\n );\n\n if (! $user instanceof User) {\n return null;\n }\n\n return $this->userRepository->updateOrCreateCrmProfile($user, $profileMetadata->getId());\n }\n\n public function syncField(FieldMetadata $fieldMetadata): Field\n {\n $field = $this->crmConfigurationRepository->updateOrCreateField($this->getConfiguration(), $fieldMetadata);\n\n if ($fieldMetadata->getType() === Field::TYPE_PICKLIST) {\n $this->fieldRepository->updatePicklistValues($field, $fieldMetadata->getOptions());\n }\n\n return $field;\n }\n\n private function syncPipelineStages(BusinessProcess $pipeline, PipelineMetadata $pipelineMetadata): void\n {\n $this->crmConfigurationRepository->updateOrCreatePipelineStages($pipeline, $pipelineMetadata->getStages());\n }\n\n private function syncRecordType(\n PipelineMetadata $pipelineMetadata,\n ?BusinessProcess $pipeline\n ): void {\n $this->crmConfigurationRepository->updateOrCreateRecordType(\n $this->getConfiguration(),\n $pipelineMetadata,\n $pipeline\n );\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Close\\Processor;\n\nuse Jiminny\\Contracts\\Repositories\\TeamRepository;\nuse Jiminny\\Exceptions\\RuntimeException;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmConfigurationRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse Jiminny\\Services\\Crm\\Metadata\\FieldMetadata;\nuse Jiminny\\Services\\Crm\\Metadata\\OrganisationMetadata;\nuse Jiminny\\Services\\Crm\\Metadata\\PipelineMetadata;\nuse Jiminny\\Services\\Crm\\Metadata\\ProfileMetadata;\n\nclass MetadataProcessor\n{\n private ?Configuration $crm = null;\n private TeamRepository $teamRepository;\n private UserRepository $userRepository;\n private CrmConfigurationRepository $crmConfigurationRepository;\n private FieldRepository $fieldRepository;\n\n public function __construct(\n TeamRepository $teamRepository,\n UserRepository $userRepository,\n CrmConfigurationRepository $crmConfigurationRepository,\n FieldRepository $fieldRepository\n ) {\n $this->teamRepository = $teamRepository;\n $this->userRepository = $userRepository;\n $this->crmConfigurationRepository = $crmConfigurationRepository;\n $this->fieldRepository = $fieldRepository;\n }\n\n public function setConfiguration(Configuration $crm): void\n {\n $this->crm = $crm;\n }\n\n /**\n * @throws RuntimeException\n */\n private function getConfiguration(): Configuration\n {\n if (! $this->crm instanceof Configuration) {\n throw new RuntimeException('Configuration not set');\n }\n\n return $this->crm;\n }\n\n public function syncOrganisation(OrganisationMetadata $organisationMetadata): void\n {\n $this->crmConfigurationRepository->updateConfiguration($this->getConfiguration(), $organisationMetadata);\n }\n\n public function syncPipeline(PipelineMetadata $pipelineMetadata): ?BusinessProcess\n {\n $businessProcess = $this->crmConfigurationRepository\n ->updateOrCreatePipeline($this->getConfiguration(), $pipelineMetadata);\n\n // A record type connects an opportunity to a business process (pipeline)\n $this->syncRecordType($pipelineMetadata, $businessProcess);\n\n $this->syncPipelineStages($businessProcess, $pipelineMetadata);\n\n return $businessProcess;\n }\n\n public function syncProfile(ProfileMetadata $profileMetadata): ?Profile\n {\n $user = $this->teamRepository->findActiveTeamMemberByEmail(\n $this->getConfiguration()->getTeam(),\n $profileMetadata->getEmail()\n );\n\n if (! $user instanceof User) {\n return null;\n }\n\n return $this->userRepository->updateOrCreateCrmProfile($user, $profileMetadata->getId());\n }\n\n public function syncField(FieldMetadata $fieldMetadata): Field\n {\n $field = $this->crmConfigurationRepository->updateOrCreateField($this->getConfiguration(), $fieldMetadata);\n\n if ($fieldMetadata->getType() === Field::TYPE_PICKLIST) {\n $this->fieldRepository->updatePicklistValues($field, $fieldMetadata->getOptions());\n }\n\n return $field;\n }\n\n private function syncPipelineStages(BusinessProcess $pipeline, PipelineMetadata $pipelineMetadata): void\n {\n $this->crmConfigurationRepository->updateOrCreatePipelineStages($pipeline, $pipelineMetadata->getStages());\n }\n\n private function syncRecordType(\n PipelineMetadata $pipelineMetadata,\n ?BusinessProcess $pipeline\n ): void {\n $this->crmConfigurationRepository->updateOrCreateRecordType(\n $this->getConfiguration(),\n $pipelineMetadata,\n $pipeline\n );\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"}]...
|
8357275665674168715
|
-4382727890989249731
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Close\Processor;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Exceptions\RuntimeException;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmConfigurationRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\UserRepository;
use Jiminny\Services\Crm\Metadata\FieldMetadata;
use Jiminny\Services\Crm\Metadata\OrganisationMetadata;
use Jiminny\Services\Crm\Metadata\PipelineMetadata;
use Jiminny\Services\Crm\Metadata\ProfileMetadata;
class MetadataProcessor
{
private ?Configuration $crm = null;
private TeamRepository $teamRepository;
private UserRepository $userRepository;
private CrmConfigurationRepository $crmConfigurationRepository;
private FieldRepository $fieldRepository;
public function __construct(
TeamRepository $teamRepository,
UserRepository $userRepository,
CrmConfigurationRepository $crmConfigurationRepository,
FieldRepository $fieldRepository
) {
$this->teamRepository = $teamRepository;
$this->userRepository = $userRepository;
$this->crmConfigurationRepository = $crmConfigurationRepository;
$this->fieldRepository = $fieldRepository;
}
public function setConfiguration(Configuration $crm): void
{
$this->crm = $crm;
}
/**
* @throws RuntimeException
*/
private function getConfiguration(): Configuration
{
if (! $this->crm instanceof Configuration) {
throw new RuntimeException('Configuration not set');
}
return $this->crm;
}
public function syncOrganisation(OrganisationMetadata $organisationMetadata): void
{
$this->crmConfigurationRepository->updateConfiguration($this->getConfiguration(), $organisationMetadata);
}
public function syncPipeline(PipelineMetadata $pipelineMetadata): ?BusinessProcess
{
$businessProcess = $this->crmConfigurationRepository
->updateOrCreatePipeline($this->getConfiguration(), $pipelineMetadata);
// A record type connects an opportunity to a business process (pipeline)
$this->syncRecordType($pipelineMetadata, $businessProcess);
$this->syncPipelineStages($businessProcess, $pipelineMetadata);
return $businessProcess;
}
public function syncProfile(ProfileMetadata $profileMetadata): ?Profile
{
$user = $this->teamRepository->findActiveTeamMemberByEmail(
$this->getConfiguration()->getTeam(),
$profileMetadata->getEmail()
);
if (! $user instanceof User) {
return null;
}
return $this->userRepository->updateOrCreateCrmProfile($user, $profileMetadata->getId());
}
public function syncField(FieldMetadata $fieldMetadata): Field
{
$field = $this->crmConfigurationRepository->updateOrCreateField($this->getConfiguration(), $fieldMetadata);
if ($fieldMetadata->getType() === Field::TYPE_PICKLIST) {
$this->fieldRepository->updatePicklistValues($field, $fieldMetadata->getOptions());
}
return $field;
}
private function syncPipelineStages(BusinessProcess $pipeline, PipelineMetadata $pipelineMetadata): void
{
$this->crmConfigurationRepository->updateOrCreatePipelineStages($pipeline, $pipelineMetadata->getStages());
}
private function syncRecordType(
PipelineMetadata $pipelineMetadata,
?BusinessProcess $pipeline
): void {
$this->crmConfigurationRepository->updateOrCreateRecordType(
$this->getConfiguration(),
$pipelineMetadata,
$pipeline
);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65494
|
2307
|
22
|
2026-05-21T07:42:05.941962+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349325941_m2.jpg...
|
PhpStorm
|
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
MetadataProcessor.php, class
MetadataProcessor.php MetadataProcessor.php, class
MetadataProcessor.php, class
96
96
$this->fieldRepository->updatePicklistValues($field, $fieldMetadata->getOptions());
$this->fieldRepository->updatePicklistValues($field, $fieldMetadata->getOptions());
MetadataProcessorTest.php, class
MetadataProcessorTest.php, class
182
182
->method('updatePicklistValues')
->method('updatePicklistValues')
Merge Usages from the Same Line
Show Read Access
Show Write Access
Show Results In Generated Code
Show Import Statements
Show $this/self references
Show Options
Preview Source
Project Files...
|
[{"role":"AXCell","text":& [{"role":"AXCell","text":"MetadataProcessor.php, class","depth":4,"on_screen":false,"role_description":"cell"},{"role":"AXStaticText","text":"MetadataProcessor.php, class","depth":5,"on_screen":false,"role_description":"text"},{"role":"AXCell","text":"96","depth":4,"on_screen":false,"role_description":"cell"},{"role":"AXStaticText","text":"96","depth":5,"on_screen":false,"role_description":"text"},{"role":"AXCell","text":"$this->fieldRepository->updatePicklistValues($field, $fieldMetadata->getOptions());","depth":4,"on_screen":false,"role_description":"cell"},{"role":"AXStaticText","text":"$this->fieldRepository->updatePicklistValues($field, $fieldMetadata->getOptions());","depth":5,"on_screen":false,"role_description":"text"},{"role":"AXCell","text":"MetadataProcessorTest.php, class","depth":4,"on_screen":false,"role_description":"cell"},{"role":"AXStaticText","text":"MetadataProcessorTest.php, class","depth":5,"on_screen":false,"role_description":"text"},{"role":"AXCell","text":"182","depth":4,"on_screen":false,"role_description":"cell"},{"role":"AXStaticText","text":"182","depth":5,"on_screen":false,"role_description":"text"},{"role":"AXCell","text":"->method('updatePicklistValues')","depth":4,"on_screen":false,"role_description":"cell"},{"role":"AXStaticText","text":"->method('updatePicklistValues')","depth":5,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Merge Usages from the Same Line","depth":2,"bounds":{"left":0.19015957,"top":0.41260973,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Read Access","depth":2,"bounds":{"left":0.19880319,"top":0.41260973,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Write Access","depth":2,"bounds":{"left":0.20744681,"top":0.41260973,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Results In Generated Code","depth":2,"bounds":{"left":0.21609043,"top":0.41260973,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Import Statements","depth":2,"bounds":{"left":0.22473404,"top":0.41260973,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show $this/self references","depth":2,"bounds":{"left":0.23337767,"top":0.41260973,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Options","depth":2,"bounds":{"left":0.24202128,"top":0.41260973,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Preview Source","depth":2,"bounds":{"left":0.25299203,"top":0.41260973,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project Files","depth":2,"bounds":{"left":0.26163563,"top":0.41260973,"width":0.03557181,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_expanded":false}]...
|
3422689603319021149
|
-7791483532066909704
|
click
|
accessibility
|
NULL
|
MetadataProcessor.php, class
MetadataProcessor.php MetadataProcessor.php, class
MetadataProcessor.php, class
96
96
$this->fieldRepository->updatePicklistValues($field, $fieldMetadata->getOptions());
$this->fieldRepository->updatePicklistValues($field, $fieldMetadata->getOptions());
MetadataProcessorTest.php, class
MetadataProcessorTest.php, class
182
182
->method('updatePicklistValues')
->method('updatePicklistValues')
Merge Usages from the Same Line
Show Read Access
Show Write Access
Show Results In Generated Code
Show Import Statements
Show $this/self references
Show Options
Preview Source
Project Files...
|
65492
|
NULL
|
NULL
|
NULL
|
|
65493
|
2306
|
28
|
2026-05-21T07:42:05.935714+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349325935_m1.jpg...
|
PhpStorm
|
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
MetadataProcessor.php, class
MetadataProcessor.php MetadataProcessor.php, class
MetadataProcessor.php, class
96
96
$this->fieldRepository->updatePicklistValues($field, $fieldMetadata->getOptions());
$this->fieldRepository->updatePicklistValues($field, $fieldMetadata->getOptions());
MetadataProcessorTest.php, class
MetadataProcessorTest.php, class
182
182
->method('updatePicklistValues')
->method('updatePicklistValues')
Merge Usages from the Same Line
Show Read Access
Show Write Access
Show Results In Generated Code
Show Import Statements
Show $this/self references
Show Options
Preview Source
Project Files
Usages
Settings…...
|
[{"role":"AXCell","text":& [{"role":"AXCell","text":"MetadataProcessor.php, class","depth":4,"on_screen":false,"role_description":"cell"},{"role":"AXStaticText","text":"MetadataProcessor.php, class","depth":5,"on_screen":false,"role_description":"text"},{"role":"AXCell","text":"96","depth":4,"on_screen":false,"role_description":"cell"},{"role":"AXStaticText","text":"96","depth":5,"on_screen":false,"role_description":"text"},{"role":"AXCell","text":"$this->fieldRepository->updatePicklistValues($field, $fieldMetadata->getOptions());","depth":4,"on_screen":false,"role_description":"cell"},{"role":"AXStaticText","text":"$this->fieldRepository->updatePicklistValues($field, $fieldMetadata->getOptions());","depth":5,"on_screen":false,"role_description":"text"},{"role":"AXCell","text":"MetadataProcessorTest.php, class","depth":4,"on_screen":false,"role_description":"cell"},{"role":"AXStaticText","text":"MetadataProcessorTest.php, class","depth":5,"on_screen":false,"role_description":"text"},{"role":"AXCell","text":"182","depth":4,"on_screen":false,"role_description":"cell"},{"role":"AXStaticText","text":"182","depth":5,"on_screen":false,"role_description":"text"},{"role":"AXCell","text":"->method('updatePicklistValues')","depth":4,"on_screen":false,"role_description":"cell"},{"role":"AXStaticText","text":"->method('updatePicklistValues')","depth":5,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Merge Usages from the Same Line","depth":2,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Read Access","depth":2,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Write Access","depth":2,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Results In Generated Code","depth":2,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Import Statements","depth":2,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show $this/self references","depth":2,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Options","depth":2,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Preview Source","depth":2,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project Files","depth":2,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Usages","depth":1,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Settings…","depth":2,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-3573222964604457793
|
-2891567138022587920
|
click
|
accessibility
|
NULL
|
MetadataProcessor.php, class
MetadataProcessor.php MetadataProcessor.php, class
MetadataProcessor.php, class
96
96
$this->fieldRepository->updatePicklistValues($field, $fieldMetadata->getOptions());
$this->fieldRepository->updatePicklistValues($field, $fieldMetadata->getOptions());
MetadataProcessorTest.php, class
MetadataProcessorTest.php, class
182
182
->method('updatePicklistValues')
->method('updatePicklistValues')
Merge Usages from the Same Line
Show Read Access
Show Write Access
Show Results In Generated Code
Show Import Statements
Show $this/self references
Show Options
Preview Source
Project Files
Usages
Settings…...
|
65491
|
NULL
|
NULL
|
NULL
|
|
65492
|
2307
|
21
|
2026-05-21T07:42:01.473570+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349321473_m2.jpg...
|
PhpStorm
|
faVsco.js – FieldRepository.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use Illuminate\Support\Collection;
use Illuminate\Support\LazyCollection;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Team;
use Jiminny\Services\Crm\Metadata\OptionMetadata;
class FieldRepository
{
/**
* @return Collection<Field>
*/
public function getAllFieldsForObjectType(Team $team, string $objectType): Collection
{
return $team->getCrmConfiguration()
->fields()
->where('object_type', '=', $objectType)
->get()
;
}
/**
* @param Team $team
* @param string[] $objectTypes
*
* @return Collection<Field>
*/
public function findAllSelectableByObjectTypes(Team $team, array $objectTypes): Collection
{
return $team->getCrmConfiguration()
->fields()
->whereIn('object_type', $objectTypes)
->where('is_selectable', true)
->orderBy('label')
->get()
;
}
public function idOrUuid(int|string $id): ?Field
{
/** @var ?Field */
return Field::idOrUuid($id);
}
/**
* @param OptionMetadata[] $options
*/
public function updatePicklistValues(Field $field, array $options): void
{
$field->values()->delete();
foreach ($options as $option) {
$field->values()->updateOrCreate([
'value' => $option->getId(),
'label' => $option->getLabel(),
], [
'sequence' => $option->getSequence(),
]);
}
}
public function updateOrCreateFieldValue(Field $field, array $data): FieldValue
{
/** @var FieldValue */
return $field->values()->updateOrCreate([
'value' => $data['value'],
], $data);
}
public function updateOrCreateOpportunityFieldData(
Field $field,
int $layoutEntityId,
int $opportunityId,
string $value,
): void {
$field->data()->updateOrCreate([
'crm_layout_entity_id' => $layoutEntityId,
'crm_field_id' => $field->getId(),
'object_type' => Field::OBJECT_OPPORTUNITY,
'object_id' => $opportunityId,
], ['value' => $value]);
}
public function findOneByCrmProviderId(Configuration $configuration, string $fieldId): ?Field
{
/** @var Field */
return $configuration->fields()->where('crm_provider_id', $fieldId)->first();
}
/**
* @param array<string,scalar> $data
*/
public function updateField(Field $field, array $data): void
{
$field->update($data);
}
public function upsertField(Configuration $configuration, array $data): Field
{
/** @var Field */
return $configuration->fields()->updateOrCreate(
[
'crm_provider_id' => $data['crm_provider_id'],
'object_type' => $data['object_type'],
],
$data,
);
}
public function findFieldByCrmIdAndObjectType(
Configuration $configuration,
string $fieldId,
string $objectType,
): ?Field {
/** @var Field */
return $configuration->fields()
->where('crm_provider_id', $fieldId)
->where('object_type', $objectType)
->first();
}
public function findAllFilterable(Team $team): LazyCollection
{
return $team
->getCrmConfiguration()
->fields()
->where('is_filterable', true)
->cursor();
}
public function findOneByCrmProviderIdAndObjectType(
Configuration $configuration,
string $fieldId,
string $objectType,
): ?Field {
/** @var ?Field */
return $configuration
->fields()
->where('crm_provider_id', $fieldId)
->where('object_type', $objectType)
->first();
}
public function findOneConfigurationFieldByProperties(Configuration $configuration, array $properties): ?Field
{
return $configuration->fields()
->where($properties)
->first();
}
public function getPicklistValues(Field $field, ?array $filterValues = []): Collection
{
$queryBuilder = $field->values()->orderBy('sequence');
if (! empty($filterValues)) {
$queryBuilder->whereIn('value', $filterValues);
}
return $queryBuilder->get();
}
public function updatePicklistValue(Field $field, array $picklistValueData): FieldValue
{
/** @var FieldValue */
return $this->updateOrCreateFieldValue($field, $picklistValueData);
}
public function deleteObsoleteField(Configuration $configuration, string $objectType, string $crmProviderId): void
{
$configuration->fields()
->where('object_type', $objectType)
->where('crm_provider_id', $crmProviderId)
->delete();
}
/**
* @param Configuration $configuration
* @param string $objectType
* @param string[] $crmProviderIds
*
* @return Collection<Field>
*/
public function identifyTeamCrmFields(
Configuration $configuration,
string $objectType,
array $crmProviderIds,
): Collection {
return $configuration->fields()
->where('object_type', $objectType)
->whereIn('crm_provider_id', $crmProviderIds)
->get();
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\LazyCollection;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Crm\\Metadata\\OptionMetadata;\n\nclass FieldRepository\n{\n /**\n * @return Collection<Field>\n */\n public function getAllFieldsForObjectType(Team $team, string $objectType): Collection\n {\n return $team->getCrmConfiguration()\n ->fields()\n ->where('object_type', '=', $objectType)\n ->get()\n ;\n }\n\n /**\n * @param Team $team\n * @param string[] $objectTypes\n *\n * @return Collection<Field>\n */\n public function findAllSelectableByObjectTypes(Team $team, array $objectTypes): Collection\n {\n return $team->getCrmConfiguration()\n ->fields()\n ->whereIn('object_type', $objectTypes)\n ->where('is_selectable', true)\n ->orderBy('label')\n ->get()\n ;\n }\n\n public function idOrUuid(int|string $id): ?Field\n {\n /** @var ?Field */\n return Field::idOrUuid($id);\n }\n\n /**\n * @param OptionMetadata[] $options\n */\n public function updatePicklistValues(Field $field, array $options): void\n {\n $field->values()->delete();\n\n foreach ($options as $option) {\n $field->values()->updateOrCreate([\n 'value' => $option->getId(),\n 'label' => $option->getLabel(),\n ], [\n 'sequence' => $option->getSequence(),\n ]);\n }\n }\n\n public function updateOrCreateFieldValue(Field $field, array $data): FieldValue\n {\n /** @var FieldValue */\n return $field->values()->updateOrCreate([\n 'value' => $data['value'],\n ], $data);\n }\n\n public function updateOrCreateOpportunityFieldData(\n Field $field,\n int $layoutEntityId,\n int $opportunityId,\n string $value,\n ): void {\n $field->data()->updateOrCreate([\n 'crm_layout_entity_id' => $layoutEntityId,\n 'crm_field_id' => $field->getId(),\n 'object_type' => Field::OBJECT_OPPORTUNITY,\n 'object_id' => $opportunityId,\n ], ['value' => $value]);\n }\n\n public function findOneByCrmProviderId(Configuration $configuration, string $fieldId): ?Field\n {\n /** @var Field */\n return $configuration->fields()->where('crm_provider_id', $fieldId)->first();\n }\n\n /**\n * @param array<string,scalar> $data\n */\n public function updateField(Field $field, array $data): void\n {\n $field->update($data);\n }\n\n public function upsertField(Configuration $configuration, array $data): Field\n {\n /** @var Field */\n return $configuration->fields()->updateOrCreate(\n [\n 'crm_provider_id' => $data['crm_provider_id'],\n 'object_type' => $data['object_type'],\n ],\n $data,\n );\n }\n\n public function findFieldByCrmIdAndObjectType(\n Configuration $configuration,\n string $fieldId,\n string $objectType,\n ): ?Field {\n /** @var Field */\n return $configuration->fields()\n ->where('crm_provider_id', $fieldId)\n ->where('object_type', $objectType)\n ->first();\n }\n\n public function findAllFilterable(Team $team): LazyCollection\n {\n return $team\n ->getCrmConfiguration()\n ->fields()\n ->where('is_filterable', true)\n ->cursor();\n }\n\n public function findOneByCrmProviderIdAndObjectType(\n Configuration $configuration,\n string $fieldId,\n string $objectType,\n ): ?Field {\n /** @var ?Field */\n return $configuration\n ->fields()\n ->where('crm_provider_id', $fieldId)\n ->where('object_type', $objectType)\n ->first();\n }\n\n public function findOneConfigurationFieldByProperties(Configuration $configuration, array $properties): ?Field\n {\n return $configuration->fields()\n ->where($properties)\n ->first();\n }\n\n public function getPicklistValues(Field $field, ?array $filterValues = []): Collection\n {\n $queryBuilder = $field->values()->orderBy('sequence');\n\n if (! empty($filterValues)) {\n $queryBuilder->whereIn('value', $filterValues);\n }\n\n return $queryBuilder->get();\n }\n\n public function updatePicklistValue(Field $field, array $picklistValueData): FieldValue\n {\n /** @var FieldValue */\n return $this->updateOrCreateFieldValue($field, $picklistValueData);\n }\n\n public function deleteObsoleteField(Configuration $configuration, string $objectType, string $crmProviderId): void\n {\n $configuration->fields()\n ->where('object_type', $objectType)\n ->where('crm_provider_id', $crmProviderId)\n ->delete();\n }\n\n /**\n * @param Configuration $configuration\n * @param string $objectType\n * @param string[] $crmProviderIds\n *\n * @return Collection<Field>\n */\n public function identifyTeamCrmFields(\n Configuration $configuration,\n string $objectType,\n array $crmProviderIds,\n ): Collection {\n return $configuration->fields()\n ->where('object_type', $objectType)\n ->whereIn('crm_provider_id', $crmProviderIds)\n ->get();\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\LazyCollection;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Crm\\Metadata\\OptionMetadata;\n\nclass FieldRepository\n{\n /**\n * @return Collection<Field>\n */\n public function getAllFieldsForObjectType(Team $team, string $objectType): Collection\n {\n return $team->getCrmConfiguration()\n ->fields()\n ->where('object_type', '=', $objectType)\n ->get()\n ;\n }\n\n /**\n * @param Team $team\n * @param string[] $objectTypes\n *\n * @return Collection<Field>\n */\n public function findAllSelectableByObjectTypes(Team $team, array $objectTypes): Collection\n {\n return $team->getCrmConfiguration()\n ->fields()\n ->whereIn('object_type', $objectTypes)\n ->where('is_selectable', true)\n ->orderBy('label')\n ->get()\n ;\n }\n\n public function idOrUuid(int|string $id): ?Field\n {\n /** @var ?Field */\n return Field::idOrUuid($id);\n }\n\n /**\n * @param OptionMetadata[] $options\n */\n public function updatePicklistValues(Field $field, array $options): void\n {\n $field->values()->delete();\n\n foreach ($options as $option) {\n $field->values()->updateOrCreate([\n 'value' => $option->getId(),\n 'label' => $option->getLabel(),\n ], [\n 'sequence' => $option->getSequence(),\n ]);\n }\n }\n\n public function updateOrCreateFieldValue(Field $field, array $data): FieldValue\n {\n /** @var FieldValue */\n return $field->values()->updateOrCreate([\n 'value' => $data['value'],\n ], $data);\n }\n\n public function updateOrCreateOpportunityFieldData(\n Field $field,\n int $layoutEntityId,\n int $opportunityId,\n string $value,\n ): void {\n $field->data()->updateOrCreate([\n 'crm_layout_entity_id' => $layoutEntityId,\n 'crm_field_id' => $field->getId(),\n 'object_type' => Field::OBJECT_OPPORTUNITY,\n 'object_id' => $opportunityId,\n ], ['value' => $value]);\n }\n\n public function findOneByCrmProviderId(Configuration $configuration, string $fieldId): ?Field\n {\n /** @var Field */\n return $configuration->fields()->where('crm_provider_id', $fieldId)->first();\n }\n\n /**\n * @param array<string,scalar> $data\n */\n public function updateField(Field $field, array $data): void\n {\n $field->update($data);\n }\n\n public function upsertField(Configuration $configuration, array $data): Field\n {\n /** @var Field */\n return $configuration->fields()->updateOrCreate(\n [\n 'crm_provider_id' => $data['crm_provider_id'],\n 'object_type' => $data['object_type'],\n ],\n $data,\n );\n }\n\n public function findFieldByCrmIdAndObjectType(\n Configuration $configuration,\n string $fieldId,\n string $objectType,\n ): ?Field {\n /** @var Field */\n return $configuration->fields()\n ->where('crm_provider_id', $fieldId)\n ->where('object_type', $objectType)\n ->first();\n }\n\n public function findAllFilterable(Team $team): LazyCollection\n {\n return $team\n ->getCrmConfiguration()\n ->fields()\n ->where('is_filterable', true)\n ->cursor();\n }\n\n public function findOneByCrmProviderIdAndObjectType(\n Configuration $configuration,\n string $fieldId,\n string $objectType,\n ): ?Field {\n /** @var ?Field */\n return $configuration\n ->fields()\n ->where('crm_provider_id', $fieldId)\n ->where('object_type', $objectType)\n ->first();\n }\n\n public function findOneConfigurationFieldByProperties(Configuration $configuration, array $properties): ?Field\n {\n return $configuration->fields()\n ->where($properties)\n ->first();\n }\n\n public function getPicklistValues(Field $field, ?array $filterValues = []): Collection\n {\n $queryBuilder = $field->values()->orderBy('sequence');\n\n if (! empty($filterValues)) {\n $queryBuilder->whereIn('value', $filterValues);\n }\n\n return $queryBuilder->get();\n }\n\n public function updatePicklistValue(Field $field, array $picklistValueData): FieldValue\n {\n /** @var FieldValue */\n return $this->updateOrCreateFieldValue($field, $picklistValueData);\n }\n\n public function deleteObsoleteField(Configuration $configuration, string $objectType, string $crmProviderId): void\n {\n $configuration->fields()\n ->where('object_type', $objectType)\n ->where('crm_provider_id', $crmProviderId)\n ->delete();\n }\n\n /**\n * @param Configuration $configuration\n * @param string $objectType\n * @param string[] $crmProviderIds\n *\n * @return Collection<Field>\n */\n public function identifyTeamCrmFields(\n Configuration $configuration,\n string $objectType,\n array $crmProviderIds,\n ): Collection {\n return $configuration->fields()\n ->where('object_type', $objectType)\n ->whereIn('crm_provider_id', $crmProviderIds)\n ->get();\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"bounds":{"left":0.44547874,"top":0.09736632,"width":0.29022607,"height":0.8818835},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
3782946305343260838
|
-4131508276899304075
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use Illuminate\Support\Collection;
use Illuminate\Support\LazyCollection;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Team;
use Jiminny\Services\Crm\Metadata\OptionMetadata;
class FieldRepository
{
/**
* @return Collection<Field>
*/
public function getAllFieldsForObjectType(Team $team, string $objectType): Collection
{
return $team->getCrmConfiguration()
->fields()
->where('object_type', '=', $objectType)
->get()
;
}
/**
* @param Team $team
* @param string[] $objectTypes
*
* @return Collection<Field>
*/
public function findAllSelectableByObjectTypes(Team $team, array $objectTypes): Collection
{
return $team->getCrmConfiguration()
->fields()
->whereIn('object_type', $objectTypes)
->where('is_selectable', true)
->orderBy('label')
->get()
;
}
public function idOrUuid(int|string $id): ?Field
{
/** @var ?Field */
return Field::idOrUuid($id);
}
/**
* @param OptionMetadata[] $options
*/
public function updatePicklistValues(Field $field, array $options): void
{
$field->values()->delete();
foreach ($options as $option) {
$field->values()->updateOrCreate([
'value' => $option->getId(),
'label' => $option->getLabel(),
], [
'sequence' => $option->getSequence(),
]);
}
}
public function updateOrCreateFieldValue(Field $field, array $data): FieldValue
{
/** @var FieldValue */
return $field->values()->updateOrCreate([
'value' => $data['value'],
], $data);
}
public function updateOrCreateOpportunityFieldData(
Field $field,
int $layoutEntityId,
int $opportunityId,
string $value,
): void {
$field->data()->updateOrCreate([
'crm_layout_entity_id' => $layoutEntityId,
'crm_field_id' => $field->getId(),
'object_type' => Field::OBJECT_OPPORTUNITY,
'object_id' => $opportunityId,
], ['value' => $value]);
}
public function findOneByCrmProviderId(Configuration $configuration, string $fieldId): ?Field
{
/** @var Field */
return $configuration->fields()->where('crm_provider_id', $fieldId)->first();
}
/**
* @param array<string,scalar> $data
*/
public function updateField(Field $field, array $data): void
{
$field->update($data);
}
public function upsertField(Configuration $configuration, array $data): Field
{
/** @var Field */
return $configuration->fields()->updateOrCreate(
[
'crm_provider_id' => $data['crm_provider_id'],
'object_type' => $data['object_type'],
],
$data,
);
}
public function findFieldByCrmIdAndObjectType(
Configuration $configuration,
string $fieldId,
string $objectType,
): ?Field {
/** @var Field */
return $configuration->fields()
->where('crm_provider_id', $fieldId)
->where('object_type', $objectType)
->first();
}
public function findAllFilterable(Team $team): LazyCollection
{
return $team
->getCrmConfiguration()
->fields()
->where('is_filterable', true)
->cursor();
}
public function findOneByCrmProviderIdAndObjectType(
Configuration $configuration,
string $fieldId,
string $objectType,
): ?Field {
/** @var ?Field */
return $configuration
->fields()
->where('crm_provider_id', $fieldId)
->where('object_type', $objectType)
->first();
}
public function findOneConfigurationFieldByProperties(Configuration $configuration, array $properties): ?Field
{
return $configuration->fields()
->where($properties)
->first();
}
public function getPicklistValues(Field $field, ?array $filterValues = []): Collection
{
$queryBuilder = $field->values()->orderBy('sequence');
if (! empty($filterValues)) {
$queryBuilder->whereIn('value', $filterValues);
}
return $queryBuilder->get();
}
public function updatePicklistValue(Field $field, array $picklistValueData): FieldValue
{
/** @var FieldValue */
return $this->updateOrCreateFieldValue($field, $picklistValueData);
}
public function deleteObsoleteField(Configuration $configuration, string $objectType, string $crmProviderId): void
{
$configuration->fields()
->where('object_type', $objectType)
->where('crm_provider_id', $crmProviderId)
->delete();
}
/**
* @param Configuration $configuration
* @param string $objectType
* @param string[] $crmProviderIds
*
* @return Collection<Field>
*/
public function identifyTeamCrmFields(
Configuration $configuration,
string $objectType,
array $crmProviderIds,
): Collection {
return $configuration->fields()
->where('object_type', $objectType)
->whereIn('crm_provider_id', $crmProviderIds)
->get();
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65491
|
2306
|
27
|
2026-05-21T07:42:01.443310+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349321443_m1.jpg...
|
PhpStorm
|
faVsco.js – FieldRepository.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use Illuminate\Support\Collection;
use Illuminate\Support\LazyCollection;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Team;
use Jiminny\Services\Crm\Metadata\OptionMetadata;
class FieldRepository
{
/**
* @return Collection<Field>
*/
public function getAllFieldsForObjectType(Team $team, string $objectType): Collection
{
return $team->getCrmConfiguration()
->fields()
->where('object_type', '=', $objectType)
->get()
;
}
/**
* @param Team $team
* @param string[] $objectTypes
*
* @return Collection<Field>
*/
public function findAllSelectableByObjectTypes(Team $team, array $objectTypes): Collection
{
return $team->getCrmConfiguration()
->fields()
->whereIn('object_type', $objectTypes)
->where('is_selectable', true)
->orderBy('label')
->get()
;
}
public function idOrUuid(int|string $id): ?Field
{
/** @var ?Field */
return Field::idOrUuid($id);
}
/**
* @param OptionMetadata[] $options
*/
public function updatePicklistValues(Field $field, array $options): void
{
$field->values()->delete();
foreach ($options as $option) {
$field->values()->updateOrCreate([
'value' => $option->getId(),
'label' => $option->getLabel(),
], [
'sequence' => $option->getSequence(),
]);
}
}
public function updateOrCreateFieldValue(Field $field, array $data): FieldValue
{
/** @var FieldValue */
return $field->values()->updateOrCreate([
'value' => $data['value'],
], $data);
}
public function updateOrCreateOpportunityFieldData(
Field $field,
int $layoutEntityId,
int $opportunityId,
string $value,
): void {
$field->data()->updateOrCreate([
'crm_layout_entity_id' => $layoutEntityId,
'crm_field_id' => $field->getId(),
'object_type' => Field::OBJECT_OPPORTUNITY,
'object_id' => $opportunityId,
], ['value' => $value]);
}
public function findOneByCrmProviderId(Configuration $configuration, string $fieldId): ?Field
{
/** @var Field */
return $configuration->fields()->where('crm_provider_id', $fieldId)->first();
}
/**
* @param array<string,scalar> $data
*/
public function updateField(Field $field, array $data): void
{
$field->update($data);
}
public function upsertField(Configuration $configuration, array $data): Field
{
/** @var Field */
return $configuration->fields()->updateOrCreate(
[
'crm_provider_id' => $data['crm_provider_id'],
'object_type' => $data['object_type'],
],
$data,
);
}
public function findFieldByCrmIdAndObjectType(
Configuration $configuration,
string $fieldId,
string $objectType,
): ?Field {
/** @var Field */
return $configuration->fields()
->where('crm_provider_id', $fieldId)
->where('object_type', $objectType)
->first();
}
public function findAllFilterable(Team $team): LazyCollection
{
return $team
->getCrmConfiguration()
->fields()
->where('is_filterable', true)
->cursor();
}
public function findOneByCrmProviderIdAndObjectType(
Configuration $configuration,
string $fieldId,
string $objectType,
): ?Field {
/** @var ?Field */
return $configuration
->fields()
->where('crm_provider_id', $fieldId)
->where('object_type', $objectType)
->first();
}
public function findOneConfigurationFieldByProperties(Configuration $configuration, array $properties): ?Field
{
return $configuration->fields()
->where($properties)
->first();
}
public function getPicklistValues(Field $field, ?array $filterValues = []): Collection
{
$queryBuilder = $field->values()->orderBy('sequence');
if (! empty($filterValues)) {
$queryBuilder->whereIn('value', $filterValues);
}
return $queryBuilder->get();
}
public function updatePicklistValue(Field $field, array $picklistValueData): FieldValue
{
/** @var FieldValue */
return $this->updateOrCreateFieldValue($field, $picklistValueData);
}
public function deleteObsoleteField(Configuration $configuration, string $objectType, string $crmProviderId): void
{
$configuration->fields()
->where('object_type', $objectType)
->where('crm_provider_id', $crmProviderId)
->delete();
}
/**
* @param Configuration $configuration
* @param string $objectType
* @param string[] $crmProviderIds
*
* @return Collection<Field>
*/
public function identifyTeamCrmFields(
Configuration $configuration,
string $objectType,
array $crmProviderIds,
): Collection {
return $configuration->fields()
->where('object_type', $objectType)
->whereIn('crm_provider_id', $crmProviderIds)
->get();
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\LazyCollection;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Crm\\Metadata\\OptionMetadata;\n\nclass FieldRepository\n{\n /**\n * @return Collection<Field>\n */\n public function getAllFieldsForObjectType(Team $team, string $objectType): Collection\n {\n return $team->getCrmConfiguration()\n ->fields()\n ->where('object_type', '=', $objectType)\n ->get()\n ;\n }\n\n /**\n * @param Team $team\n * @param string[] $objectTypes\n *\n * @return Collection<Field>\n */\n public function findAllSelectableByObjectTypes(Team $team, array $objectTypes): Collection\n {\n return $team->getCrmConfiguration()\n ->fields()\n ->whereIn('object_type', $objectTypes)\n ->where('is_selectable', true)\n ->orderBy('label')\n ->get()\n ;\n }\n\n public function idOrUuid(int|string $id): ?Field\n {\n /** @var ?Field */\n return Field::idOrUuid($id);\n }\n\n /**\n * @param OptionMetadata[] $options\n */\n public function updatePicklistValues(Field $field, array $options): void\n {\n $field->values()->delete();\n\n foreach ($options as $option) {\n $field->values()->updateOrCreate([\n 'value' => $option->getId(),\n 'label' => $option->getLabel(),\n ], [\n 'sequence' => $option->getSequence(),\n ]);\n }\n }\n\n public function updateOrCreateFieldValue(Field $field, array $data): FieldValue\n {\n /** @var FieldValue */\n return $field->values()->updateOrCreate([\n 'value' => $data['value'],\n ], $data);\n }\n\n public function updateOrCreateOpportunityFieldData(\n Field $field,\n int $layoutEntityId,\n int $opportunityId,\n string $value,\n ): void {\n $field->data()->updateOrCreate([\n 'crm_layout_entity_id' => $layoutEntityId,\n 'crm_field_id' => $field->getId(),\n 'object_type' => Field::OBJECT_OPPORTUNITY,\n 'object_id' => $opportunityId,\n ], ['value' => $value]);\n }\n\n public function findOneByCrmProviderId(Configuration $configuration, string $fieldId): ?Field\n {\n /** @var Field */\n return $configuration->fields()->where('crm_provider_id', $fieldId)->first();\n }\n\n /**\n * @param array<string,scalar> $data\n */\n public function updateField(Field $field, array $data): void\n {\n $field->update($data);\n }\n\n public function upsertField(Configuration $configuration, array $data): Field\n {\n /** @var Field */\n return $configuration->fields()->updateOrCreate(\n [\n 'crm_provider_id' => $data['crm_provider_id'],\n 'object_type' => $data['object_type'],\n ],\n $data,\n );\n }\n\n public function findFieldByCrmIdAndObjectType(\n Configuration $configuration,\n string $fieldId,\n string $objectType,\n ): ?Field {\n /** @var Field */\n return $configuration->fields()\n ->where('crm_provider_id', $fieldId)\n ->where('object_type', $objectType)\n ->first();\n }\n\n public function findAllFilterable(Team $team): LazyCollection\n {\n return $team\n ->getCrmConfiguration()\n ->fields()\n ->where('is_filterable', true)\n ->cursor();\n }\n\n public function findOneByCrmProviderIdAndObjectType(\n Configuration $configuration,\n string $fieldId,\n string $objectType,\n ): ?Field {\n /** @var ?Field */\n return $configuration\n ->fields()\n ->where('crm_provider_id', $fieldId)\n ->where('object_type', $objectType)\n ->first();\n }\n\n public function findOneConfigurationFieldByProperties(Configuration $configuration, array $properties): ?Field\n {\n return $configuration->fields()\n ->where($properties)\n ->first();\n }\n\n public function getPicklistValues(Field $field, ?array $filterValues = []): Collection\n {\n $queryBuilder = $field->values()->orderBy('sequence');\n\n if (! empty($filterValues)) {\n $queryBuilder->whereIn('value', $filterValues);\n }\n\n return $queryBuilder->get();\n }\n\n public function updatePicklistValue(Field $field, array $picklistValueData): FieldValue\n {\n /** @var FieldValue */\n return $this->updateOrCreateFieldValue($field, $picklistValueData);\n }\n\n public function deleteObsoleteField(Configuration $configuration, string $objectType, string $crmProviderId): void\n {\n $configuration->fields()\n ->where('object_type', $objectType)\n ->where('crm_provider_id', $crmProviderId)\n ->delete();\n }\n\n /**\n * @param Configuration $configuration\n * @param string $objectType\n * @param string[] $crmProviderIds\n *\n * @return Collection<Field>\n */\n public function identifyTeamCrmFields(\n Configuration $configuration,\n string $objectType,\n array $crmProviderIds,\n ): Collection {\n return $configuration->fields()\n ->where('object_type', $objectType)\n ->whereIn('crm_provider_id', $crmProviderIds)\n ->get();\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\LazyCollection;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Crm\\Metadata\\OptionMetadata;\n\nclass FieldRepository\n{\n /**\n * @return Collection<Field>\n */\n public function getAllFieldsForObjectType(Team $team, string $objectType): Collection\n {\n return $team->getCrmConfiguration()\n ->fields()\n ->where('object_type', '=', $objectType)\n ->get()\n ;\n }\n\n /**\n * @param Team $team\n * @param string[] $objectTypes\n *\n * @return Collection<Field>\n */\n public function findAllSelectableByObjectTypes(Team $team, array $objectTypes): Collection\n {\n return $team->getCrmConfiguration()\n ->fields()\n ->whereIn('object_type', $objectTypes)\n ->where('is_selectable', true)\n ->orderBy('label')\n ->get()\n ;\n }\n\n public function idOrUuid(int|string $id): ?Field\n {\n /** @var ?Field */\n return Field::idOrUuid($id);\n }\n\n /**\n * @param OptionMetadata[] $options\n */\n public function updatePicklistValues(Field $field, array $options): void\n {\n $field->values()->delete();\n\n foreach ($options as $option) {\n $field->values()->updateOrCreate([\n 'value' => $option->getId(),\n 'label' => $option->getLabel(),\n ], [\n 'sequence' => $option->getSequence(),\n ]);\n }\n }\n\n public function updateOrCreateFieldValue(Field $field, array $data): FieldValue\n {\n /** @var FieldValue */\n return $field->values()->updateOrCreate([\n 'value' => $data['value'],\n ], $data);\n }\n\n public function updateOrCreateOpportunityFieldData(\n Field $field,\n int $layoutEntityId,\n int $opportunityId,\n string $value,\n ): void {\n $field->data()->updateOrCreate([\n 'crm_layout_entity_id' => $layoutEntityId,\n 'crm_field_id' => $field->getId(),\n 'object_type' => Field::OBJECT_OPPORTUNITY,\n 'object_id' => $opportunityId,\n ], ['value' => $value]);\n }\n\n public function findOneByCrmProviderId(Configuration $configuration, string $fieldId): ?Field\n {\n /** @var Field */\n return $configuration->fields()->where('crm_provider_id', $fieldId)->first();\n }\n\n /**\n * @param array<string,scalar> $data\n */\n public function updateField(Field $field, array $data): void\n {\n $field->update($data);\n }\n\n public function upsertField(Configuration $configuration, array $data): Field\n {\n /** @var Field */\n return $configuration->fields()->updateOrCreate(\n [\n 'crm_provider_id' => $data['crm_provider_id'],\n 'object_type' => $data['object_type'],\n ],\n $data,\n );\n }\n\n public function findFieldByCrmIdAndObjectType(\n Configuration $configuration,\n string $fieldId,\n string $objectType,\n ): ?Field {\n /** @var Field */\n return $configuration->fields()\n ->where('crm_provider_id', $fieldId)\n ->where('object_type', $objectType)\n ->first();\n }\n\n public function findAllFilterable(Team $team): LazyCollection\n {\n return $team\n ->getCrmConfiguration()\n ->fields()\n ->where('is_filterable', true)\n ->cursor();\n }\n\n public function findOneByCrmProviderIdAndObjectType(\n Configuration $configuration,\n string $fieldId,\n string $objectType,\n ): ?Field {\n /** @var ?Field */\n return $configuration\n ->fields()\n ->where('crm_provider_id', $fieldId)\n ->where('object_type', $objectType)\n ->first();\n }\n\n public function findOneConfigurationFieldByProperties(Configuration $configuration, array $properties): ?Field\n {\n return $configuration->fields()\n ->where($properties)\n ->first();\n }\n\n public function getPicklistValues(Field $field, ?array $filterValues = []): Collection\n {\n $queryBuilder = $field->values()->orderBy('sequence');\n\n if (! empty($filterValues)) {\n $queryBuilder->whereIn('value', $filterValues);\n }\n\n return $queryBuilder->get();\n }\n\n public function updatePicklistValue(Field $field, array $picklistValueData): FieldValue\n {\n /** @var FieldValue */\n return $this->updateOrCreateFieldValue($field, $picklistValueData);\n }\n\n public function deleteObsoleteField(Configuration $configuration, string $objectType, string $crmProviderId): void\n {\n $configuration->fields()\n ->where('object_type', $objectType)\n ->where('crm_provider_id', $crmProviderId)\n ->delete();\n }\n\n /**\n * @param Configuration $configuration\n * @param string $objectType\n * @param string[] $crmProviderIds\n *\n * @return Collection<Field>\n */\n public function identifyTeamCrmFields(\n Configuration $configuration,\n string $objectType,\n array $crmProviderIds,\n ): Collection {\n return $configuration->fields()\n ->where('object_type', $objectType)\n ->whereIn('crm_provider_id', $crmProviderIds)\n ->get();\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"on_screen":false,"role_description":"text"}]...
|
6098876064718157734
|
-4167677811951817355
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use Illuminate\Support\Collection;
use Illuminate\Support\LazyCollection;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Team;
use Jiminny\Services\Crm\Metadata\OptionMetadata;
class FieldRepository
{
/**
* @return Collection<Field>
*/
public function getAllFieldsForObjectType(Team $team, string $objectType): Collection
{
return $team->getCrmConfiguration()
->fields()
->where('object_type', '=', $objectType)
->get()
;
}
/**
* @param Team $team
* @param string[] $objectTypes
*
* @return Collection<Field>
*/
public function findAllSelectableByObjectTypes(Team $team, array $objectTypes): Collection
{
return $team->getCrmConfiguration()
->fields()
->whereIn('object_type', $objectTypes)
->where('is_selectable', true)
->orderBy('label')
->get()
;
}
public function idOrUuid(int|string $id): ?Field
{
/** @var ?Field */
return Field::idOrUuid($id);
}
/**
* @param OptionMetadata[] $options
*/
public function updatePicklistValues(Field $field, array $options): void
{
$field->values()->delete();
foreach ($options as $option) {
$field->values()->updateOrCreate([
'value' => $option->getId(),
'label' => $option->getLabel(),
], [
'sequence' => $option->getSequence(),
]);
}
}
public function updateOrCreateFieldValue(Field $field, array $data): FieldValue
{
/** @var FieldValue */
return $field->values()->updateOrCreate([
'value' => $data['value'],
], $data);
}
public function updateOrCreateOpportunityFieldData(
Field $field,
int $layoutEntityId,
int $opportunityId,
string $value,
): void {
$field->data()->updateOrCreate([
'crm_layout_entity_id' => $layoutEntityId,
'crm_field_id' => $field->getId(),
'object_type' => Field::OBJECT_OPPORTUNITY,
'object_id' => $opportunityId,
], ['value' => $value]);
}
public function findOneByCrmProviderId(Configuration $configuration, string $fieldId): ?Field
{
/** @var Field */
return $configuration->fields()->where('crm_provider_id', $fieldId)->first();
}
/**
* @param array<string,scalar> $data
*/
public function updateField(Field $field, array $data): void
{
$field->update($data);
}
public function upsertField(Configuration $configuration, array $data): Field
{
/** @var Field */
return $configuration->fields()->updateOrCreate(
[
'crm_provider_id' => $data['crm_provider_id'],
'object_type' => $data['object_type'],
],
$data,
);
}
public function findFieldByCrmIdAndObjectType(
Configuration $configuration,
string $fieldId,
string $objectType,
): ?Field {
/** @var Field */
return $configuration->fields()
->where('crm_provider_id', $fieldId)
->where('object_type', $objectType)
->first();
}
public function findAllFilterable(Team $team): LazyCollection
{
return $team
->getCrmConfiguration()
->fields()
->where('is_filterable', true)
->cursor();
}
public function findOneByCrmProviderIdAndObjectType(
Configuration $configuration,
string $fieldId,
string $objectType,
): ?Field {
/** @var ?Field */
return $configuration
->fields()
->where('crm_provider_id', $fieldId)
->where('object_type', $objectType)
->first();
}
public function findOneConfigurationFieldByProperties(Configuration $configuration, array $properties): ?Field
{
return $configuration->fields()
->where($properties)
->first();
}
public function getPicklistValues(Field $field, ?array $filterValues = []): Collection
{
$queryBuilder = $field->values()->orderBy('sequence');
if (! empty($filterValues)) {
$queryBuilder->whereIn('value', $filterValues);
}
return $queryBuilder->get();
}
public function updatePicklistValue(Field $field, array $picklistValueData): FieldValue
{
/** @var FieldValue */
return $this->updateOrCreateFieldValue($field, $picklistValueData);
}
public function deleteObsoleteField(Configuration $configuration, string $objectType, string $crmProviderId): void
{
$configuration->fields()
->where('object_type', $objectType)
->where('crm_provider_id', $crmProviderId)
->delete();
}
/**
* @param Configuration $configuration
* @param string $objectType
* @param string[] $crmProviderIds
*
* @return Collection<Field>
*/
public function identifyTeamCrmFields(
Configuration $configuration,
string $objectType,
array $crmProviderIds,
): Collection {
return $configuration->fields()
->where('object_type', $objectType)
->whereIn('crm_provider_id', $crmProviderIds)
->get();
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65490
|
2307
|
20
|
2026-05-21T07:42:00.666858+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349320666_m2.jpg...
|
PhpStorm
|
faVsco.js – FieldRepository.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use Illuminate\Support\Collection;
use Illuminate\Support\LazyCollection;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Team;
use Jiminny\Services\Crm\Metadata\OptionMetadata;
class FieldRepository
{
/**
* @return Collection<Field>
*/
public function getAllFieldsForObjectType(Team $team, string $objectType): Collection
{
return $team->getCrmConfiguration()
->fields()
->where('object_type', '=', $objectType)
->get()
;
}
/**
* @param Team $team
* @param string[] $objectTypes
*
* @return Collection<Field>
*/
public function findAllSelectableByObjectTypes(Team $team, array $objectTypes): Collection
{
return $team->getCrmConfiguration()
->fields()
->whereIn('object_type', $objectTypes)
->where('is_selectable', true)
->orderBy('label')
->get()
;
}
public function idOrUuid(int|string $id): ?Field
{
/** @var ?Field */
return Field::idOrUuid($id);
}
/**
* @param OptionMetadata[] $options
*/
public function updatePicklistValues(Field $field, array $options): void
{
$field->values()->delete();
foreach ($options as $option) {
$field->values()->updateOrCreate([
'value' => $option->getId(),
'label' => $option->getLabel(),
], [
'sequence' => $option->getSequence(),
]);
}
}
public function updateOrCreateFieldValue(Field $field, array $data): FieldValue
{
/** @var FieldValue */
return $field->values()->updateOrCreate([
'value' => $data['value'],
], $data);
}
public function updateOrCreateOpportunityFieldData(
Field $field,
int $layoutEntityId,
int $opportunityId,
string $value,
): void {
$field->data()->updateOrCreate([
'crm_layout_entity_id' => $layoutEntityId,
'crm_field_id' => $field->getId(),
'object_type' => Field::OBJECT_OPPORTUNITY,
'object_id' => $opportunityId,
], ['value' => $value]);
}
public function findOneByCrmProviderId(Configuration $configuration, string $fieldId): ?Field
{
/** @var Field */
return $configuration->fields()->where('crm_provider_id', $fieldId)->first();
}
/**
* @param array<string,scalar> $data
*/
public function updateField(Field $field, array $data): void
{
$field->update($data);
}
public function upsertField(Configuration $configuration, array $data): Field
{
/** @var Field */
return $configuration->fields()->updateOrCreate(
[
'crm_provider_id' => $data['crm_provider_id'],
'object_type' => $data['object_type'],
],
$data,
);
}
public function findFieldByCrmIdAndObjectType(
Configuration $configuration,
string $fieldId,
string $objectType,
): ?Field {
/** @var Field */
return $configuration->fields()
->where('crm_provider_id', $fieldId)
->where('object_type', $objectType)
->first();
}
public function findAllFilterable(Team $team): LazyCollection
{
return $team
->getCrmConfiguration()
->fields()
->where('is_filterable', true)
->cursor();
}
public function findOneByCrmProviderIdAndObjectType(
Configuration $configuration,
string $fieldId,
string $objectType,
): ?Field {
/** @var ?Field */
return $configuration
->fields()
->where('crm_provider_id', $fieldId)
->where('object_type', $objectType)
->first();
}
public function findOneConfigurationFieldByProperties(Configuration $configuration, array $properties): ?Field
{
return $configuration->fields()
->where($properties)
->first();
}
public function getPicklistValues(Field $field, ?array $filterValues = []): Collection
{
$queryBuilder = $field->values()->orderBy('sequence');
if (! empty($filterValues)) {
$queryBuilder->whereIn('value', $filterValues);
}
return $queryBuilder->get();
}
public function updatePicklistValue(Field $field, array $picklistValueData): FieldValue
{
/** @var FieldValue */
return $this->updateOrCreateFieldValue($field, $picklistValueData);
}
public function deleteObsoleteField(Configuration $configuration, string $objectType, string $crmProviderId): void
{
$configuration->fields()
->where('object_type', $objectType)
->where('crm_provider_id', $crmProviderId)
->delete();
}
/**
* @param Configuration $configuration
* @param string $objectType
* @param string[] $crmProviderIds
*
* @return Collection<Field>
*/
public function identifyTeamCrmFields(
Configuration $configuration,
string $objectType,
array $crmProviderIds,
): Collection {
return $configuration->fields()
->where('object_type', $objectType)
->whereIn('crm_provider_id', $crmProviderIds)
->get();
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\LazyCollection;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Crm\\Metadata\\OptionMetadata;\n\nclass FieldRepository\n{\n /**\n * @return Collection<Field>\n */\n public function getAllFieldsForObjectType(Team $team, string $objectType): Collection\n {\n return $team->getCrmConfiguration()\n ->fields()\n ->where('object_type', '=', $objectType)\n ->get()\n ;\n }\n\n /**\n * @param Team $team\n * @param string[] $objectTypes\n *\n * @return Collection<Field>\n */\n public function findAllSelectableByObjectTypes(Team $team, array $objectTypes): Collection\n {\n return $team->getCrmConfiguration()\n ->fields()\n ->whereIn('object_type', $objectTypes)\n ->where('is_selectable', true)\n ->orderBy('label')\n ->get()\n ;\n }\n\n public function idOrUuid(int|string $id): ?Field\n {\n /** @var ?Field */\n return Field::idOrUuid($id);\n }\n\n /**\n * @param OptionMetadata[] $options\n */\n public function updatePicklistValues(Field $field, array $options): void\n {\n $field->values()->delete();\n\n foreach ($options as $option) {\n $field->values()->updateOrCreate([\n 'value' => $option->getId(),\n 'label' => $option->getLabel(),\n ], [\n 'sequence' => $option->getSequence(),\n ]);\n }\n }\n\n public function updateOrCreateFieldValue(Field $field, array $data): FieldValue\n {\n /** @var FieldValue */\n return $field->values()->updateOrCreate([\n 'value' => $data['value'],\n ], $data);\n }\n\n public function updateOrCreateOpportunityFieldData(\n Field $field,\n int $layoutEntityId,\n int $opportunityId,\n string $value,\n ): void {\n $field->data()->updateOrCreate([\n 'crm_layout_entity_id' => $layoutEntityId,\n 'crm_field_id' => $field->getId(),\n 'object_type' => Field::OBJECT_OPPORTUNITY,\n 'object_id' => $opportunityId,\n ], ['value' => $value]);\n }\n\n public function findOneByCrmProviderId(Configuration $configuration, string $fieldId): ?Field\n {\n /** @var Field */\n return $configuration->fields()->where('crm_provider_id', $fieldId)->first();\n }\n\n /**\n * @param array<string,scalar> $data\n */\n public function updateField(Field $field, array $data): void\n {\n $field->update($data);\n }\n\n public function upsertField(Configuration $configuration, array $data): Field\n {\n /** @var Field */\n return $configuration->fields()->updateOrCreate(\n [\n 'crm_provider_id' => $data['crm_provider_id'],\n 'object_type' => $data['object_type'],\n ],\n $data,\n );\n }\n\n public function findFieldByCrmIdAndObjectType(\n Configuration $configuration,\n string $fieldId,\n string $objectType,\n ): ?Field {\n /** @var Field */\n return $configuration->fields()\n ->where('crm_provider_id', $fieldId)\n ->where('object_type', $objectType)\n ->first();\n }\n\n public function findAllFilterable(Team $team): LazyCollection\n {\n return $team\n ->getCrmConfiguration()\n ->fields()\n ->where('is_filterable', true)\n ->cursor();\n }\n\n public function findOneByCrmProviderIdAndObjectType(\n Configuration $configuration,\n string $fieldId,\n string $objectType,\n ): ?Field {\n /** @var ?Field */\n return $configuration\n ->fields()\n ->where('crm_provider_id', $fieldId)\n ->where('object_type', $objectType)\n ->first();\n }\n\n public function findOneConfigurationFieldByProperties(Configuration $configuration, array $properties): ?Field\n {\n return $configuration->fields()\n ->where($properties)\n ->first();\n }\n\n public function getPicklistValues(Field $field, ?array $filterValues = []): Collection\n {\n $queryBuilder = $field->values()->orderBy('sequence');\n\n if (! empty($filterValues)) {\n $queryBuilder->whereIn('value', $filterValues);\n }\n\n return $queryBuilder->get();\n }\n\n public function updatePicklistValue(Field $field, array $picklistValueData): FieldValue\n {\n /** @var FieldValue */\n return $this->updateOrCreateFieldValue($field, $picklistValueData);\n }\n\n public function deleteObsoleteField(Configuration $configuration, string $objectType, string $crmProviderId): void\n {\n $configuration->fields()\n ->where('object_type', $objectType)\n ->where('crm_provider_id', $crmProviderId)\n ->delete();\n }\n\n /**\n * @param Configuration $configuration\n * @param string $objectType\n * @param string[] $crmProviderIds\n *\n * @return Collection<Field>\n */\n public function identifyTeamCrmFields(\n Configuration $configuration,\n string $objectType,\n array $crmProviderIds,\n ): Collection {\n return $configuration->fields()\n ->where('object_type', $objectType)\n ->whereIn('crm_provider_id', $crmProviderIds)\n ->get();\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\LazyCollection;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Crm\\Metadata\\OptionMetadata;\n\nclass FieldRepository\n{\n /**\n * @return Collection<Field>\n */\n public function getAllFieldsForObjectType(Team $team, string $objectType): Collection\n {\n return $team->getCrmConfiguration()\n ->fields()\n ->where('object_type', '=', $objectType)\n ->get()\n ;\n }\n\n /**\n * @param Team $team\n * @param string[] $objectTypes\n *\n * @return Collection<Field>\n */\n public function findAllSelectableByObjectTypes(Team $team, array $objectTypes): Collection\n {\n return $team->getCrmConfiguration()\n ->fields()\n ->whereIn('object_type', $objectTypes)\n ->where('is_selectable', true)\n ->orderBy('label')\n ->get()\n ;\n }\n\n public function idOrUuid(int|string $id): ?Field\n {\n /** @var ?Field */\n return Field::idOrUuid($id);\n }\n\n /**\n * @param OptionMetadata[] $options\n */\n public function updatePicklistValues(Field $field, array $options): void\n {\n $field->values()->delete();\n\n foreach ($options as $option) {\n $field->values()->updateOrCreate([\n 'value' => $option->getId(),\n 'label' => $option->getLabel(),\n ], [\n 'sequence' => $option->getSequence(),\n ]);\n }\n }\n\n public function updateOrCreateFieldValue(Field $field, array $data): FieldValue\n {\n /** @var FieldValue */\n return $field->values()->updateOrCreate([\n 'value' => $data['value'],\n ], $data);\n }\n\n public function updateOrCreateOpportunityFieldData(\n Field $field,\n int $layoutEntityId,\n int $opportunityId,\n string $value,\n ): void {\n $field->data()->updateOrCreate([\n 'crm_layout_entity_id' => $layoutEntityId,\n 'crm_field_id' => $field->getId(),\n 'object_type' => Field::OBJECT_OPPORTUNITY,\n 'object_id' => $opportunityId,\n ], ['value' => $value]);\n }\n\n public function findOneByCrmProviderId(Configuration $configuration, string $fieldId): ?Field\n {\n /** @var Field */\n return $configuration->fields()->where('crm_provider_id', $fieldId)->first();\n }\n\n /**\n * @param array<string,scalar> $data\n */\n public function updateField(Field $field, array $data): void\n {\n $field->update($data);\n }\n\n public function upsertField(Configuration $configuration, array $data): Field\n {\n /** @var Field */\n return $configuration->fields()->updateOrCreate(\n [\n 'crm_provider_id' => $data['crm_provider_id'],\n 'object_type' => $data['object_type'],\n ],\n $data,\n );\n }\n\n public function findFieldByCrmIdAndObjectType(\n Configuration $configuration,\n string $fieldId,\n string $objectType,\n ): ?Field {\n /** @var Field */\n return $configuration->fields()\n ->where('crm_provider_id', $fieldId)\n ->where('object_type', $objectType)\n ->first();\n }\n\n public function findAllFilterable(Team $team): LazyCollection\n {\n return $team\n ->getCrmConfiguration()\n ->fields()\n ->where('is_filterable', true)\n ->cursor();\n }\n\n public function findOneByCrmProviderIdAndObjectType(\n Configuration $configuration,\n string $fieldId,\n string $objectType,\n ): ?Field {\n /** @var ?Field */\n return $configuration\n ->fields()\n ->where('crm_provider_id', $fieldId)\n ->where('object_type', $objectType)\n ->first();\n }\n\n public function findOneConfigurationFieldByProperties(Configuration $configuration, array $properties): ?Field\n {\n return $configuration->fields()\n ->where($properties)\n ->first();\n }\n\n public function getPicklistValues(Field $field, ?array $filterValues = []): Collection\n {\n $queryBuilder = $field->values()->orderBy('sequence');\n\n if (! empty($filterValues)) {\n $queryBuilder->whereIn('value', $filterValues);\n }\n\n return $queryBuilder->get();\n }\n\n public function updatePicklistValue(Field $field, array $picklistValueData): FieldValue\n {\n /** @var FieldValue */\n return $this->updateOrCreateFieldValue($field, $picklistValueData);\n }\n\n public function deleteObsoleteField(Configuration $configuration, string $objectType, string $crmProviderId): void\n {\n $configuration->fields()\n ->where('object_type', $objectType)\n ->where('crm_provider_id', $crmProviderId)\n ->delete();\n }\n\n /**\n * @param Configuration $configuration\n * @param string $objectType\n * @param string[] $crmProviderIds\n *\n * @return Collection<Field>\n */\n public function identifyTeamCrmFields(\n Configuration $configuration,\n string $objectType,\n array $crmProviderIds,\n ): Collection {\n return $configuration->fields()\n ->where('object_type', $objectType)\n ->whereIn('crm_provider_id', $crmProviderIds)\n ->get();\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"bounds":{"left":0.44547874,"top":0.09736632,"width":0.29022607,"height":0.8818835},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"}]...
|
1363923065559702658
|
-4131508276899304075
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use Illuminate\Support\Collection;
use Illuminate\Support\LazyCollection;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Team;
use Jiminny\Services\Crm\Metadata\OptionMetadata;
class FieldRepository
{
/**
* @return Collection<Field>
*/
public function getAllFieldsForObjectType(Team $team, string $objectType): Collection
{
return $team->getCrmConfiguration()
->fields()
->where('object_type', '=', $objectType)
->get()
;
}
/**
* @param Team $team
* @param string[] $objectTypes
*
* @return Collection<Field>
*/
public function findAllSelectableByObjectTypes(Team $team, array $objectTypes): Collection
{
return $team->getCrmConfiguration()
->fields()
->whereIn('object_type', $objectTypes)
->where('is_selectable', true)
->orderBy('label')
->get()
;
}
public function idOrUuid(int|string $id): ?Field
{
/** @var ?Field */
return Field::idOrUuid($id);
}
/**
* @param OptionMetadata[] $options
*/
public function updatePicklistValues(Field $field, array $options): void
{
$field->values()->delete();
foreach ($options as $option) {
$field->values()->updateOrCreate([
'value' => $option->getId(),
'label' => $option->getLabel(),
], [
'sequence' => $option->getSequence(),
]);
}
}
public function updateOrCreateFieldValue(Field $field, array $data): FieldValue
{
/** @var FieldValue */
return $field->values()->updateOrCreate([
'value' => $data['value'],
], $data);
}
public function updateOrCreateOpportunityFieldData(
Field $field,
int $layoutEntityId,
int $opportunityId,
string $value,
): void {
$field->data()->updateOrCreate([
'crm_layout_entity_id' => $layoutEntityId,
'crm_field_id' => $field->getId(),
'object_type' => Field::OBJECT_OPPORTUNITY,
'object_id' => $opportunityId,
], ['value' => $value]);
}
public function findOneByCrmProviderId(Configuration $configuration, string $fieldId): ?Field
{
/** @var Field */
return $configuration->fields()->where('crm_provider_id', $fieldId)->first();
}
/**
* @param array<string,scalar> $data
*/
public function updateField(Field $field, array $data): void
{
$field->update($data);
}
public function upsertField(Configuration $configuration, array $data): Field
{
/** @var Field */
return $configuration->fields()->updateOrCreate(
[
'crm_provider_id' => $data['crm_provider_id'],
'object_type' => $data['object_type'],
],
$data,
);
}
public function findFieldByCrmIdAndObjectType(
Configuration $configuration,
string $fieldId,
string $objectType,
): ?Field {
/** @var Field */
return $configuration->fields()
->where('crm_provider_id', $fieldId)
->where('object_type', $objectType)
->first();
}
public function findAllFilterable(Team $team): LazyCollection
{
return $team
->getCrmConfiguration()
->fields()
->where('is_filterable', true)
->cursor();
}
public function findOneByCrmProviderIdAndObjectType(
Configuration $configuration,
string $fieldId,
string $objectType,
): ?Field {
/** @var ?Field */
return $configuration
->fields()
->where('crm_provider_id', $fieldId)
->where('object_type', $objectType)
->first();
}
public function findOneConfigurationFieldByProperties(Configuration $configuration, array $properties): ?Field
{
return $configuration->fields()
->where($properties)
->first();
}
public function getPicklistValues(Field $field, ?array $filterValues = []): Collection
{
$queryBuilder = $field->values()->orderBy('sequence');
if (! empty($filterValues)) {
$queryBuilder->whereIn('value', $filterValues);
}
return $queryBuilder->get();
}
public function updatePicklistValue(Field $field, array $picklistValueData): FieldValue
{
/** @var FieldValue */
return $this->updateOrCreateFieldValue($field, $picklistValueData);
}
public function deleteObsoleteField(Configuration $configuration, string $objectType, string $crmProviderId): void
{
$configuration->fields()
->where('object_type', $objectType)
->where('crm_provider_id', $crmProviderId)
->delete();
}
/**
* @param Configuration $configuration
* @param string $objectType
* @param string[] $crmProviderIds
*
* @return Collection<Field>
*/
public function identifyTeamCrmFields(
Configuration $configuration,
string $objectType,
array $crmProviderIds,
): Collection {
return $configuration->fields()
->where('object_type', $objectType)
->whereIn('crm_provider_id', $crmProviderIds)
->get();
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions...
|
65488
|
NULL
|
NULL
|
NULL
|
|
65489
|
2306
|
26
|
2026-05-21T07:42:00.646466+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349320646_m1.jpg...
|
PhpStorm
|
faVsco.js – FieldRepository.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use Illuminate\Support\Collection;
use Illuminate\Support\LazyCollection;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Team;
use Jiminny\Services\Crm\Metadata\OptionMetadata;
class FieldRepository
{
/**
* @return Collection<Field>
*/
public function getAllFieldsForObjectType(Team $team, string $objectType): Collection
{
return $team->getCrmConfiguration()
->fields()
->where('object_type', '=', $objectType)
->get()
;
}
/**
* @param Team $team
* @param string[] $objectTypes
*
* @return Collection<Field>
*/
public function findAllSelectableByObjectTypes(Team $team, array $objectTypes): Collection
{
return $team->getCrmConfiguration()
->fields()
->whereIn('object_type', $objectTypes)
->where('is_selectable', true)
->orderBy('label')
->get()
;
}
public function idOrUuid(int|string $id): ?Field
{
/** @var ?Field */
return Field::idOrUuid($id);
}
/**
* @param OptionMetadata[] $options
*/
public function updatePicklistValues(Field $field, array $options): void
{
$field->values()->delete();
foreach ($options as $option) {
$field->values()->updateOrCreate([
'value' => $option->getId(),
'label' => $option->getLabel(),
], [
'sequence' => $option->getSequence(),
]);
}
}
public function updateOrCreateFieldValue(Field $field, array $data): FieldValue
{
/** @var FieldValue */
return $field->values()->updateOrCreate([
'value' => $data['value'],
], $data);
}
public function updateOrCreateOpportunityFieldData(
Field $field,
int $layoutEntityId,
int $opportunityId,
string $value,
): void {
$field->data()->updateOrCreate([
'crm_layout_entity_id' => $layoutEntityId,
'crm_field_id' => $field->getId(),
'object_type' => Field::OBJECT_OPPORTUNITY,
'object_id' => $opportunityId,
], ['value' => $value]);
}
public function findOneByCrmProviderId(Configuration $configuration, string $fieldId): ?Field
{
/** @var Field */
return $configuration->fields()->where('crm_provider_id', $fieldId)->first();
}
/**
* @param array<string,scalar> $data
*/
public function updateField(Field $field, array $data): void
{
$field->update($data);
}
public function upsertField(Configuration $configuration, array $data): Field
{
/** @var Field */
return $configuration->fields()->updateOrCreate(
[
'crm_provider_id' => $data['crm_provider_id'],
'object_type' => $data['object_type'],
],
$data,
);
}
public function findFieldByCrmIdAndObjectType(
Configuration $configuration,
string $fieldId,
string $objectType,
): ?Field {
/** @var Field */
return $configuration->fields()
->where('crm_provider_id', $fieldId)
->where('object_type', $objectType)
->first();
}
public function findAllFilterable(Team $team): LazyCollection
{
return $team
->getCrmConfiguration()
->fields()
->where('is_filterable', true)
->cursor();
}
public function findOneByCrmProviderIdAndObjectType(
Configuration $configuration,
string $fieldId,
string $objectType,
): ?Field {
/** @var ?Field */
return $configuration
->fields()
->where('crm_provider_id', $fieldId)
->where('object_type', $objectType)
->first();
}
public function findOneConfigurationFieldByProperties(Configuration $configuration, array $properties): ?Field
{
return $configuration->fields()
->where($properties)
->first();
}
public function getPicklistValues(Field $field, ?array $filterValues = []): Collection
{
$queryBuilder = $field->values()->orderBy('sequence');
if (! empty($filterValues)) {
$queryBuilder->whereIn('value', $filterValues);
}
return $queryBuilder->get();
}
public function updatePicklistValue(Field $field, array $picklistValueData): FieldValue
{
/** @var FieldValue */
return $this->updateOrCreateFieldValue($field, $picklistValueData);
}
public function deleteObsoleteField(Configuration $configuration, string $objectType, string $crmProviderId): void
{
$configuration->fields()
->where('object_type', $objectType)
->where('crm_provider_id', $crmProviderId)
->delete();
}
/**
* @param Configuration $configuration
* @param string $objectType
* @param string[] $crmProviderIds
*
* @return Collection<Field>
*/
public function identifyTeamCrmFields(
Configuration $configuration,
string $objectType,
array $crmProviderIds,
): Collection {
return $configuration->fields()
->where('object_type', $objectType)
->whereIn('crm_provider_id', $crmProviderIds)
->get();
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\LazyCollection;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Crm\\Metadata\\OptionMetadata;\n\nclass FieldRepository\n{\n /**\n * @return Collection<Field>\n */\n public function getAllFieldsForObjectType(Team $team, string $objectType): Collection\n {\n return $team->getCrmConfiguration()\n ->fields()\n ->where('object_type', '=', $objectType)\n ->get()\n ;\n }\n\n /**\n * @param Team $team\n * @param string[] $objectTypes\n *\n * @return Collection<Field>\n */\n public function findAllSelectableByObjectTypes(Team $team, array $objectTypes): Collection\n {\n return $team->getCrmConfiguration()\n ->fields()\n ->whereIn('object_type', $objectTypes)\n ->where('is_selectable', true)\n ->orderBy('label')\n ->get()\n ;\n }\n\n public function idOrUuid(int|string $id): ?Field\n {\n /** @var ?Field */\n return Field::idOrUuid($id);\n }\n\n /**\n * @param OptionMetadata[] $options\n */\n public function updatePicklistValues(Field $field, array $options): void\n {\n $field->values()->delete();\n\n foreach ($options as $option) {\n $field->values()->updateOrCreate([\n 'value' => $option->getId(),\n 'label' => $option->getLabel(),\n ], [\n 'sequence' => $option->getSequence(),\n ]);\n }\n }\n\n public function updateOrCreateFieldValue(Field $field, array $data): FieldValue\n {\n /** @var FieldValue */\n return $field->values()->updateOrCreate([\n 'value' => $data['value'],\n ], $data);\n }\n\n public function updateOrCreateOpportunityFieldData(\n Field $field,\n int $layoutEntityId,\n int $opportunityId,\n string $value,\n ): void {\n $field->data()->updateOrCreate([\n 'crm_layout_entity_id' => $layoutEntityId,\n 'crm_field_id' => $field->getId(),\n 'object_type' => Field::OBJECT_OPPORTUNITY,\n 'object_id' => $opportunityId,\n ], ['value' => $value]);\n }\n\n public function findOneByCrmProviderId(Configuration $configuration, string $fieldId): ?Field\n {\n /** @var Field */\n return $configuration->fields()->where('crm_provider_id', $fieldId)->first();\n }\n\n /**\n * @param array<string,scalar> $data\n */\n public function updateField(Field $field, array $data): void\n {\n $field->update($data);\n }\n\n public function upsertField(Configuration $configuration, array $data): Field\n {\n /** @var Field */\n return $configuration->fields()->updateOrCreate(\n [\n 'crm_provider_id' => $data['crm_provider_id'],\n 'object_type' => $data['object_type'],\n ],\n $data,\n );\n }\n\n public function findFieldByCrmIdAndObjectType(\n Configuration $configuration,\n string $fieldId,\n string $objectType,\n ): ?Field {\n /** @var Field */\n return $configuration->fields()\n ->where('crm_provider_id', $fieldId)\n ->where('object_type', $objectType)\n ->first();\n }\n\n public function findAllFilterable(Team $team): LazyCollection\n {\n return $team\n ->getCrmConfiguration()\n ->fields()\n ->where('is_filterable', true)\n ->cursor();\n }\n\n public function findOneByCrmProviderIdAndObjectType(\n Configuration $configuration,\n string $fieldId,\n string $objectType,\n ): ?Field {\n /** @var ?Field */\n return $configuration\n ->fields()\n ->where('crm_provider_id', $fieldId)\n ->where('object_type', $objectType)\n ->first();\n }\n\n public function findOneConfigurationFieldByProperties(Configuration $configuration, array $properties): ?Field\n {\n return $configuration->fields()\n ->where($properties)\n ->first();\n }\n\n public function getPicklistValues(Field $field, ?array $filterValues = []): Collection\n {\n $queryBuilder = $field->values()->orderBy('sequence');\n\n if (! empty($filterValues)) {\n $queryBuilder->whereIn('value', $filterValues);\n }\n\n return $queryBuilder->get();\n }\n\n public function updatePicklistValue(Field $field, array $picklistValueData): FieldValue\n {\n /** @var FieldValue */\n return $this->updateOrCreateFieldValue($field, $picklistValueData);\n }\n\n public function deleteObsoleteField(Configuration $configuration, string $objectType, string $crmProviderId): void\n {\n $configuration->fields()\n ->where('object_type', $objectType)\n ->where('crm_provider_id', $crmProviderId)\n ->delete();\n }\n\n /**\n * @param Configuration $configuration\n * @param string $objectType\n * @param string[] $crmProviderIds\n *\n * @return Collection<Field>\n */\n public function identifyTeamCrmFields(\n Configuration $configuration,\n string $objectType,\n array $crmProviderIds,\n ): Collection {\n return $configuration->fields()\n ->where('object_type', $objectType)\n ->whereIn('crm_provider_id', $crmProviderIds)\n ->get();\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\LazyCollection;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Crm\\Metadata\\OptionMetadata;\n\nclass FieldRepository\n{\n /**\n * @return Collection<Field>\n */\n public function getAllFieldsForObjectType(Team $team, string $objectType): Collection\n {\n return $team->getCrmConfiguration()\n ->fields()\n ->where('object_type', '=', $objectType)\n ->get()\n ;\n }\n\n /**\n * @param Team $team\n * @param string[] $objectTypes\n *\n * @return Collection<Field>\n */\n public function findAllSelectableByObjectTypes(Team $team, array $objectTypes): Collection\n {\n return $team->getCrmConfiguration()\n ->fields()\n ->whereIn('object_type', $objectTypes)\n ->where('is_selectable', true)\n ->orderBy('label')\n ->get()\n ;\n }\n\n public function idOrUuid(int|string $id): ?Field\n {\n /** @var ?Field */\n return Field::idOrUuid($id);\n }\n\n /**\n * @param OptionMetadata[] $options\n */\n public function updatePicklistValues(Field $field, array $options): void\n {\n $field->values()->delete();\n\n foreach ($options as $option) {\n $field->values()->updateOrCreate([\n 'value' => $option->getId(),\n 'label' => $option->getLabel(),\n ], [\n 'sequence' => $option->getSequence(),\n ]);\n }\n }\n\n public function updateOrCreateFieldValue(Field $field, array $data): FieldValue\n {\n /** @var FieldValue */\n return $field->values()->updateOrCreate([\n 'value' => $data['value'],\n ], $data);\n }\n\n public function updateOrCreateOpportunityFieldData(\n Field $field,\n int $layoutEntityId,\n int $opportunityId,\n string $value,\n ): void {\n $field->data()->updateOrCreate([\n 'crm_layout_entity_id' => $layoutEntityId,\n 'crm_field_id' => $field->getId(),\n 'object_type' => Field::OBJECT_OPPORTUNITY,\n 'object_id' => $opportunityId,\n ], ['value' => $value]);\n }\n\n public function findOneByCrmProviderId(Configuration $configuration, string $fieldId): ?Field\n {\n /** @var Field */\n return $configuration->fields()->where('crm_provider_id', $fieldId)->first();\n }\n\n /**\n * @param array<string,scalar> $data\n */\n public function updateField(Field $field, array $data): void\n {\n $field->update($data);\n }\n\n public function upsertField(Configuration $configuration, array $data): Field\n {\n /** @var Field */\n return $configuration->fields()->updateOrCreate(\n [\n 'crm_provider_id' => $data['crm_provider_id'],\n 'object_type' => $data['object_type'],\n ],\n $data,\n );\n }\n\n public function findFieldByCrmIdAndObjectType(\n Configuration $configuration,\n string $fieldId,\n string $objectType,\n ): ?Field {\n /** @var Field */\n return $configuration->fields()\n ->where('crm_provider_id', $fieldId)\n ->where('object_type', $objectType)\n ->first();\n }\n\n public function findAllFilterable(Team $team): LazyCollection\n {\n return $team\n ->getCrmConfiguration()\n ->fields()\n ->where('is_filterable', true)\n ->cursor();\n }\n\n public function findOneByCrmProviderIdAndObjectType(\n Configuration $configuration,\n string $fieldId,\n string $objectType,\n ): ?Field {\n /** @var ?Field */\n return $configuration\n ->fields()\n ->where('crm_provider_id', $fieldId)\n ->where('object_type', $objectType)\n ->first();\n }\n\n public function findOneConfigurationFieldByProperties(Configuration $configuration, array $properties): ?Field\n {\n return $configuration->fields()\n ->where($properties)\n ->first();\n }\n\n public function getPicklistValues(Field $field, ?array $filterValues = []): Collection\n {\n $queryBuilder = $field->values()->orderBy('sequence');\n\n if (! empty($filterValues)) {\n $queryBuilder->whereIn('value', $filterValues);\n }\n\n return $queryBuilder->get();\n }\n\n public function updatePicklistValue(Field $field, array $picklistValueData): FieldValue\n {\n /** @var FieldValue */\n return $this->updateOrCreateFieldValue($field, $picklistValueData);\n }\n\n public function deleteObsoleteField(Configuration $configuration, string $objectType, string $crmProviderId): void\n {\n $configuration->fields()\n ->where('object_type', $objectType)\n ->where('crm_provider_id', $crmProviderId)\n ->delete();\n }\n\n /**\n * @param Configuration $configuration\n * @param string $objectType\n * @param string[] $crmProviderIds\n *\n * @return Collection<Field>\n */\n public function identifyTeamCrmFields(\n Configuration $configuration,\n string $objectType,\n array $crmProviderIds,\n ): Collection {\n return $configuration->fields()\n ->where('object_type', $objectType)\n ->whereIn('crm_provider_id', $crmProviderIds)\n ->get();\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"on_screen":false,"role_description":"text"}]...
|
6168755295770182110
|
-4131649014932918923
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use Illuminate\Support\Collection;
use Illuminate\Support\LazyCollection;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Team;
use Jiminny\Services\Crm\Metadata\OptionMetadata;
class FieldRepository
{
/**
* @return Collection<Field>
*/
public function getAllFieldsForObjectType(Team $team, string $objectType): Collection
{
return $team->getCrmConfiguration()
->fields()
->where('object_type', '=', $objectType)
->get()
;
}
/**
* @param Team $team
* @param string[] $objectTypes
*
* @return Collection<Field>
*/
public function findAllSelectableByObjectTypes(Team $team, array $objectTypes): Collection
{
return $team->getCrmConfiguration()
->fields()
->whereIn('object_type', $objectTypes)
->where('is_selectable', true)
->orderBy('label')
->get()
;
}
public function idOrUuid(int|string $id): ?Field
{
/** @var ?Field */
return Field::idOrUuid($id);
}
/**
* @param OptionMetadata[] $options
*/
public function updatePicklistValues(Field $field, array $options): void
{
$field->values()->delete();
foreach ($options as $option) {
$field->values()->updateOrCreate([
'value' => $option->getId(),
'label' => $option->getLabel(),
], [
'sequence' => $option->getSequence(),
]);
}
}
public function updateOrCreateFieldValue(Field $field, array $data): FieldValue
{
/** @var FieldValue */
return $field->values()->updateOrCreate([
'value' => $data['value'],
], $data);
}
public function updateOrCreateOpportunityFieldData(
Field $field,
int $layoutEntityId,
int $opportunityId,
string $value,
): void {
$field->data()->updateOrCreate([
'crm_layout_entity_id' => $layoutEntityId,
'crm_field_id' => $field->getId(),
'object_type' => Field::OBJECT_OPPORTUNITY,
'object_id' => $opportunityId,
], ['value' => $value]);
}
public function findOneByCrmProviderId(Configuration $configuration, string $fieldId): ?Field
{
/** @var Field */
return $configuration->fields()->where('crm_provider_id', $fieldId)->first();
}
/**
* @param array<string,scalar> $data
*/
public function updateField(Field $field, array $data): void
{
$field->update($data);
}
public function upsertField(Configuration $configuration, array $data): Field
{
/** @var Field */
return $configuration->fields()->updateOrCreate(
[
'crm_provider_id' => $data['crm_provider_id'],
'object_type' => $data['object_type'],
],
$data,
);
}
public function findFieldByCrmIdAndObjectType(
Configuration $configuration,
string $fieldId,
string $objectType,
): ?Field {
/** @var Field */
return $configuration->fields()
->where('crm_provider_id', $fieldId)
->where('object_type', $objectType)
->first();
}
public function findAllFilterable(Team $team): LazyCollection
{
return $team
->getCrmConfiguration()
->fields()
->where('is_filterable', true)
->cursor();
}
public function findOneByCrmProviderIdAndObjectType(
Configuration $configuration,
string $fieldId,
string $objectType,
): ?Field {
/** @var ?Field */
return $configuration
->fields()
->where('crm_provider_id', $fieldId)
->where('object_type', $objectType)
->first();
}
public function findOneConfigurationFieldByProperties(Configuration $configuration, array $properties): ?Field
{
return $configuration->fields()
->where($properties)
->first();
}
public function getPicklistValues(Field $field, ?array $filterValues = []): Collection
{
$queryBuilder = $field->values()->orderBy('sequence');
if (! empty($filterValues)) {
$queryBuilder->whereIn('value', $filterValues);
}
return $queryBuilder->get();
}
public function updatePicklistValue(Field $field, array $picklistValueData): FieldValue
{
/** @var FieldValue */
return $this->updateOrCreateFieldValue($field, $picklistValueData);
}
public function deleteObsoleteField(Configuration $configuration, string $objectType, string $crmProviderId): void
{
$configuration->fields()
->where('object_type', $objectType)
->where('crm_provider_id', $crmProviderId)
->delete();
}
/**
* @param Configuration $configuration
* @param string $objectType
* @param string[] $crmProviderIds
*
* @return Collection<Field>
*/
public function identifyTeamCrmFields(
Configuration $configuration,
string $objectType,
array $crmProviderIds,
): Collection {
return $configuration->fields()
->where('object_type', $objectType)
->whereIn('crm_provider_id', $crmProviderIds)
->get();
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder...
|
65487
|
NULL
|
NULL
|
NULL
|
|
65487
|
2306
|
25
|
2026-05-21T07:41:54.865066+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349314865_m1.jpg...
|
PhpStorm
|
faVsco.js – FieldRepository.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use Illuminate\Support\Collection;
use Illuminate\Support\LazyCollection;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Team;
use Jiminny\Services\Crm\Metadata\OptionMetadata;
class FieldRepository
{
/**
* @return Collection<Field>
*/
public function getAllFieldsForObjectType(Team $team, string $objectType): Collection
{
return $team->getCrmConfiguration()
->fields()
->where('object_type', '=', $objectType)
->get()
;
}
/**
* @param Team $team
* @param string[] $objectTypes
*
* @return Collection<Field>
*/
public function findAllSelectableByObjectTypes(Team $team, array $objectTypes): Collection
{
return $team->getCrmConfiguration()
->fields()
->whereIn('object_type', $objectTypes)
->where('is_selectable', true)
->orderBy('label')
->get()
;
}
public function idOrUuid(int|string $id): ?Field
{
/** @var ?Field */
return Field::idOrUuid($id);
}
/**
* @param OptionMetadata[] $options
*/
public function updatePicklistValues(Field $field, array $options): void
{
$field->values()->delete();
foreach ($options as $option) {
$field->values()->updateOrCreate([
'value' => $option->getId(),
'label' => $option->getLabel(),
], [
'sequence' => $option->getSequence(),
]);
}
}
public function updateOrCreateFieldValue(Field $field, array $data): FieldValue
{
/** @var FieldValue */
return $field->values()->updateOrCreate([
'value' => $data['value'],
], $data);
}
public function updateOrCreateOpportunityFieldData(
Field $field,
int $layoutEntityId,
int $opportunityId,
string $value,
): void {
$field->data()->updateOrCreate([
'crm_layout_entity_id' => $layoutEntityId,
'crm_field_id' => $field->getId(),
'object_type' => Field::OBJECT_OPPORTUNITY,
'object_id' => $opportunityId,
], ['value' => $value]);
}
public function findOneByCrmProviderId(Configuration $configuration, string $fieldId): ?Field
{
/** @var Field */
return $configuration->fields()->where('crm_provider_id', $fieldId)->first();
}
/**
* @param array<string,scalar> $data
*/
public function updateField(Field $field, array $data): void
{
$field->update($data);
}
public function upsertField(Configuration $configuration, array $data): Field
{
/** @var Field */
return $configuration->fields()->updateOrCreate(
[
'crm_provider_id' => $data['crm_provider_id'],
'object_type' => $data['object_type'],
],
$data,
);
}
public function findFieldByCrmIdAndObjectType(
Configuration $configuration,
string $fieldId,
string $objectType,
): ?Field {
/** @var Field */
return $configuration->fields()
->where('crm_provider_id', $fieldId)
->where('object_type', $objectType)
->first();
}
public function findAllFilterable(Team $team): LazyCollection
{
return $team
->getCrmConfiguration()
->fields()
->where('is_filterable', true)
->cursor();
}
public function findOneByCrmProviderIdAndObjectType(
Configuration $configuration,
string $fieldId,
string $objectType,
): ?Field {
/** @var ?Field */
return $configuration
->fields()
->where('crm_provider_id', $fieldId)
->where('object_type', $objectType)
->first();
}
public function findOneConfigurationFieldByProperties(Configuration $configuration, array $properties): ?Field
{
return $configuration->fields()
->where($properties)
->first();
}
public function getPicklistValues(Field $field, ?array $filterValues = []): Collection
{
$queryBuilder = $field->values()->orderBy('sequence');
if (! empty($filterValues)) {
$queryBuilder->whereIn('value', $filterValues);
}
return $queryBuilder->get();
}
public function updatePicklistValue(Field $field, array $picklistValueData): FieldValue
{
/** @var FieldValue */
return $this->updateOrCreateFieldValue($field, $picklistValueData);
}
public function deleteObsoleteField(Configuration $configuration, string $objectType, string $crmProviderId): void
{
$configuration->fields()
->where('object_type', $objectType)
->where('crm_provider_id', $crmProviderId)
->delete();
}
/**
* @param Configuration $configuration
* @param string $objectType
* @param string[] $crmProviderIds
*
* @return Collection<Field>
*/
public function identifyTeamCrmFields(
Configuration $configuration,
string $objectType,
array $crmProviderIds,
): Collection {
return $configuration->fields()
->where('object_type', $objectType)
->whereIn('crm_provider_id', $crmProviderIds)
->get();
}
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Analyzing…","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\LazyCollection;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Crm\\Metadata\\OptionMetadata;\n\nclass FieldRepository\n{\n /**\n * @return Collection<Field>\n */\n public function getAllFieldsForObjectType(Team $team, string $objectType): Collection\n {\n return $team->getCrmConfiguration()\n ->fields()\n ->where('object_type', '=', $objectType)\n ->get()\n ;\n }\n\n /**\n * @param Team $team\n * @param string[] $objectTypes\n *\n * @return Collection<Field>\n */\n public function findAllSelectableByObjectTypes(Team $team, array $objectTypes): Collection\n {\n return $team->getCrmConfiguration()\n ->fields()\n ->whereIn('object_type', $objectTypes)\n ->where('is_selectable', true)\n ->orderBy('label')\n ->get()\n ;\n }\n\n public function idOrUuid(int|string $id): ?Field\n {\n /** @var ?Field */\n return Field::idOrUuid($id);\n }\n\n /**\n * @param OptionMetadata[] $options\n */\n public function updatePicklistValues(Field $field, array $options): void\n {\n $field->values()->delete();\n\n foreach ($options as $option) {\n $field->values()->updateOrCreate([\n 'value' => $option->getId(),\n 'label' => $option->getLabel(),\n ], [\n 'sequence' => $option->getSequence(),\n ]);\n }\n }\n\n public function updateOrCreateFieldValue(Field $field, array $data): FieldValue\n {\n /** @var FieldValue */\n return $field->values()->updateOrCreate([\n 'value' => $data['value'],\n ], $data);\n }\n\n public function updateOrCreateOpportunityFieldData(\n Field $field,\n int $layoutEntityId,\n int $opportunityId,\n string $value,\n ): void {\n $field->data()->updateOrCreate([\n 'crm_layout_entity_id' => $layoutEntityId,\n 'crm_field_id' => $field->getId(),\n 'object_type' => Field::OBJECT_OPPORTUNITY,\n 'object_id' => $opportunityId,\n ], ['value' => $value]);\n }\n\n public function findOneByCrmProviderId(Configuration $configuration, string $fieldId): ?Field\n {\n /** @var Field */\n return $configuration->fields()->where('crm_provider_id', $fieldId)->first();\n }\n\n /**\n * @param array<string,scalar> $data\n */\n public function updateField(Field $field, array $data): void\n {\n $field->update($data);\n }\n\n public function upsertField(Configuration $configuration, array $data): Field\n {\n /** @var Field */\n return $configuration->fields()->updateOrCreate(\n [\n 'crm_provider_id' => $data['crm_provider_id'],\n 'object_type' => $data['object_type'],\n ],\n $data,\n );\n }\n\n public function findFieldByCrmIdAndObjectType(\n Configuration $configuration,\n string $fieldId,\n string $objectType,\n ): ?Field {\n /** @var Field */\n return $configuration->fields()\n ->where('crm_provider_id', $fieldId)\n ->where('object_type', $objectType)\n ->first();\n }\n\n public function findAllFilterable(Team $team): LazyCollection\n {\n return $team\n ->getCrmConfiguration()\n ->fields()\n ->where('is_filterable', true)\n ->cursor();\n }\n\n public function findOneByCrmProviderIdAndObjectType(\n Configuration $configuration,\n string $fieldId,\n string $objectType,\n ): ?Field {\n /** @var ?Field */\n return $configuration\n ->fields()\n ->where('crm_provider_id', $fieldId)\n ->where('object_type', $objectType)\n ->first();\n }\n\n public function findOneConfigurationFieldByProperties(Configuration $configuration, array $properties): ?Field\n {\n return $configuration->fields()\n ->where($properties)\n ->first();\n }\n\n public function getPicklistValues(Field $field, ?array $filterValues = []): Collection\n {\n $queryBuilder = $field->values()->orderBy('sequence');\n\n if (! empty($filterValues)) {\n $queryBuilder->whereIn('value', $filterValues);\n }\n\n return $queryBuilder->get();\n }\n\n public function updatePicklistValue(Field $field, array $picklistValueData): FieldValue\n {\n /** @var FieldValue */\n return $this->updateOrCreateFieldValue($field, $picklistValueData);\n }\n\n public function deleteObsoleteField(Configuration $configuration, string $objectType, string $crmProviderId): void\n {\n $configuration->fields()\n ->where('object_type', $objectType)\n ->where('crm_provider_id', $crmProviderId)\n ->delete();\n }\n\n /**\n * @param Configuration $configuration\n * @param string $objectType\n * @param string[] $crmProviderIds\n *\n * @return Collection<Field>\n */\n public function identifyTeamCrmFields(\n Configuration $configuration,\n string $objectType,\n array $crmProviderIds,\n ): Collection {\n return $configuration->fields()\n ->where('object_type', $objectType)\n ->whereIn('crm_provider_id', $crmProviderIds)\n ->get();\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\LazyCollection;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Crm\\Metadata\\OptionMetadata;\n\nclass FieldRepository\n{\n /**\n * @return Collection<Field>\n */\n public function getAllFieldsForObjectType(Team $team, string $objectType): Collection\n {\n return $team->getCrmConfiguration()\n ->fields()\n ->where('object_type', '=', $objectType)\n ->get()\n ;\n }\n\n /**\n * @param Team $team\n * @param string[] $objectTypes\n *\n * @return Collection<Field>\n */\n public function findAllSelectableByObjectTypes(Team $team, array $objectTypes): Collection\n {\n return $team->getCrmConfiguration()\n ->fields()\n ->whereIn('object_type', $objectTypes)\n ->where('is_selectable', true)\n ->orderBy('label')\n ->get()\n ;\n }\n\n public function idOrUuid(int|string $id): ?Field\n {\n /** @var ?Field */\n return Field::idOrUuid($id);\n }\n\n /**\n * @param OptionMetadata[] $options\n */\n public function updatePicklistValues(Field $field, array $options): void\n {\n $field->values()->delete();\n\n foreach ($options as $option) {\n $field->values()->updateOrCreate([\n 'value' => $option->getId(),\n 'label' => $option->getLabel(),\n ], [\n 'sequence' => $option->getSequence(),\n ]);\n }\n }\n\n public function updateOrCreateFieldValue(Field $field, array $data): FieldValue\n {\n /** @var FieldValue */\n return $field->values()->updateOrCreate([\n 'value' => $data['value'],\n ], $data);\n }\n\n public function updateOrCreateOpportunityFieldData(\n Field $field,\n int $layoutEntityId,\n int $opportunityId,\n string $value,\n ): void {\n $field->data()->updateOrCreate([\n 'crm_layout_entity_id' => $layoutEntityId,\n 'crm_field_id' => $field->getId(),\n 'object_type' => Field::OBJECT_OPPORTUNITY,\n 'object_id' => $opportunityId,\n ], ['value' => $value]);\n }\n\n public function findOneByCrmProviderId(Configuration $configuration, string $fieldId): ?Field\n {\n /** @var Field */\n return $configuration->fields()->where('crm_provider_id', $fieldId)->first();\n }\n\n /**\n * @param array<string,scalar> $data\n */\n public function updateField(Field $field, array $data): void\n {\n $field->update($data);\n }\n\n public function upsertField(Configuration $configuration, array $data): Field\n {\n /** @var Field */\n return $configuration->fields()->updateOrCreate(\n [\n 'crm_provider_id' => $data['crm_provider_id'],\n 'object_type' => $data['object_type'],\n ],\n $data,\n );\n }\n\n public function findFieldByCrmIdAndObjectType(\n Configuration $configuration,\n string $fieldId,\n string $objectType,\n ): ?Field {\n /** @var Field */\n return $configuration->fields()\n ->where('crm_provider_id', $fieldId)\n ->where('object_type', $objectType)\n ->first();\n }\n\n public function findAllFilterable(Team $team): LazyCollection\n {\n return $team\n ->getCrmConfiguration()\n ->fields()\n ->where('is_filterable', true)\n ->cursor();\n }\n\n public function findOneByCrmProviderIdAndObjectType(\n Configuration $configuration,\n string $fieldId,\n string $objectType,\n ): ?Field {\n /** @var ?Field */\n return $configuration\n ->fields()\n ->where('crm_provider_id', $fieldId)\n ->where('object_type', $objectType)\n ->first();\n }\n\n public function findOneConfigurationFieldByProperties(Configuration $configuration, array $properties): ?Field\n {\n return $configuration->fields()\n ->where($properties)\n ->first();\n }\n\n public function getPicklistValues(Field $field, ?array $filterValues = []): Collection\n {\n $queryBuilder = $field->values()->orderBy('sequence');\n\n if (! empty($filterValues)) {\n $queryBuilder->whereIn('value', $filterValues);\n }\n\n return $queryBuilder->get();\n }\n\n public function updatePicklistValue(Field $field, array $picklistValueData): FieldValue\n {\n /** @var FieldValue */\n return $this->updateOrCreateFieldValue($field, $picklistValueData);\n }\n\n public function deleteObsoleteField(Configuration $configuration, string $objectType, string $crmProviderId): void\n {\n $configuration->fields()\n ->where('object_type', $objectType)\n ->where('crm_provider_id', $crmProviderId)\n ->delete();\n }\n\n /**\n * @param Configuration $configuration\n * @param string $objectType\n * @param string[] $crmProviderIds\n *\n * @return Collection<Field>\n */\n public function identifyTeamCrmFields(\n Configuration $configuration,\n string $objectType,\n array $crmProviderIds,\n ): Collection {\n return $configuration->fields()\n ->where('object_type', $objectType)\n ->whereIn('crm_provider_id', $crmProviderIds)\n ->get();\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false}]...
|
-915585642258243567
|
-2978587871736909979
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use Illuminate\Support\Collection;
use Illuminate\Support\LazyCollection;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Team;
use Jiminny\Services\Crm\Metadata\OptionMetadata;
class FieldRepository
{
/**
* @return Collection<Field>
*/
public function getAllFieldsForObjectType(Team $team, string $objectType): Collection
{
return $team->getCrmConfiguration()
->fields()
->where('object_type', '=', $objectType)
->get()
;
}
/**
* @param Team $team
* @param string[] $objectTypes
*
* @return Collection<Field>
*/
public function findAllSelectableByObjectTypes(Team $team, array $objectTypes): Collection
{
return $team->getCrmConfiguration()
->fields()
->whereIn('object_type', $objectTypes)
->where('is_selectable', true)
->orderBy('label')
->get()
;
}
public function idOrUuid(int|string $id): ?Field
{
/** @var ?Field */
return Field::idOrUuid($id);
}
/**
* @param OptionMetadata[] $options
*/
public function updatePicklistValues(Field $field, array $options): void
{
$field->values()->delete();
foreach ($options as $option) {
$field->values()->updateOrCreate([
'value' => $option->getId(),
'label' => $option->getLabel(),
], [
'sequence' => $option->getSequence(),
]);
}
}
public function updateOrCreateFieldValue(Field $field, array $data): FieldValue
{
/** @var FieldValue */
return $field->values()->updateOrCreate([
'value' => $data['value'],
], $data);
}
public function updateOrCreateOpportunityFieldData(
Field $field,
int $layoutEntityId,
int $opportunityId,
string $value,
): void {
$field->data()->updateOrCreate([
'crm_layout_entity_id' => $layoutEntityId,
'crm_field_id' => $field->getId(),
'object_type' => Field::OBJECT_OPPORTUNITY,
'object_id' => $opportunityId,
], ['value' => $value]);
}
public function findOneByCrmProviderId(Configuration $configuration, string $fieldId): ?Field
{
/** @var Field */
return $configuration->fields()->where('crm_provider_id', $fieldId)->first();
}
/**
* @param array<string,scalar> $data
*/
public function updateField(Field $field, array $data): void
{
$field->update($data);
}
public function upsertField(Configuration $configuration, array $data): Field
{
/** @var Field */
return $configuration->fields()->updateOrCreate(
[
'crm_provider_id' => $data['crm_provider_id'],
'object_type' => $data['object_type'],
],
$data,
);
}
public function findFieldByCrmIdAndObjectType(
Configuration $configuration,
string $fieldId,
string $objectType,
): ?Field {
/** @var Field */
return $configuration->fields()
->where('crm_provider_id', $fieldId)
->where('object_type', $objectType)
->first();
}
public function findAllFilterable(Team $team): LazyCollection
{
return $team
->getCrmConfiguration()
->fields()
->where('is_filterable', true)
->cursor();
}
public function findOneByCrmProviderIdAndObjectType(
Configuration $configuration,
string $fieldId,
string $objectType,
): ?Field {
/** @var ?Field */
return $configuration
->fields()
->where('crm_provider_id', $fieldId)
->where('object_type', $objectType)
->first();
}
public function findOneConfigurationFieldByProperties(Configuration $configuration, array $properties): ?Field
{
return $configuration->fields()
->where($properties)
->first();
}
public function getPicklistValues(Field $field, ?array $filterValues = []): Collection
{
$queryBuilder = $field->values()->orderBy('sequence');
if (! empty($filterValues)) {
$queryBuilder->whereIn('value', $filterValues);
}
return $queryBuilder->get();
}
public function updatePicklistValue(Field $field, array $picklistValueData): FieldValue
{
/** @var FieldValue */
return $this->updateOrCreateFieldValue($field, $picklistValueData);
}
public function deleteObsoleteField(Configuration $configuration, string $objectType, string $crmProviderId): void
{
$configuration->fields()
->where('object_type', $objectType)
->where('crm_provider_id', $crmProviderId)
->delete();
}
/**
* @param Configuration $configuration
* @param string $objectType
* @param string[] $crmProviderIds
*
* @return Collection<Field>
*/
public function identifyTeamCrmFields(
Configuration $configuration,
string $objectType,
array $crmProviderIds,
): Collection {
return $configuration->fields()
->where('object_type', $objectType)
->whereIn('crm_provider_id', $crmProviderIds)
->get();
}
}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65486
|
2306
|
24
|
2026-05-21T07:41:53.210434+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349313210_m1.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4235983745889776938
|
-8204421443435123770
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
SlackFileEditViewGoHistoryWindowHelpscreelDOCKER0 81DEV (-zsh)₴2APP (-zsh)whisper_init_state:whisper_init_state:kv padsize=2.36 MBcompute buffer (conv)whisper_init_state: compute buffer (encode) =whisper_init_state: compute buffer (cross)=whisper_init_state:compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocatingwhisper_backend_init_gpu: device 0: Metal (type:1)whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)whisper_backend_init_gpu: using Metal backendggml_metal_init: allocatingggml_metal_init: found device: Apple M1ggml_metal_init: picking default device: Apple M1ggml_metal_init:use fusion= trueggml_metal_init:use concurrency= trueggml_metal_init: use graph optimizetruewhisper_backend_init: using BLAS backendwhisper_init_state: kv self size3.15 MBwhisper_init_state: kv cross size =9.44 MBwhisper_init_state: kv padsize =2.36 MBwhisper_init_state: compute buffer (conv)whisper_init_state: compute buffer (encode) =whisper_init_state: compute buffer (cross)=whisper_init_state: compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocatingwhisper_backend_init_gpu:device 0: Metal (type: 1)whisper_backend_init_gpu: found GPUdevice 0: Metal (type: 1, cnt: 0)whisper_backend_init_gpu: using Metal backendggml_metal_init: allocatingggml_metal_init: found device: Apple M1ggml_metal_init: picking default device: Apple M1ggml_metal_init:use fusion= trueggml_metal_init:use concurrencytrueggml_metal_init:use graph optimizetruewhisper_backend_init: using BLAS backendwhisper_init_state: kv self size3.15 MBwhisper_init_state: kv cross size =9.44 MBwhisper_init_state: kv padsize=2.36 MBwhisper_init_state: compute buffer (conv)whisper_init_state: compute buffer (encode) =whisper_init_state: compute buffer (cross)whisper_init_state: compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocating2026-05-21T10:13:41.913005ZINFO screenpipe_audio::audio_manager::manager: reconciliatior2026-05-21710:15:15.5768762INFO screenpipe_engine::event_driven_capture: content dedup:j Support Daily - in 4h 45 m100% С8• Thu 21 May 10:15:32•••EDQHomeDMsActivityFilesLater•••More+→Describe what you are looking forJiminny ...ThreadsC9 Unreadsà platform-inner-teamGalya Dimitrova, Nikolay Yankov, and youa ThreadsHuddles• Drafts & sentDirectories01External connections* Starred& jiminny-x-integrati...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# curiosity_lab# engineering# general# happy_birthday# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# supportLukas Kovalik 31 minutes agoдобро утро, тази страница не трябва ли да япоказваме само ако няма reportsCleanShot 2026-05-21 at [EMAIL] your questions into ongoing insightsGalya Dimitrova 23 minutes agoДа, би трябвалоLukas Kovalik 22 minutes agoче сега ми го показва и ако имам reportLukas Kovalik 21 minutes agoна neptuneNewNikolay Yankov 6 minutes agoвсичко е наредReply...Also send to à platform-inner-team+AaYou're up to date...
|
65484
|
NULL
|
NULL
|
NULL
|
|
65488
|
2307
|
19
|
2026-05-21T07:41:53.210431+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349313210_m2.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4235983745889776938
|
-8204421443435123770
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
slackFV [EMAIL]=.phounit.result.cacheE .prettierignore= windsurtrulesphpde neloer.onophpide heloer_models.ohophp artisanM'CLAUDE.mdcomooser.isoncomooser.lockdependency-checker.json8 dev ison= ids tytl=infection.ison.distMLINSTAlI.mdMLINTERNAI WERHOOK SFTUP mdEjiminny_storageMiliconsos mdllM Makefile1рackace-lock. sonE phpstan.neon.dist= phostan-baseline.neon<> phpunit.xmlTe raw sal query.saM+ README.mdsô sonar-proiect propertiesE test.ov‹> Untitled Diaaram.xmliusvetur.confio.isM+ WEBHOOK FILTERING_IMPLEMENTATION.mo>1h External Librariesv =° Scratches and Consolesv batabase Consolesv AEU# console (EUlI DEAL RISKS (SU1A DITEUlA EU (EU]v Ajiminny@localhostA console (jiminny@localhost]# Di [liminny@localhostlA HS local [iiminny@localhostlA SF ['iiminny@localhost]& zoho dev [iiminny@localhost]V & PRODA console [PROD]& console 1 [PROD1LDIIPRODCActivityController.ong© ConvertLeadActivities.php= laravel.log4 SF jiminny@localhost]4 HS_local [jiminny@localhost]& console (PROD] X# console [euyLeadkepository.ong© PurgeLookupCache.php© SyncPlanhat.phpo synerorlannatpnpA console [STAGING]AcuivityLeadConverted.php© UserAutomatedreporscontroller.phpx© PlaybackController.php)Inteqrationapp/service.onoC) LeadConverted.ono570571C) CreateCommentedEvent.php(C) CreateSmsSentEvent.phpC) PlanhatActivityListener.php© AskAnythingPromptService.php572(C) AutomatedReportsRepositorv.php© AutomatedReportsCommand.phpphp api_v2.phpC) RequestGenerateReportJob.php573574© AutomatedReportResult.php(C) AutomatedReport.oho575use Jiminny \Services \Kiosk \AutomatedReports \ReportSortDirection;A1422 ^ v 576use Jiminny \Services\PlanhatService;use ectumtnace hutp kequestuse Inrowable,class UserAutomatedReportsController extends Controllenpublic const int RESULTS PER_ PAGE = 25:public const string SORT COLUMN = 'sort column':public const strina SORT DIRECTION = "sort direction':public function constructprivate readonly AutomatedReportsRepository $automatedReportsRepository.private readonly AutomatedRenortsService SautomatedRenortsServicelorivate readoni.v AniResponseService samiResponseServi.ce.orivate readoni.v Resnonse Sresnonse.private readonly PlanhatService $planhatService1...poST lanilv1lautomated-renorts/interest 1usadepublic function trackInterest(Request $request): JsonResponse(...}* Othnows ApplicationException58(09 >GET /api/v1/automated-reportspublic function list(Request Srequest): JsonResponse(...}125 0)DELETE/api/vl/automated-reports/kuuidpublic function delete(Request Srequest. string Suuid): JsonResponsef...} -609610--611612613616Tx: AutovSo jiminny vCONCAT(u.id, CASE WHEN U.id = t.owner_id THEN' (owner)' ELSE'' END) AS USEr_i041 A1 A40 V65 ^sa.*t.owner_id FROM social_accounts saNoun usens u on u.ide sa.sociablle 1diJOIN teams t 1..n<->1: on t.id = u.team_idWHERE u.team_id = 581 and sa.provider = 'salesforce';SELECT * FROM automated_report_results order by id desc;select * from features;select * from team_features where feature_id = 40;select * from teams where id = 556:select * trom automated reports:where id = 54: # 4fdd41f6-dcf0-30d0-b339-7345381b6044|"pat", "podcast"SELECT * FROM automated report results WHERE uuid to bin( '822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;select * from automated_report_results order by id desc;SELECT * FROMWHERE id = 1919:select * fromautomated report results WHERE report id = 54:select * from opportunities where id = 7594349:SELECT * FROM teams WHERE name LIKE '%Lesg': # 711. 692. [EMAIL] * from playbooks where team_id = 711; # event 226147SELEd * FROM Dlavbook catedonies WHERE Dlavbook 1d = 55151SELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event':SELECT * SROM eom fields WHEREI1d = 2261471SELECT * FROM crm_field_values WHERE crm_field_id = 226147;SELECT * FROM crm_configurations WHERE id = 692;SELSCTCONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '• END) AS user_id,v.emailsa.*,t.owner id FROM social accounts saJOIN users u on v.id = sa.sociable idJOIN teams t 1..n<->1: on t.id = u.team idWHERE U.team_id = 711 and sa.provider = 'salesforce";SELECT * FROM crm profiles cp JOIN users u 1..n<->1: on u.id = co.user id WHERE u.team_id = 711:select * from leadsselect * from calendarsSELECTS 0 hllsupoont Dally • In 4h 40m100% 52• Inu z1 May 10.10.34AskJiminnyReportActivityServiceTestvCascadePlaybook Categorie+0 ..connected. How isi. Can we vali eoneactivity tyee nith orit cabest aeeiewmane o, W dati anwsyggesinsingrow hohow to distinguishThoughts68 Fast Context How are playbook_categories populated and synced from crm_fields / crm_field_values... in 4.14s >Explored 4 files and searched 5 queriesRead ImportActivitvTypes.php #L95-104Searched olavbook cateaories in databaselmiarations (4) >egories|playbook_categories.*create in database/migrations (0)searched playoook_categor in database/migrations (<)Searched activity type in database/migrations (4)SurtingAsk anvthina (*4L)@ Codo Caudo Onue 17 ModiumNN Windeurf Toame 504.60...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65485
|
2307
|
18
|
2026-05-21T07:41:35.862833+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349295862_m2.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php
CleanDuplicateFieldDataCommand.php
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php
SetupActivityTypeForFollowUp.php
SetupCloseCrm.php
SetupCopperCrm.php
SetupCrmCommand.php
SetupLayouts.php
SyncAccount.php
SyncContact.php
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class
SyncProfileMetadata.php, class
SyncTeamMetadata.php, class
UpdateOpportunitySpecifications.php, class
DealInsights, folder
Dev, folder
Dialers, folder
DTOs
Elasticsearch
EngagementStats
GeckoExport
Livestream
Mailboxes, folder
Migrate
PlaybackThemes
Playbooks
Playlists, folder
Postmark, folder
ProphetAi, folder
Reports, folder
AutomatedReportsCommand.php
AutomatedReportsRetentionPolicyCommand.php
AutomatedReportsSendCommand.php
CreateMockAskJiminnyReportResultCommand.php
DeleteReportCommand.php
GenerateMarketingReport.php, class
Team.php, class
Usage.php, class
Slack
Teams
Tracks
Transcription
Twilio
Users
Vocabulary
Zoom
Command.php, class
CreateDatabaseUsers.php, class...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"bounds":{"left":0.15990691,"top":0.007980846,"width":0.2662899,"height":0.98324025},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"bounds":{"left":0.44547874,"top":0.09736632,"width":0.29022607,"height":0.8818835},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackPage","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlist","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Prophet","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProsperWorks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Queue","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Router","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Saml2","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SCIM","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Seeder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sentry","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Serializer","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Settings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sidekick","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Slack","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TimeMemoryMapper","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Transcription","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TranscriptionSummary, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Twilio, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uploader, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UrlGenerator, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Utility, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uuid, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Waveform, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Webhooks, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Workflow, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Configuration","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Console","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Commands, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activities","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Analytics","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Calendars","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Crm","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Hubspot","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IntegrationApp","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Traits","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AddLayoutEntities.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutologDelayedCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BackfillOpportunityUserFromAccountCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornCommandAbstract.php, abstract class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornPingCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSearchCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSessionCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CheckActivityLoggableCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CleanDuplicateFieldDataCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FullSyncOpportunityCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LogActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ManageSyncStrategyCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchCrmObjectsCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchOpportunityActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MigrateProvider.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProcessHubspotObjectsSyncBatches.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PurgeDeletedOpportunitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ResetGovernorLimits.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SendNotLogged.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupActivityTypeForFollowUp.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCloseCrm.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCopperCrm.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCrmCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupLayouts.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncAccount.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncContact.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncFieldMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotActiveDeals.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncLead.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunitiesMissingFieldDataCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunity.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncProfileMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncTeamMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UpdateOpportunitySpecifications.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dev, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dialers, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DTOs","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Elasticsearch","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"EngagementStats","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GeckoExport","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Livestream","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Mailboxes, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Migrate","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackThemes","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playbooks","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlists, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Postmark, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Reports, folder","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutomatedReportsCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutomatedReportsRetentionPolicyCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutomatedReportsSendCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CreateMockAskJiminnyReportResultCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DeleteReportCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GenerateMarketingReport.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Team.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Usage.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Slack","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Teams","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Tracks","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Transcription","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Twilio","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Users","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Vocabulary","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Zoom","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Command.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CreateDatabaseUsers.php, class","depth":10,"on_screen":false,"role_description":"text"}]...
|
-4969646139324939661
|
-6409495119138910956
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php
CleanDuplicateFieldDataCommand.php
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php
SetupActivityTypeForFollowUp.php
SetupCloseCrm.php
SetupCopperCrm.php
SetupCrmCommand.php
SetupLayouts.php
SyncAccount.php
SyncContact.php
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class
SyncProfileMetadata.php, class
SyncTeamMetadata.php, class
UpdateOpportunitySpecifications.php, class
DealInsights, folder
Dev, folder
Dialers, folder
DTOs
Elasticsearch
EngagementStats
GeckoExport
Livestream
Mailboxes, folder
Migrate
PlaybackThemes
Playbooks
Playlists, folder
Postmark, folder
ProphetAi, folder
Reports, folder
AutomatedReportsCommand.php
AutomatedReportsRetentionPolicyCommand.php
AutomatedReportsSendCommand.php
CreateMockAskJiminnyReportResultCommand.php
DeleteReportCommand.php
GenerateMarketingReport.php, class
Team.php, class
Usage.php, class
Slack
Teams
Tracks
Transcription
Twilio
Users
Vocabulary
Zoom
Command.php, class
CreateDatabaseUsers.php, class...
|
65483
|
NULL
|
NULL
|
NULL
|
|
65484
|
2306
|
23
|
2026-05-21T07:41:35.787977+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349295787_m1.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php
CleanDuplicateFieldDataCommand.php
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php
SetupActivityTypeForFollowUp.php
SetupCloseCrm.php
SetupCopperCrm.php
SetupCrmCommand.php
SetupLayouts.php
SyncAccount.php
SyncContact.php
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class
SyncProfileMetadata.php, class...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackPage","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlist","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Prophet","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProsperWorks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Queue","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Router","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Saml2","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SCIM","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Seeder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sentry","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Serializer","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Settings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sidekick","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Slack","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TimeMemoryMapper","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Transcription","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TranscriptionSummary, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Twilio, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uploader, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UrlGenerator, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Utility, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uuid, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Waveform, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Webhooks, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Workflow, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Configuration","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Console","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Commands, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activities","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Analytics","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Calendars","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Crm","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Hubspot","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IntegrationApp","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Traits","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AddLayoutEntities.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutologDelayedCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BackfillOpportunityUserFromAccountCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornCommandAbstract.php, abstract class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornPingCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSearchCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSessionCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CheckActivityLoggableCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CleanDuplicateFieldDataCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FullSyncOpportunityCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LogActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ManageSyncStrategyCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchCrmObjectsCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchOpportunityActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MigrateProvider.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProcessHubspotObjectsSyncBatches.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PurgeDeletedOpportunitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ResetGovernorLimits.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SendNotLogged.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupActivityTypeForFollowUp.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCloseCrm.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCopperCrm.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCrmCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupLayouts.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncAccount.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncContact.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncFieldMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotActiveDeals.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncLead.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunitiesMissingFieldDataCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunity.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncProfileMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"}]...
|
8460510130546683954
|
-6412872269032321772
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php
CleanDuplicateFieldDataCommand.php
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php
SetupActivityTypeForFollowUp.php
SetupCloseCrm.php
SetupCopperCrm.php
SetupCrmCommand.php
SetupLayouts.php
SyncAccount.php
SyncContact.php
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class
SyncProfileMetadata.php, class...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65482
|
2306
|
22
|
2026-05-21T07:41:05.439497+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349265439_m1.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker, folder","depth":9,"on_screen":false,"role_description":"text"}]...
|
-3183846560324211647
|
-8717730116901200620
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder...
|
65480
|
NULL
|
NULL
|
NULL
|
|
65483
|
2307
|
17
|
2026-05-21T07:41:05.419501+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349265419_m2.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"bounds":{"left":0.19780585,"top":0.007980846,"width":0.25897607,"height":0.98324025},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"bounds":{"left":0.44547874,"top":0.09736632,"width":0.29022607,"height":0.8818835},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"}]...
|
5817002037882781695
|
-8717730082541445868
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65480
|
2306
|
21
|
2026-05-21T07:41:04.712459+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349264712_m1.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie, folder","depth":9,"on_screen":false,"role_description":"text"}]...
|
-1566601011576084229
|
-8717730117438055148
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65481
|
2307
|
16
|
2026-05-21T07:41:04.693708+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349264693_m2.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"bounds":{"left":0.19780585,"top":0.007980846,"width":0.25897607,"height":0.98324025},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"bounds":{"left":0.44547874,"top":0.09736632,"width":0.29022607,"height":0.8818835},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"}]...
|
7089743142087417934
|
-8717591578436149996
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring...
|
65479
|
NULL
|
NULL
|
NULL
|
|
65478
|
2306
|
20
|
2026-05-21T07:41:03.176791+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349263176_m1.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":9,"on_screen":false,"role_description":"text"}]...
|
-2857235976388263470
|
-8717730116901184236
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot...
|
65476
|
NULL
|
NULL
|
NULL
|
|
65479
|
2307
|
15
|
2026-05-21T07:41:03.176790+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349263176_m2.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"bounds":{"left":0.15990691,"top":0.0071827616,"width":0.2662899,"height":0.98324025},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"bounds":{"left":0.44547874,"top":0.09736632,"width":0.29022607,"height":0.8818835},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"}]...
|
5572889657176821371
|
-6411746335839417068
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65476
|
2306
|
19
|
2026-05-21T07:41:02.400573+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349262400_m1.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackPage","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlist","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Prophet","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProsperWorks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Queue","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Router","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Saml2","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SCIM","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Seeder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sentry","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Serializer","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Settings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sidekick","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Slack","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TimeMemoryMapper","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Transcription","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TranscriptionSummary, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Twilio, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uploader, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UrlGenerator, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Utility, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uuid, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Waveform, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Webhooks, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Workflow, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Configuration","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Console","depth":8,"on_screen":false,"role_description":"text"}]...
|
-8555780578124376235
|
-8142395263430931180
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65477
|
2307
|
14
|
2026-05-21T07:41:02.384353+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349262384_m2.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"bounds":{"left":0.15990691,"top":0.0071827616,"width":0.2662899,"height":0.98324025},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"bounds":{"left":0.44547874,"top":0.09736632,"width":0.29022607,"height":0.8818835},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"}]...
|
5310908547720353950
|
-8717730081467720428
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk...
|
65475
|
NULL
|
NULL
|
NULL
|
|
65474
|
2306
|
18
|
2026-05-21T07:41:00.437323+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349260437_m1.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackPage","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlist","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Prophet","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProsperWorks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Queue","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Router","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Saml2","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SCIM","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Seeder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sentry","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Serializer","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Settings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sidekick","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Slack","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TimeMemoryMapper","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Transcription","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TranscriptionSummary, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Twilio, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uploader, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UrlGenerator, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Utility, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uuid, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Waveform, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Webhooks, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Workflow, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Configuration","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Console","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Commands, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activities","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Analytics","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Calendars","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Crm","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Hubspot","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IntegrationApp","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Traits","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AddLayoutEntities.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutologDelayedCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BackfillOpportunityUserFromAccountCommand.php, class","depth":11,"on_screen":false,"role_description":"text"}]...
|
-7862546749473264626
|
-8142254525942592236
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class...
|
65473
|
NULL
|
NULL
|
NULL
|
|
65475
|
2307
|
13
|
2026-05-21T07:41:00.421514+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349260421_m2.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"bounds":{"left":0.15990691,"top":0.0,"width":0.2662899,"height":0.98324025},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"bounds":{"left":0.44547874,"top":0.09736632,"width":0.29022607,"height":0.8818835},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"on_screen":false,"role_description":"text"}]...
|
-661905251928204165
|
-8717730116901184236
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65473
|
2306
|
17
|
2026-05-21T07:40:59.611096+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349259611_m1.jpg...
|
PhpStorm
|
faVsco.js – SyncCrmFieldsTrait.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php
CleanDuplicateFieldDataCommand.php
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php
SetupActivityTypeForFollowUp.php
SetupCloseCrm.php
SetupCopperCrm.php
SetupCrmCommand.php
SetupLayouts.php
SyncAccount.php
SyncContact.php
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\IntegrationApp\\ServiceTraits;\n\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\Config\\IntegrationAppProviders;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmField;\nuse Jiminny\\Services\\Crm\\IntegrationApp\\DTO\\CrmFieldDefinitionsManager;\nuse RuntimeException;\n\ntrait SyncCrmFieldsTrait\n{\n public function syncFields(): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {\n $fieldManager = new CrmFieldDefinitionsManager();\n\n foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));\n $this->syncObjectTypeFields($fieldType, $crmFields);\n }\n }\n\n return;\n }\n\n foreach ($this->getFieldTypes() as $object) {\n $this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));\n $fields = $this->client->getObjectFields($object);\n foreach ($fields as $fieldDto) {\n $field = $this->importCrmField($fieldDto);\n if ($field->isPicklist()) {\n $this->importPicklistValues($field);\n }\n }\n }\n }\n\n private function syncObjectTypeFields(string $fieldType, array $crmFields): void\n {\n foreach ($crmFields as $crmField) {\n $this->syncCrmField($fieldType, $crmField);\n }\n }\n\n private function syncCrmField(string $fieldType, array $crmField): void\n {\n $fieldData = [\n 'crm_provider_id' => $crmField['crm_id'],\n 'object_type' => $fieldType,\n 'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),\n 'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),\n 'type' => $crmField['type'],\n 'is_selectable' => $crmField['is_selectable'] ?? true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n $field = $fieldRepository->upsertField($this->config, $fieldData);\n\n $this->logger->info('[integration-app] Synced field', [\n 'field' => $field->getLabel(),\n 'team_id' => $this->team?->getId(),\n ]);\n\n $field->refresh();\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n\n private function importCrmField(CrmField $crmField): Field\n {\n $fieldData = [\n 'crm_provider_id' => $crmField->getExternalId(),\n 'object_type' => $crmField->getObjectType(),\n 'label' => $crmField->getLabel()\n ? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)\n : '',\n 'description' => $crmField->getDescription()\n ? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)\n : null,\n 'type' => $crmField->getType(),\n 'is_selectable' => true,\n ];\n\n /** @var FieldRepository $fieldRepository */\n $fieldRepository = app(FieldRepository::class);\n\n return $fieldRepository->upsertField($this->config, $fieldData);\n }\n\n /**\n * Works together with SyncTeamMetadata command if new field is added and needs to be synced.\n */\n public function syncField(Field $field): void\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldId = $field->getCrmProviderId();\n $fieldType = $field->getObjectType();\n\n $fieldManager = new CrmFieldDefinitionsManager();\n $fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);\n\n $this->syncCrmField($fieldType, $fieldDefinition);\n } else {\n $fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());\n $this->importCrmField($fieldDto);\n }\n }\n\n public function importPicklistValues(Field $field): array\n {\n if (! $this->editionConfig->supportsCrmFieldsSync()) {\n $fieldManager = new CrmFieldDefinitionsManager();\n $picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());\n } else {\n if (! $field->isPicklist()) {\n return [];\n }\n\n $picklistValues = $this->client->getPicklistValues(\n $field->getObjectType(),\n $field->getCrmProviderId(),\n );\n }\n\n if (empty($picklistValues)) {\n return [];\n }\n\n return $this->importOptions($field, $picklistValues);\n }\n\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $sequence = 0;\n $fieldRepo = app(FieldRepository::class);\n\n foreach ($options as $option) {\n $value = [\n 'value' => $option,\n 'label' => $option,\n 'sequence' => $sequence++,\n ];\n\n $fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);\n }\n\n return $fieldValues;\n }\n\n protected function getFieldTypes(): array\n {\n return match ($this->config->getEdition()) {\n IntegrationAppProviders::MS_DYNAMICS => [\n Field::OBJECT_OPPORTUNITY,\n Field::OBJECT_LEAD,\n Field::OBJECT_CONTACT,\n Field::OBJECT_ACCOUNT,\n Field::OBJECT_TASK,\n ],\n default => throw new RuntimeException('Unsupported CRM provider')\n };\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Acl","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activity","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Dtos","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Events","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackPage","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Playlist","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Prophet","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProsperWorks","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Queue","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Router","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Saml2","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SCIM","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Seeder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sentry","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Serializer","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Settings","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Sidekick","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Slack","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TimeMemoryMapper","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Transcription","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"TranscriptionSummary, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Twilio, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uploader, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"UrlGenerator, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Utility, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Uuid, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Waveform, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Webhooks, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Workflow, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Configuration","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Console","depth":8,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Commands, folder","depth":9,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Activities","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Analytics","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Calendars","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Crm","depth":10,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Hubspot","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IntegrationApp","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Traits","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AddLayoutEntities.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"AutologDelayedCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BackfillOpportunityUserFromAccountCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornCommandAbstract.php, abstract class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornPingCommand.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSearchCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSessionCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CheckActivityLoggableCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"CleanDuplicateFieldDataCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"FullSyncOpportunityCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"LogActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ManageSyncStrategyCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchCrmObjectsCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MatchOpportunityActivitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"MigrateProvider.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ProcessHubspotObjectsSyncBatches.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PurgeDeletedOpportunitiesCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ResetGovernorLimits.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SendNotLogged.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupActivityTypeForFollowUp.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCloseCrm.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCopperCrm.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupCrmCommand.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SetupLayouts.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncAccount.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncContact.php","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncFieldMetadata.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotActiveDeals.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncLead.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncObjects.php, class","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunitiesMissingFieldDataCommand.php, class","depth":11,"on_screen":false,"role_description":"text"}]...
|
6767534694907463242
|
-8141198994779927276
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\IntegrationApp\ServiceTraits;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Services\Crm\IntegrationApp\Config\IntegrationAppProviders;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmField;
use Jiminny\Services\Crm\IntegrationApp\DTO\CrmFieldDefinitionsManager;
use RuntimeException;
trait SyncCrmFieldsTrait
{
public function syncFields(): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
if ($this->config->getEdition() === IntegrationAppProviders::ZOHO_CRM) {
$fieldManager = new CrmFieldDefinitionsManager();
foreach ($fieldManager->getFieldDefinitions() as $fieldType => $crmFields) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $fieldType));
$this->syncObjectTypeFields($fieldType, $crmFields);
}
}
return;
}
foreach ($this->getFieldTypes() as $object) {
$this->logger->info(sprintf('[integration-app] Syncing %s fields.', $object));
$fields = $this->client->getObjectFields($object);
foreach ($fields as $fieldDto) {
$field = $this->importCrmField($fieldDto);
if ($field->isPicklist()) {
$this->importPicklistValues($field);
}
}
}
}
private function syncObjectTypeFields(string $fieldType, array $crmFields): void
{
foreach ($crmFields as $crmField) {
$this->syncCrmField($fieldType, $crmField);
}
}
private function syncCrmField(string $fieldType, array $crmField): void
{
$fieldData = [
'crm_provider_id' => $crmField['crm_id'],
'object_type' => $fieldType,
'label' => mb_strimwidth($crmField['label'], 0, Field::LABEL_MAX_LENGTH),
'description' => mb_strimwidth($crmField['description'], 0, Field::DESCRIPTION_MAX_LENGTH),
'type' => $crmField['type'],
'is_selectable' => $crmField['is_selectable'] ?? true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
$field = $fieldRepository->upsertField($this->config, $fieldData);
$this->logger->info('[integration-app] Synced field', [
'field' => $field->getLabel(),
'team_id' => $this->team?->getId(),
]);
$field->refresh();
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
private function importCrmField(CrmField $crmField): Field
{
$fieldData = [
'crm_provider_id' => $crmField->getExternalId(),
'object_type' => $crmField->getObjectType(),
'label' => $crmField->getLabel()
? mb_strimwidth($crmField->getLabel(), 0, Field::LABEL_MAX_LENGTH)
: '',
'description' => $crmField->getDescription()
? mb_strimwidth($crmField->getDescription(), 0, Field::DESCRIPTION_MAX_LENGTH)
: null,
'type' => $crmField->getType(),
'is_selectable' => true,
];
/** @var FieldRepository $fieldRepository */
$fieldRepository = app(FieldRepository::class);
return $fieldRepository->upsertField($this->config, $fieldData);
}
/**
* Works together with SyncTeamMetadata command if new field is added and needs to be synced.
*/
public function syncField(Field $field): void
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldId = $field->getCrmProviderId();
$fieldType = $field->getObjectType();
$fieldManager = new CrmFieldDefinitionsManager();
$fieldDefinition = $fieldManager->findByCrmId($fieldId, $fieldType);
$this->syncCrmField($fieldType, $fieldDefinition);
} else {
$fieldDto = $this->client->getField($field->getObjectType(), $field->getCrmProviderId());
$this->importCrmField($fieldDto);
}
}
public function importPicklistValues(Field $field): array
{
if (! $this->editionConfig->supportsCrmFieldsSync()) {
$fieldManager = new CrmFieldDefinitionsManager();
$picklistValues = $fieldManager->getPicklistValues($field->getCrmProviderId());
} else {
if (! $field->isPicklist()) {
return [];
}
$picklistValues = $this->client->getPicklistValues(
$field->getObjectType(),
$field->getCrmProviderId(),
);
}
if (empty($picklistValues)) {
return [];
}
return $this->importOptions($field, $picklistValues);
}
private function importOptions(Field $field, array $options): array
{
$fieldValues = [];
$sequence = 0;
$fieldRepo = app(FieldRepository::class);
foreach ($options as $option) {
$value = [
'value' => $option,
'label' => $option,
'sequence' => $sequence++,
];
$fieldValues[] = $fieldRepo->updateOrCreateFieldValue($field, $value);
}
return $fieldValues;
}
protected function getFieldTypes(): array
{
return match ($this->config->getEdition()) {
IntegrationAppProviders::MS_DYNAMICS => [
Field::OBJECT_OPPORTUNITY,
Field::OBJECT_LEAD,
Field::OBJECT_CONTACT,
Field::OBJECT_ACCOUNT,
Field::OBJECT_TASK,
],
default => throw new RuntimeException('Unsupported CRM provider')
};
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl
ActionItems
Activity
ActivityAnalytics
ActivitySearch
AiActivityType
AiAutomation
AiCallScoring
AskAnything
Dtos
Events
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration
Console
Commands, folder
Activities
Analytics
Calendars
Crm
Hubspot
IntegrationApp
Traits
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BackfillOpportunityUserFromAccountCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php
BullhornSessionCommand.php
CheckActivityLoggableCommand.php
CleanDuplicateFieldDataCommand.php
FullSyncOpportunityCommand.php
LogActivitiesCommand.php
ManageSyncStrategyCommand.php
MatchCrmObjectsCommand.php
MatchOpportunityActivitiesCommand.php
MigrateProvider.php
ProcessHubspotObjectsSyncBatches.php
PurgeDeletedOpportunitiesCommand.php
ResetGovernorLimits.php
SendNotLogged.php
SetupActivityTypeForFollowUp.php
SetupCloseCrm.php
SetupCopperCrm.php
SetupCrmCommand.php
SetupLayouts.php
SyncAccount.php
SyncContact.php
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65472
|
2307
|
12
|
2026-05-21T07:40:28.206330+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349228206_m2.jpg...
|
PhpStorm
|
faVsco.js – SharedSyncFieldsTrait.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
8043719072324535154
|
-8628527368849355612
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
slackFV [EMAIL]=.phounit. Project: faVsco.js, menu
slackFV [EMAIL]=.phounit.result.cacheE .prettierignore= windsurtrulesphpde neloer.onophpide heloer_models.ohophp artisanM'CLAUDE.mdcomooser.isoncomooser.lockdependency-checker.json8 dev ison= ids tytl=infection.ison.distMLINSTAlI.mdMLINTERNAI WERHOOK SFTUP mdEjiminny_storageMiliconsos mdllM Makefile1рackace-lock. sonE phpstan.neon.dist= phostan-baseline.neon<> phpunit.xmlTe raw sal query.saM+ README.mdsô sonar-proiect propertiesE test.ov‹> Untitled Diaaram.xmliusvetur.confio.isM+ WEBHOOK FILTERING_IMPLEMENTATION.mo>1h External Librariesv =° Scratches and Consolesv batabase Consolesv AEU# console (EUlI DEAL RISKS (SU1A DITEUlA EU (EU]v Ajiminny@localhostA console (jiminny@localhost]# Di [liminny@localhostlA HS local [iiminny@localhostlA SF ['iiminny@localhost]& zoho dev [iiminny@localhost]V & PRODA console [PROD]& console 1 [PROD1LDIIPRODCActivityController.ong© ConvertLeadActivities.php= laravel.log4 SF jiminny@localhost]4 HS_local [jiminny@localhost]& console (PROD] X# console [euyLeadkepository.ong© PurgeLookupCache.php© SyncPlanhat.phpo synerorlannatpnpA console [STAGING]AcuivityLeadConverted.php© UserAutomatedreporscontroller.phpx© PlaybackController.php)Inteqrationapp/service.onoC) LeadConverted.ono570571C) CreateCommentedEvent.php(C) CreateSmsSentEvent.phpC) PlanhatActivityListener.php© AskAnythingPromptService.php572(C) AutomatedReportsRepositorv.php© AutomatedReportsCommand.phpphp api_v2.phpC) RequestGenerateReportJob.php573574© AutomatedReportResult.php(C) AutomatedReport.oho575use Jiminny \Services \Kiosk \AutomatedReports \ReportSortDirection;A1422 ^ v 576use Jiminny \Services\PlanhatService;use ectumtnace hutp kequestuse Inrowable,class UserAutomatedReportsController extends Controllenpublic const int RESULTS PER_ PAGE = 25:public const string SORT COLUMN = 'sort column':public const strina SORT DIRECTION = "sort direction':public function constructprivate readonly AutomatedReportsRepository $automatedReportsRepository.private readonly AutomatedRenortsService SautomatedRenortsServicelorivate readoni.v AniResponseService samiResponseServi.ce.orivate readoni.v Resnonse Sresnonse.private readonly PlanhatService $planhatService1...poST lanilv1lautomated-renorts/interest 1usadepublic function trackInterest(Request $request): JsonResponse(...}* Othnows ApplicationException58(09 >GET /api/v1/automated-reportspublic function list(Request Srequest): JsonResponse(...}125 0)DELETE/api/vl/automated-reports/kuuidpublic function delete(Request Srequest. string Suuid): JsonResponsef...} -609610--611612613616Tx: AutovSo jiminny vCONCAT(u.id, CASE WHEN U.id = t.owner_id THEN' (owner)' ELSE'' END) AS USEr_i041 A1 A40 V65 ^sa.*t.owner_id FROM social_accounts saNoun usens u on u.ide sa.sociablle 1diJOIN teams t 1..n<->1: on t.id = u.team_idWHERE u.team_id = 581 and sa.provider = 'salesforce';SELECT * FROM automated_report_results order by id desc;select * from features;select * from team_features where feature_id = 40;select * from teams where id = 556:select * trom automated reports:where id = 54: # 4fdd41f6-dcf0-30d0-b339-7345381b6044|"pat", "podcast"SELECT * FROM automated report results WHERE uuid to bin( '822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;select * from automated_report_results order by id desc;SELECT * FROMWHERE id = 1919:select * fromautomated report results WHERE report id = 54:select * from opportunities where id = 7594349:SELECT * FROM teams WHERE name LIKE '%Lesg': # 711. 692. [EMAIL] * from playbooks where team_id = 711; # event 226147SELEd * FROM Dlavbook catedonies WHERE Dlavbook 1d = 55151SELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event':SELECT * SROM eom fields WHEREI1d = 2261471SELECT * FROM crm_field_values WHERE crm_field_id = 226147;SELECT * FROM crm_configurations WHERE id = 692;SELSCTCONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '• END) AS user_id,v.emailsa.*,t.owner id FROM social accounts saJOIN users u on v.id = sa.sociable idJOIN teams t 1..n<->1: on t.id = u.team idWHERE U.team_id = 711 and sa.provider = 'salesforce";SELECT * FROM crm profiles cp JOIN users u 1..n<->1: on u.id = co.user id WHERE u.team_id = 711:select * from leadsselect * from calendarsSELECTS 0 hllsupoont Dally • In 4h 40m100% 52• Inu z1 May 10.10.34AskJiminnyReportActivityServiceTestvCascadePlaybook Categorie+0 ..connected. How isi. Can we vali eoneactivity tyee nith orit cabest aeeiewmane o, W dati anwsyggesinsingrow hohow to distinguishThoughts68 Fast Context How are playbook_categories populated and synced from crm_fields / crm_field_values... in 4.14s >Explored 4 files and searched 5 queriesRead ImportActivitvTypes.php #L95-104Searched olavbook cateaories in databaselmiarations (4) >egories|playbook_categories.*create in database/migrations (0)searched playoook_categor in database/migrations (<)Searched activity type in database/migrations (4)SurtingAsk anvthina (*4L)@ Codo Caudo Onue 17 ModiumNN Windeurf Toame 504.60...
|
65470
|
NULL
|
NULL
|
NULL
|
|
65471
|
2306
|
16
|
2026-05-21T07:40:28.186022+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349228186_m1.jpg...
|
PhpStorm
|
faVsco.js – SharedSyncFieldsTrait.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
5222591262487654398
|
-8636637129462003327
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
SlackFileEditViewGoHistoryWindowHelpscreelDOCKER0 81DEV (-zsh)₴2APP (-zsh)whisper_init_state:whisper_init_state:kv padsize=2.36 MBcompute buffer (conv)whisper_init_state: compute buffer (encode) =whisper_init_state: compute buffer (cross)=whisper_init_state:compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocatingwhisper_backend_init_gpu: device 0: Metal (type:1)whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)whisper_backend_init_gpu: using Metal backendggml_metal_init: allocatingggml_metal_init: found device: Apple M1ggml_metal_init: picking default device: Apple M1ggml_metal_init:use fusion= trueggml_metal_init:use concurrency= trueggml_metal_init: use graph optimizetruewhisper_backend_init: using BLAS backendwhisper_init_state: kv self size3.15 MBwhisper_init_state: kv cross size =9.44 MBwhisper_init_state: kv padsize =2.36 MBwhisper_init_state: compute buffer (conv)whisper_init_state: compute buffer (encode) =whisper_init_state: compute buffer (cross)=whisper_init_state: compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocatingwhisper_backend_init_gpu:device 0: Metal (type: 1)whisper_backend_init_gpu: found GPUdevice 0: Metal (type: 1, cnt: 0)whisper_backend_init_gpu: using Metal backendggml_metal_init: allocatingggml_metal_init: found device: Apple M1ggml_metal_init: picking default device: Apple M1ggml_metal_init:use fusion= trueggml_metal_init:use concurrencytrueggml_metal_init:use graph optimizetruewhisper_backend_init: using BLAS backendwhisper_init_state: kv self size3.15 MBwhisper_init_state: kv cross size =9.44 MBwhisper_init_state: kv padsize=2.36 MBwhisper_init_state: compute buffer (conv)whisper_init_state: compute buffer (encode) =whisper_init_state: compute buffer (cross)whisper_init_state: compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocating2026-05-21T10:13:41.913005ZINFO screenpipe_audio::audio_manager::manager: reconciliatior2026-05-21710:15:15.5768762INFO screenpipe_engine::event_driven_capture: content dedup:j Support Daily - in 4h 45 m100% С8• Thu 21 May 10:15:32•••EDQHomeDMsActivityFilesLater•••More+→Describe what you are looking forJiminny ...ThreadsC9 Unreadsà platform-inner-teamGalya Dimitrova, Nikolay Yankov, and youa ThreadsHuddles• Drafts & sentDirectories01External connections* Starred& jiminny-x-integrati...platform-inner-teamChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# curiosity_lab# engineering# general# happy_birthday# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# supportLukas Kovalik 31 minutes agoдобро утро, тази страница не трябва ли да япоказваме само ако няма reportsCleanShot 2026-05-21 at [EMAIL] your questions into ongoing insightsGalya Dimitrova 23 minutes agoДа, би трябвалоLukas Kovalik 22 minutes agoче сега ми го показва и ако имам reportLukas Kovalik 21 minutes agoна neptuneNewNikolay Yankov 6 minutes agoвсичко е наредReply...Also send to à platform-inner-team+AaYou're up to date...
|
65469
|
NULL
|
NULL
|
NULL
|
|
65469
|
2306
|
15
|
2026-05-21T07:40:12.253201+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349212253_m1.jpg...
|
PhpStorm
|
faVsco.js – SharedSyncFieldsTrait.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\CrmObjects\ServiceTraits;
use Illuminate\Bus\Dispatcher;
use Jiminny\Exceptions\RuntimeException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\RecordTypeFieldValuesRepository;
use Jiminny\Services\Crm\CrmObjects\Fields\Definition;
use Jiminny\Services\Crm\CrmObjects\Fields\DefinitionInterface;
use Jiminny\Services\Crm\CrmObjects\Fields\FieldTransformerInterface;
use Jiminny\Services\Crm\CrmObjects\Jobs\DeleteCrmFieldsJob;
/**
* A shared trait that holds common synchronisation logic.
*
* Currently sharing sunchronisation logic between Hubspot and Salesforce
*/
trait SharedSyncFieldsTrait
{
private const int DELETE_FIELDS_CHUNK_SIZE = 100;
private ?Dispatcher $jobDispatcher = null;
abstract protected function getFieldTypes(): array;
abstract protected function getObjectFields(string $objectType): array;
abstract protected function prepareTransformer(string $crmObjectType): FieldTransformerInterface;
public function listSupportedObjectTypes(): array
{
return $this->getFieldTypes();
}
/**
* @throws SocialAccountTokenInvalidException
*/
public function syncFields(): void
{
$this->logger->info('Syncing fields for CRM', [
'provider' => $this->getDisplayName(),
'team_id' => $this->team->getId(),
]);
$fieldRepository = app(FieldRepository::class);
foreach ($this->getFieldTypes() as $objectType) {
$this->syncSingleObjectType($fieldRepository, $objectType);
}
}
/**
* @throws SocialAccountTokenInvalidException
*/
protected function syncSingleObjectType(FieldRepository $fieldRepository, string $objectType): void
{
$this->logger->info('Sync fields per type', [
'object_type' => $objectType,
'team_id' => $this->team->getId(),
]);
$updatedFields = [];
$existingFields = [];
$existingFieldsCollection = $fieldRepository->getAllFieldsForObjectType($this->team, $objectType);
$existingFieldsCollection->map(function ($field) use (&$existingFields) {
$existingFields[] = $field->getCrmProviderId();
});
$currentFields = $this->getFields($objectType);
foreach ($currentFields as $fieldData) {
$updatedFields[] = $fieldData->name;
$this->updateSingleField($fieldRepository, $fieldData);
}
/** Those fields are removed from the crm, and we need to stop working with them as well.*/
$obsoletedFields = array_diff($existingFields, $updatedFields);
/**
* There are potentially a few special fields, that may exist only locally.
* And yet they must not be deleted, since they are used for special internal purposes.
* i.e. meetingOutcome, activityType, disposition
*/
$obsoletedNonSpecialFields = array_diff($obsoletedFields, $this->getSpecialFieldsList());
if (! empty($obsoletedNonSpecialFields)) {
$this->logger->info('Clean up obsolete fields per object type', [
'object_type' => $objectType,
'team_id' => $this->team->getId(),
'obsolete_fields_count' => count($obsoletedNonSpecialFields),
]);
$chunks = array_chunk($obsoletedNonSpecialFields, self::DELETE_FIELDS_CHUNK_SIZE);
foreach ($chunks as $chunk) {
$this->getDispatcher()
->dispatch(new DeleteCrmFieldsJob(
teamId: $this->team->getId(),
objectType: $objectType,
crmProviderIds: $chunk,
));
}
}
}
protected function importFieldPicklistValue(
FieldRepository $fieldRepository,
Field $field,
Definition $fieldDefinition,
): void {
$this->logger->info('Import picklist values for field', [
'field_id' => $field->getId(),
'crm_provider_id' => $field->getCrmProviderId(),
'object_type' => $field->getObjectType(),
'team_id' => $this->team->getId(),
]);
$existingPicklistItemsCollection = $fieldRepository->getPicklistValues($field);
$existingPicklistItems = $existingPicklistItemsCollection->pluck('value')->toArray();
$updatedPicklistItems = [];
foreach ($fieldDefinition->getPicklistItems() as $eachPicklist) {
$updatedPicklistItems[] = $eachPicklist->getValue();
$fieldRepository->updatePicklistValue($field, $eachPicklist->export());
}
$notUpdatedPicklistItems = array_values(array_diff($existingPicklistItems, $updatedPicklistItems));
$this->logger->info('Picklist items updated', [
'field_id' => $field->getId(),
]);
// Nothing to delete, move to next field
if (empty($notUpdatedPicklistItems)) {
return;
}
// Delete the old values that are no longer used.
// Get IDs of the values to be deleted
$valuesToDelete = $fieldRepository->getPicklistValues($field, $notUpdatedPicklistItems);
if ($valuesToDelete->isNotEmpty()) {
$this->logger->info('Picklist items to be deleted', [
'field_id' => $field->getId(),
'values_to_delete' => $notUpdatedPicklistItems,
]);
// Remove Record type field value associations
$recordTypeFieldValuesRepository = app(RecordTypeFieldValuesRepository::class);
$recordTypeFieldValuesRepository->deleteForCrmFieldValueIds(
$valuesToDelete->pluck('id')->toArray(),
);
// Now safely delete from crm_field_values
foreach ($valuesToDelete->all() as $eachFieldValue) {
$eachFieldValue->delete();
}
}
}
private function updateSingleField(
FieldRepository $fieldRepository,
Definition $fieldData
): void {
$field = $this->upsertField($fieldRepository, $fieldData);
if ($fieldData->isPicklist()) {
$this->importFieldPicklistValue($fieldRepository, $field, $fieldData);
}
}
protected function upsertField(FieldRepository $fieldRepository, Definition $fieldData): Field
{
return $fieldRepository->upsertField(
configuration: $this->team->getCrmConfiguration(),
data: $fieldData->export(),
);
}
/**
* Gets the valid fields for a given Crm Object for a specific Crm object.
*
* @param string $crmObject The name of the target crm object. i.e. Account, Opportunity, Deal, etc.
*
* @return Definition[]
*/
protected function getFields(string $crmObject): array
{
$fields = [];
$transformer = $this->prepareTransformer($crmObject);
foreach ($this->getObjectFields($crmObject) as $row) {
/** @var DefinitionInterface&Definition $definition */
$definition = $transformer->transform($row);
$definitionFields = $this->handleDefinitionAlias($definition);
/**
* At least one field will be provided, potentially two, if the fields needs an alias, too.
*
* @var Definition $eachField
*/
foreach ($definitionFields as $eachField) {
$fields[] = $eachField;
}
}
return $fields;
}
private function handleDefinitionAlias(Definition $definition): array
{
$fields = [];
/** Overload special picklist items where applicable */
$this->decorateWithSpecialPicklistItems($definition);
$fields[] = $definition;
/**
* Alias fields are our internal representations for special fields
* that some CRMs support (ActivityType -> task.hs_activity_type).
*
* Aliases are shorthands that remap external to internal fields
*/
if ($this->shouldAddAliasFieldDefinition($definition)) {
$fields[] = $this->addAliasFieldDefinition($definition);
}
return $fields;
}
private function getDispatcher(): Dispatcher
{
if ($this->jobDispatcher === null) {
$this->jobDispatcher = app(Dispatcher::class);
}
return $this->jobDispatcher;
}
/**
* If applicable, decorate the field with Special Picklist items.
*
* Currently applicable for Hubspot only. The current implementations are placeholders for other CRMs.
*/
protected function decorateWithSpecialPicklistItems(Definition $fieldDefinition): void
{
// Nothing to do
}
protected function shouldAddAliasFieldDefinition(Definition $fieldDefinition): bool
{
return false;
}
protected function addAliasFieldDefinition(Definition $fieldDefinition): Definition
{
throw new RuntimeException('Method not implemented, nor required.');
}
/**
* Get a list of special fields that shouldn't be deleted, even if they do not remotely exist
*/
protected function getSpecialFieldsList(): array
{
return [];
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\CrmObjects\\ServiceTraits;\n\nuse Illuminate\\Bus\\Dispatcher;\nuse Jiminny\\Exceptions\\RuntimeException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\RecordTypeFieldValuesRepository;\nuse Jiminny\\Services\\Crm\\CrmObjects\\Fields\\Definition;\nuse Jiminny\\Services\\Crm\\CrmObjects\\Fields\\DefinitionInterface;\nuse Jiminny\\Services\\Crm\\CrmObjects\\Fields\\FieldTransformerInterface;\nuse Jiminny\\Services\\Crm\\CrmObjects\\Jobs\\DeleteCrmFieldsJob;\n\n/**\n * A shared trait that holds common synchronisation logic.\n *\n * Currently sharing sunchronisation logic between Hubspot and Salesforce\n */\ntrait SharedSyncFieldsTrait\n{\n private const int DELETE_FIELDS_CHUNK_SIZE = 100;\n\n private ?Dispatcher $jobDispatcher = null;\n\n abstract protected function getFieldTypes(): array;\n\n abstract protected function getObjectFields(string $objectType): array;\n\n abstract protected function prepareTransformer(string $crmObjectType): FieldTransformerInterface;\n\n public function listSupportedObjectTypes(): array\n {\n return $this->getFieldTypes();\n }\n\n /**\n * @throws SocialAccountTokenInvalidException\n */\n public function syncFields(): void\n {\n $this->logger->info('Syncing fields for CRM', [\n 'provider' => $this->getDisplayName(),\n 'team_id' => $this->team->getId(),\n ]);\n\n $fieldRepository = app(FieldRepository::class);\n\n foreach ($this->getFieldTypes() as $objectType) {\n $this->syncSingleObjectType($fieldRepository, $objectType);\n }\n }\n\n /**\n * @throws SocialAccountTokenInvalidException\n */\n protected function syncSingleObjectType(FieldRepository $fieldRepository, string $objectType): void\n {\n $this->logger->info('Sync fields per type', [\n 'object_type' => $objectType,\n 'team_id' => $this->team->getId(),\n ]);\n\n $updatedFields = [];\n $existingFields = [];\n\n $existingFieldsCollection = $fieldRepository->getAllFieldsForObjectType($this->team, $objectType);\n $existingFieldsCollection->map(function ($field) use (&$existingFields) {\n $existingFields[] = $field->getCrmProviderId();\n });\n\n $currentFields = $this->getFields($objectType);\n foreach ($currentFields as $fieldData) {\n $updatedFields[] = $fieldData->name;\n\n $this->updateSingleField($fieldRepository, $fieldData);\n }\n\n /** Those fields are removed from the crm, and we need to stop working with them as well.*/\n $obsoletedFields = array_diff($existingFields, $updatedFields);\n\n /**\n * There are potentially a few special fields, that may exist only locally.\n * And yet they must not be deleted, since they are used for special internal purposes.\n * i.e. meetingOutcome, activityType, disposition\n */\n $obsoletedNonSpecialFields = array_diff($obsoletedFields, $this->getSpecialFieldsList());\n\n if (! empty($obsoletedNonSpecialFields)) {\n $this->logger->info('Clean up obsolete fields per object type', [\n 'object_type' => $objectType,\n 'team_id' => $this->team->getId(),\n 'obsolete_fields_count' => count($obsoletedNonSpecialFields),\n ]);\n\n $chunks = array_chunk($obsoletedNonSpecialFields, self::DELETE_FIELDS_CHUNK_SIZE);\n foreach ($chunks as $chunk) {\n $this->getDispatcher()\n ->dispatch(new DeleteCrmFieldsJob(\n teamId: $this->team->getId(),\n objectType: $objectType,\n crmProviderIds: $chunk,\n ));\n }\n }\n }\n\n protected function importFieldPicklistValue(\n FieldRepository $fieldRepository,\n Field $field,\n Definition $fieldDefinition,\n ): void {\n $this->logger->info('Import picklist values for field', [\n 'field_id' => $field->getId(),\n 'crm_provider_id' => $field->getCrmProviderId(),\n 'object_type' => $field->getObjectType(),\n 'team_id' => $this->team->getId(),\n ]);\n\n $existingPicklistItemsCollection = $fieldRepository->getPicklistValues($field);\n $existingPicklistItems = $existingPicklistItemsCollection->pluck('value')->toArray();\n\n $updatedPicklistItems = [];\n foreach ($fieldDefinition->getPicklistItems() as $eachPicklist) {\n $updatedPicklistItems[] = $eachPicklist->getValue();\n $fieldRepository->updatePicklistValue($field, $eachPicklist->export());\n }\n\n $notUpdatedPicklistItems = array_values(array_diff($existingPicklistItems, $updatedPicklistItems));\n\n $this->logger->info('Picklist items updated', [\n 'field_id' => $field->getId(),\n ]);\n\n // Nothing to delete, move to next field\n if (empty($notUpdatedPicklistItems)) {\n return;\n }\n\n // Delete the old values that are no longer used.\n // Get IDs of the values to be deleted\n $valuesToDelete = $fieldRepository->getPicklistValues($field, $notUpdatedPicklistItems);\n\n if ($valuesToDelete->isNotEmpty()) {\n $this->logger->info('Picklist items to be deleted', [\n 'field_id' => $field->getId(),\n 'values_to_delete' => $notUpdatedPicklistItems,\n ]);\n\n // Remove Record type field value associations\n $recordTypeFieldValuesRepository = app(RecordTypeFieldValuesRepository::class);\n $recordTypeFieldValuesRepository->deleteForCrmFieldValueIds(\n $valuesToDelete->pluck('id')->toArray(),\n );\n\n // Now safely delete from crm_field_values\n foreach ($valuesToDelete->all() as $eachFieldValue) {\n $eachFieldValue->delete();\n }\n }\n }\n\n private function updateSingleField(\n FieldRepository $fieldRepository,\n Definition $fieldData\n ): void {\n $field = $this->upsertField($fieldRepository, $fieldData);\n\n if ($fieldData->isPicklist()) {\n $this->importFieldPicklistValue($fieldRepository, $field, $fieldData);\n }\n }\n\n protected function upsertField(FieldRepository $fieldRepository, Definition $fieldData): Field\n {\n return $fieldRepository->upsertField(\n configuration: $this->team->getCrmConfiguration(),\n data: $fieldData->export(),\n );\n }\n\n /**\n * Gets the valid fields for a given Crm Object for a specific Crm object.\n *\n * @param string $crmObject The name of the target crm object. i.e. Account, Opportunity, Deal, etc.\n *\n * @return Definition[]\n */\n protected function getFields(string $crmObject): array\n {\n $fields = [];\n $transformer = $this->prepareTransformer($crmObject);\n foreach ($this->getObjectFields($crmObject) as $row) {\n /** @var DefinitionInterface&Definition $definition */\n $definition = $transformer->transform($row);\n\n $definitionFields = $this->handleDefinitionAlias($definition);\n\n /**\n * At least one field will be provided, potentially two, if the fields needs an alias, too.\n *\n * @var Definition $eachField\n */\n foreach ($definitionFields as $eachField) {\n $fields[] = $eachField;\n }\n }\n\n return $fields;\n }\n\n private function handleDefinitionAlias(Definition $definition): array\n {\n $fields = [];\n /** Overload special picklist items where applicable */\n $this->decorateWithSpecialPicklistItems($definition);\n $fields[] = $definition;\n\n /**\n * Alias fields are our internal representations for special fields\n * that some CRMs support (ActivityType -> task.hs_activity_type).\n *\n * Aliases are shorthands that remap external to internal fields\n */\n if ($this->shouldAddAliasFieldDefinition($definition)) {\n $fields[] = $this->addAliasFieldDefinition($definition);\n }\n\n return $fields;\n }\n\n private function getDispatcher(): Dispatcher\n {\n if ($this->jobDispatcher === null) {\n $this->jobDispatcher = app(Dispatcher::class);\n }\n\n return $this->jobDispatcher;\n }\n\n /**\n * If applicable, decorate the field with Special Picklist items.\n *\n * Currently applicable for Hubspot only. The current implementations are placeholders for other CRMs.\n */\n protected function decorateWithSpecialPicklistItems(Definition $fieldDefinition): void\n {\n // Nothing to do\n }\n\n protected function shouldAddAliasFieldDefinition(Definition $fieldDefinition): bool\n {\n return false;\n }\n\n protected function addAliasFieldDefinition(Definition $fieldDefinition): Definition\n {\n throw new RuntimeException('Method not implemented, nor required.');\n }\n\n /**\n * Get a list of special fields that shouldn't be deleted, even if they do not remotely exist\n */\n protected function getSpecialFieldsList(): array\n {\n return [];\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\CrmObjects\\ServiceTraits;\n\nuse Illuminate\\Bus\\Dispatcher;\nuse Jiminny\\Exceptions\\RuntimeException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\RecordTypeFieldValuesRepository;\nuse Jiminny\\Services\\Crm\\CrmObjects\\Fields\\Definition;\nuse Jiminny\\Services\\Crm\\CrmObjects\\Fields\\DefinitionInterface;\nuse Jiminny\\Services\\Crm\\CrmObjects\\Fields\\FieldTransformerInterface;\nuse Jiminny\\Services\\Crm\\CrmObjects\\Jobs\\DeleteCrmFieldsJob;\n\n/**\n * A shared trait that holds common synchronisation logic.\n *\n * Currently sharing sunchronisation logic between Hubspot and Salesforce\n */\ntrait SharedSyncFieldsTrait\n{\n private const int DELETE_FIELDS_CHUNK_SIZE = 100;\n\n private ?Dispatcher $jobDispatcher = null;\n\n abstract protected function getFieldTypes(): array;\n\n abstract protected function getObjectFields(string $objectType): array;\n\n abstract protected function prepareTransformer(string $crmObjectType): FieldTransformerInterface;\n\n public function listSupportedObjectTypes(): array\n {\n return $this->getFieldTypes();\n }\n\n /**\n * @throws SocialAccountTokenInvalidException\n */\n public function syncFields(): void\n {\n $this->logger->info('Syncing fields for CRM', [\n 'provider' => $this->getDisplayName(),\n 'team_id' => $this->team->getId(),\n ]);\n\n $fieldRepository = app(FieldRepository::class);\n\n foreach ($this->getFieldTypes() as $objectType) {\n $this->syncSingleObjectType($fieldRepository, $objectType);\n }\n }\n\n /**\n * @throws SocialAccountTokenInvalidException\n */\n protected function syncSingleObjectType(FieldRepository $fieldRepository, string $objectType): void\n {\n $this->logger->info('Sync fields per type', [\n 'object_type' => $objectType,\n 'team_id' => $this->team->getId(),\n ]);\n\n $updatedFields = [];\n $existingFields = [];\n\n $existingFieldsCollection = $fieldRepository->getAllFieldsForObjectType($this->team, $objectType);\n $existingFieldsCollection->map(function ($field) use (&$existingFields) {\n $existingFields[] = $field->getCrmProviderId();\n });\n\n $currentFields = $this->getFields($objectType);\n foreach ($currentFields as $fieldData) {\n $updatedFields[] = $fieldData->name;\n\n $this->updateSingleField($fieldRepository, $fieldData);\n }\n\n /** Those fields are removed from the crm, and we need to stop working with them as well.*/\n $obsoletedFields = array_diff($existingFields, $updatedFields);\n\n /**\n * There are potentially a few special fields, that may exist only locally.\n * And yet they must not be deleted, since they are used for special internal purposes.\n * i.e. meetingOutcome, activityType, disposition\n */\n $obsoletedNonSpecialFields = array_diff($obsoletedFields, $this->getSpecialFieldsList());\n\n if (! empty($obsoletedNonSpecialFields)) {\n $this->logger->info('Clean up obsolete fields per object type', [\n 'object_type' => $objectType,\n 'team_id' => $this->team->getId(),\n 'obsolete_fields_count' => count($obsoletedNonSpecialFields),\n ]);\n\n $chunks = array_chunk($obsoletedNonSpecialFields, self::DELETE_FIELDS_CHUNK_SIZE);\n foreach ($chunks as $chunk) {\n $this->getDispatcher()\n ->dispatch(new DeleteCrmFieldsJob(\n teamId: $this->team->getId(),\n objectType: $objectType,\n crmProviderIds: $chunk,\n ));\n }\n }\n }\n\n protected function importFieldPicklistValue(\n FieldRepository $fieldRepository,\n Field $field,\n Definition $fieldDefinition,\n ): void {\n $this->logger->info('Import picklist values for field', [\n 'field_id' => $field->getId(),\n 'crm_provider_id' => $field->getCrmProviderId(),\n 'object_type' => $field->getObjectType(),\n 'team_id' => $this->team->getId(),\n ]);\n\n $existingPicklistItemsCollection = $fieldRepository->getPicklistValues($field);\n $existingPicklistItems = $existingPicklistItemsCollection->pluck('value')->toArray();\n\n $updatedPicklistItems = [];\n foreach ($fieldDefinition->getPicklistItems() as $eachPicklist) {\n $updatedPicklistItems[] = $eachPicklist->getValue();\n $fieldRepository->updatePicklistValue($field, $eachPicklist->export());\n }\n\n $notUpdatedPicklistItems = array_values(array_diff($existingPicklistItems, $updatedPicklistItems));\n\n $this->logger->info('Picklist items updated', [\n 'field_id' => $field->getId(),\n ]);\n\n // Nothing to delete, move to next field\n if (empty($notUpdatedPicklistItems)) {\n return;\n }\n\n // Delete the old values that are no longer used.\n // Get IDs of the values to be deleted\n $valuesToDelete = $fieldRepository->getPicklistValues($field, $notUpdatedPicklistItems);\n\n if ($valuesToDelete->isNotEmpty()) {\n $this->logger->info('Picklist items to be deleted', [\n 'field_id' => $field->getId(),\n 'values_to_delete' => $notUpdatedPicklistItems,\n ]);\n\n // Remove Record type field value associations\n $recordTypeFieldValuesRepository = app(RecordTypeFieldValuesRepository::class);\n $recordTypeFieldValuesRepository->deleteForCrmFieldValueIds(\n $valuesToDelete->pluck('id')->toArray(),\n );\n\n // Now safely delete from crm_field_values\n foreach ($valuesToDelete->all() as $eachFieldValue) {\n $eachFieldValue->delete();\n }\n }\n }\n\n private function updateSingleField(\n FieldRepository $fieldRepository,\n Definition $fieldData\n ): void {\n $field = $this->upsertField($fieldRepository, $fieldData);\n\n if ($fieldData->isPicklist()) {\n $this->importFieldPicklistValue($fieldRepository, $field, $fieldData);\n }\n }\n\n protected function upsertField(FieldRepository $fieldRepository, Definition $fieldData): Field\n {\n return $fieldRepository->upsertField(\n configuration: $this->team->getCrmConfiguration(),\n data: $fieldData->export(),\n );\n }\n\n /**\n * Gets the valid fields for a given Crm Object for a specific Crm object.\n *\n * @param string $crmObject The name of the target crm object. i.e. Account, Opportunity, Deal, etc.\n *\n * @return Definition[]\n */\n protected function getFields(string $crmObject): array\n {\n $fields = [];\n $transformer = $this->prepareTransformer($crmObject);\n foreach ($this->getObjectFields($crmObject) as $row) {\n /** @var DefinitionInterface&Definition $definition */\n $definition = $transformer->transform($row);\n\n $definitionFields = $this->handleDefinitionAlias($definition);\n\n /**\n * At least one field will be provided, potentially two, if the fields needs an alias, too.\n *\n * @var Definition $eachField\n */\n foreach ($definitionFields as $eachField) {\n $fields[] = $eachField;\n }\n }\n\n return $fields;\n }\n\n private function handleDefinitionAlias(Definition $definition): array\n {\n $fields = [];\n /** Overload special picklist items where applicable */\n $this->decorateWithSpecialPicklistItems($definition);\n $fields[] = $definition;\n\n /**\n * Alias fields are our internal representations for special fields\n * that some CRMs support (ActivityType -> task.hs_activity_type).\n *\n * Aliases are shorthands that remap external to internal fields\n */\n if ($this->shouldAddAliasFieldDefinition($definition)) {\n $fields[] = $this->addAliasFieldDefinition($definition);\n }\n\n return $fields;\n }\n\n private function getDispatcher(): Dispatcher\n {\n if ($this->jobDispatcher === null) {\n $this->jobDispatcher = app(Dispatcher::class);\n }\n\n return $this->jobDispatcher;\n }\n\n /**\n * If applicable, decorate the field with Special Picklist items.\n *\n * Currently applicable for Hubspot only. The current implementations are placeholders for other CRMs.\n */\n protected function decorateWithSpecialPicklistItems(Definition $fieldDefinition): void\n {\n // Nothing to do\n }\n\n protected function shouldAddAliasFieldDefinition(Definition $fieldDefinition): bool\n {\n return false;\n }\n\n protected function addAliasFieldDefinition(Definition $fieldDefinition): Definition\n {\n throw new RuntimeException('Method not implemented, nor required.');\n }\n\n /**\n * Get a list of special fields that shouldn't be deleted, even if they do not remotely exist\n */\n protected function getSpecialFieldsList(): array\n {\n return [];\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"on_screen":false,"role_description":"text"}]...
|
5939242430973264012
|
-4141321692866666925
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\CrmObjects\ServiceTraits;
use Illuminate\Bus\Dispatcher;
use Jiminny\Exceptions\RuntimeException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\RecordTypeFieldValuesRepository;
use Jiminny\Services\Crm\CrmObjects\Fields\Definition;
use Jiminny\Services\Crm\CrmObjects\Fields\DefinitionInterface;
use Jiminny\Services\Crm\CrmObjects\Fields\FieldTransformerInterface;
use Jiminny\Services\Crm\CrmObjects\Jobs\DeleteCrmFieldsJob;
/**
* A shared trait that holds common synchronisation logic.
*
* Currently sharing sunchronisation logic between Hubspot and Salesforce
*/
trait SharedSyncFieldsTrait
{
private const int DELETE_FIELDS_CHUNK_SIZE = 100;
private ?Dispatcher $jobDispatcher = null;
abstract protected function getFieldTypes(): array;
abstract protected function getObjectFields(string $objectType): array;
abstract protected function prepareTransformer(string $crmObjectType): FieldTransformerInterface;
public function listSupportedObjectTypes(): array
{
return $this->getFieldTypes();
}
/**
* @throws SocialAccountTokenInvalidException
*/
public function syncFields(): void
{
$this->logger->info('Syncing fields for CRM', [
'provider' => $this->getDisplayName(),
'team_id' => $this->team->getId(),
]);
$fieldRepository = app(FieldRepository::class);
foreach ($this->getFieldTypes() as $objectType) {
$this->syncSingleObjectType($fieldRepository, $objectType);
}
}
/**
* @throws SocialAccountTokenInvalidException
*/
protected function syncSingleObjectType(FieldRepository $fieldRepository, string $objectType): void
{
$this->logger->info('Sync fields per type', [
'object_type' => $objectType,
'team_id' => $this->team->getId(),
]);
$updatedFields = [];
$existingFields = [];
$existingFieldsCollection = $fieldRepository->getAllFieldsForObjectType($this->team, $objectType);
$existingFieldsCollection->map(function ($field) use (&$existingFields) {
$existingFields[] = $field->getCrmProviderId();
});
$currentFields = $this->getFields($objectType);
foreach ($currentFields as $fieldData) {
$updatedFields[] = $fieldData->name;
$this->updateSingleField($fieldRepository, $fieldData);
}
/** Those fields are removed from the crm, and we need to stop working with them as well.*/
$obsoletedFields = array_diff($existingFields, $updatedFields);
/**
* There are potentially a few special fields, that may exist only locally.
* And yet they must not be deleted, since they are used for special internal purposes.
* i.e. meetingOutcome, activityType, disposition
*/
$obsoletedNonSpecialFields = array_diff($obsoletedFields, $this->getSpecialFieldsList());
if (! empty($obsoletedNonSpecialFields)) {
$this->logger->info('Clean up obsolete fields per object type', [
'object_type' => $objectType,
'team_id' => $this->team->getId(),
'obsolete_fields_count' => count($obsoletedNonSpecialFields),
]);
$chunks = array_chunk($obsoletedNonSpecialFields, self::DELETE_FIELDS_CHUNK_SIZE);
foreach ($chunks as $chunk) {
$this->getDispatcher()
->dispatch(new DeleteCrmFieldsJob(
teamId: $this->team->getId(),
objectType: $objectType,
crmProviderIds: $chunk,
));
}
}
}
protected function importFieldPicklistValue(
FieldRepository $fieldRepository,
Field $field,
Definition $fieldDefinition,
): void {
$this->logger->info('Import picklist values for field', [
'field_id' => $field->getId(),
'crm_provider_id' => $field->getCrmProviderId(),
'object_type' => $field->getObjectType(),
'team_id' => $this->team->getId(),
]);
$existingPicklistItemsCollection = $fieldRepository->getPicklistValues($field);
$existingPicklistItems = $existingPicklistItemsCollection->pluck('value')->toArray();
$updatedPicklistItems = [];
foreach ($fieldDefinition->getPicklistItems() as $eachPicklist) {
$updatedPicklistItems[] = $eachPicklist->getValue();
$fieldRepository->updatePicklistValue($field, $eachPicklist->export());
}
$notUpdatedPicklistItems = array_values(array_diff($existingPicklistItems, $updatedPicklistItems));
$this->logger->info('Picklist items updated', [
'field_id' => $field->getId(),
]);
// Nothing to delete, move to next field
if (empty($notUpdatedPicklistItems)) {
return;
}
// Delete the old values that are no longer used.
// Get IDs of the values to be deleted
$valuesToDelete = $fieldRepository->getPicklistValues($field, $notUpdatedPicklistItems);
if ($valuesToDelete->isNotEmpty()) {
$this->logger->info('Picklist items to be deleted', [
'field_id' => $field->getId(),
'values_to_delete' => $notUpdatedPicklistItems,
]);
// Remove Record type field value associations
$recordTypeFieldValuesRepository = app(RecordTypeFieldValuesRepository::class);
$recordTypeFieldValuesRepository->deleteForCrmFieldValueIds(
$valuesToDelete->pluck('id')->toArray(),
);
// Now safely delete from crm_field_values
foreach ($valuesToDelete->all() as $eachFieldValue) {
$eachFieldValue->delete();
}
}
}
private function updateSingleField(
FieldRepository $fieldRepository,
Definition $fieldData
): void {
$field = $this->upsertField($fieldRepository, $fieldData);
if ($fieldData->isPicklist()) {
$this->importFieldPicklistValue($fieldRepository, $field, $fieldData);
}
}
protected function upsertField(FieldRepository $fieldRepository, Definition $fieldData): Field
{
return $fieldRepository->upsertField(
configuration: $this->team->getCrmConfiguration(),
data: $fieldData->export(),
);
}
/**
* Gets the valid fields for a given Crm Object for a specific Crm object.
*
* @param string $crmObject The name of the target crm object. i.e. Account, Opportunity, Deal, etc.
*
* @return Definition[]
*/
protected function getFields(string $crmObject): array
{
$fields = [];
$transformer = $this->prepareTransformer($crmObject);
foreach ($this->getObjectFields($crmObject) as $row) {
/** @var DefinitionInterface&Definition $definition */
$definition = $transformer->transform($row);
$definitionFields = $this->handleDefinitionAlias($definition);
/**
* At least one field will be provided, potentially two, if the fields needs an alias, too.
*
* @var Definition $eachField
*/
foreach ($definitionFields as $eachField) {
$fields[] = $eachField;
}
}
return $fields;
}
private function handleDefinitionAlias(Definition $definition): array
{
$fields = [];
/** Overload special picklist items where applicable */
$this->decorateWithSpecialPicklistItems($definition);
$fields[] = $definition;
/**
* Alias fields are our internal representations for special fields
* that some CRMs support (ActivityType -> task.hs_activity_type).
*
* Aliases are shorthands that remap external to internal fields
*/
if ($this->shouldAddAliasFieldDefinition($definition)) {
$fields[] = $this->addAliasFieldDefinition($definition);
}
return $fields;
}
private function getDispatcher(): Dispatcher
{
if ($this->jobDispatcher === null) {
$this->jobDispatcher = app(Dispatcher::class);
}
return $this->jobDispatcher;
}
/**
* If applicable, decorate the field with Special Picklist items.
*
* Currently applicable for Hubspot only. The current implementations are placeholders for other CRMs.
*/
protected function decorateWithSpecialPicklistItems(Definition $fieldDefinition): void
{
// Nothing to do
}
protected function shouldAddAliasFieldDefinition(Definition $fieldDefinition): bool
{
return false;
}
protected function addAliasFieldDefinition(Definition $fieldDefinition): Definition
{
throw new RuntimeException('Method not implemented, nor required.');
}
/**
* Get a list of special fields that shouldn't be deleted, even if they do not remotely exist
*/
protected function getSpecialFieldsList(): array
{
return [];
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65470
|
2307
|
11
|
2026-05-21T07:40:12.238106+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349212238_m2.jpg...
|
PhpStorm
|
faVsco.js – SharedSyncFieldsTrait.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\CrmObjects\ServiceTraits;
use Illuminate\Bus\Dispatcher;
use Jiminny\Exceptions\RuntimeException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\RecordTypeFieldValuesRepository;
use Jiminny\Services\Crm\CrmObjects\Fields\Definition;
use Jiminny\Services\Crm\CrmObjects\Fields\DefinitionInterface;
use Jiminny\Services\Crm\CrmObjects\Fields\FieldTransformerInterface;
use Jiminny\Services\Crm\CrmObjects\Jobs\DeleteCrmFieldsJob;
/**
* A shared trait that holds common synchronisation logic.
*
* Currently sharing sunchronisation logic between Hubspot and Salesforce
*/
trait SharedSyncFieldsTrait
{
private const int DELETE_FIELDS_CHUNK_SIZE = 100;
private ?Dispatcher $jobDispatcher = null;
abstract protected function getFieldTypes(): array;
abstract protected function getObjectFields(string $objectType): array;
abstract protected function prepareTransformer(string $crmObjectType): FieldTransformerInterface;
public function listSupportedObjectTypes(): array
{
return $this->getFieldTypes();
}
/**
* @throws SocialAccountTokenInvalidException
*/
public function syncFields(): void
{
$this->logger->info('Syncing fields for CRM', [
'provider' => $this->getDisplayName(),
'team_id' => $this->team->getId(),
]);
$fieldRepository = app(FieldRepository::class);
foreach ($this->getFieldTypes() as $objectType) {
$this->syncSingleObjectType($fieldRepository, $objectType);
}
}
/**
* @throws SocialAccountTokenInvalidException
*/
protected function syncSingleObjectType(FieldRepository $fieldRepository, string $objectType): void
{
$this->logger->info('Sync fields per type', [
'object_type' => $objectType,
'team_id' => $this->team->getId(),
]);
$updatedFields = [];
$existingFields = [];
$existingFieldsCollection = $fieldRepository->getAllFieldsForObjectType($this->team, $objectType);
$existingFieldsCollection->map(function ($field) use (&$existingFields) {
$existingFields[] = $field->getCrmProviderId();
});
$currentFields = $this->getFields($objectType);
foreach ($currentFields as $fieldData) {
$updatedFields[] = $fieldData->name;
$this->updateSingleField($fieldRepository, $fieldData);
}
/** Those fields are removed from the crm, and we need to stop working with them as well.*/
$obsoletedFields = array_diff($existingFields, $updatedFields);
/**
* There are potentially a few special fields, that may exist only locally.
* And yet they must not be deleted, since they are used for special internal purposes.
* i.e. meetingOutcome, activityType, disposition
*/
$obsoletedNonSpecialFields = array_diff($obsoletedFields, $this->getSpecialFieldsList());
if (! empty($obsoletedNonSpecialFields)) {
$this->logger->info('Clean up obsolete fields per object type', [
'object_type' => $objectType,
'team_id' => $this->team->getId(),
'obsolete_fields_count' => count($obsoletedNonSpecialFields),
]);
$chunks = array_chunk($obsoletedNonSpecialFields, self::DELETE_FIELDS_CHUNK_SIZE);
foreach ($chunks as $chunk) {
$this->getDispatcher()
->dispatch(new DeleteCrmFieldsJob(
teamId: $this->team->getId(),
objectType: $objectType,
crmProviderIds: $chunk,
));
}
}
}
protected function importFieldPicklistValue(
FieldRepository $fieldRepository,
Field $field,
Definition $fieldDefinition,
): void {
$this->logger->info('Import picklist values for field', [
'field_id' => $field->getId(),
'crm_provider_id' => $field->getCrmProviderId(),
'object_type' => $field->getObjectType(),
'team_id' => $this->team->getId(),
]);
$existingPicklistItemsCollection = $fieldRepository->getPicklistValues($field);
$existingPicklistItems = $existingPicklistItemsCollection->pluck('value')->toArray();
$updatedPicklistItems = [];
foreach ($fieldDefinition->getPicklistItems() as $eachPicklist) {
$updatedPicklistItems[] = $eachPicklist->getValue();
$fieldRepository->updatePicklistValue($field, $eachPicklist->export());
}
$notUpdatedPicklistItems = array_values(array_diff($existingPicklistItems, $updatedPicklistItems));
$this->logger->info('Picklist items updated', [
'field_id' => $field->getId(),
]);
// Nothing to delete, move to next field
if (empty($notUpdatedPicklistItems)) {
return;
}
// Delete the old values that are no longer used.
// Get IDs of the values to be deleted
$valuesToDelete = $fieldRepository->getPicklistValues($field, $notUpdatedPicklistItems);
if ($valuesToDelete->isNotEmpty()) {
$this->logger->info('Picklist items to be deleted', [
'field_id' => $field->getId(),
'values_to_delete' => $notUpdatedPicklistItems,
]);
// Remove Record type field value associations
$recordTypeFieldValuesRepository = app(RecordTypeFieldValuesRepository::class);
$recordTypeFieldValuesRepository->deleteForCrmFieldValueIds(
$valuesToDelete->pluck('id')->toArray(),
);
// Now safely delete from crm_field_values
foreach ($valuesToDelete->all() as $eachFieldValue) {
$eachFieldValue->delete();
}
}
}
private function updateSingleField(
FieldRepository $fieldRepository,
Definition $fieldData
): void {
$field = $this->upsertField($fieldRepository, $fieldData);
if ($fieldData->isPicklist()) {
$this->importFieldPicklistValue($fieldRepository, $field, $fieldData);
}
}
protected function upsertField(FieldRepository $fieldRepository, Definition $fieldData): Field
{
return $fieldRepository->upsertField(
configuration: $this->team->getCrmConfiguration(),
data: $fieldData->export(),
);
}
/**
* Gets the valid fields for a given Crm Object for a specific Crm object.
*
* @param string $crmObject The name of the target crm object. i.e. Account, Opportunity, Deal, etc.
*
* @return Definition[]
*/
protected function getFields(string $crmObject): array
{
$fields = [];
$transformer = $this->prepareTransformer($crmObject);
foreach ($this->getObjectFields($crmObject) as $row) {
/** @var DefinitionInterface&Definition $definition */
$definition = $transformer->transform($row);
$definitionFields = $this->handleDefinitionAlias($definition);
/**
* At least one field will be provided, potentially two, if the fields needs an alias, too.
*
* @var Definition $eachField
*/
foreach ($definitionFields as $eachField) {
$fields[] = $eachField;
}
}
return $fields;
}
private function handleDefinitionAlias(Definition $definition): array
{
$fields = [];
/** Overload special picklist items where applicable */
$this->decorateWithSpecialPicklistItems($definition);
$fields[] = $definition;
/**
* Alias fields are our internal representations for special fields
* that some CRMs support (ActivityType -> task.hs_activity_type).
*
* Aliases are shorthands that remap external to internal fields
*/
if ($this->shouldAddAliasFieldDefinition($definition)) {
$fields[] = $this->addAliasFieldDefinition($definition);
}
return $fields;
}
private function getDispatcher(): Dispatcher
{
if ($this->jobDispatcher === null) {
$this->jobDispatcher = app(Dispatcher::class);
}
return $this->jobDispatcher;
}
/**
* If applicable, decorate the field with Special Picklist items.
*
* Currently applicable for Hubspot only. The current implementations are placeholders for other CRMs.
*/
protected function decorateWithSpecialPicklistItems(Definition $fieldDefinition): void
{
// Nothing to do
}
protected function shouldAddAliasFieldDefinition(Definition $fieldDefinition): bool
{
return false;
}
protected function addAliasFieldDefinition(Definition $fieldDefinition): Definition
{
throw new RuntimeException('Method not implemented, nor required.');
}
/**
* Get a list of special fields that shouldn't be deleted, even if they do not remotely exist
*/
protected function getSpecialFieldsList(): array
{
return [];
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.3929521,"top":0.07581804,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.40292552,"top":0.07581804,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.4119016,"top":0.074221864,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.4192154,"top":0.074221864,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\CrmObjects\\ServiceTraits;\n\nuse Illuminate\\Bus\\Dispatcher;\nuse Jiminny\\Exceptions\\RuntimeException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\RecordTypeFieldValuesRepository;\nuse Jiminny\\Services\\Crm\\CrmObjects\\Fields\\Definition;\nuse Jiminny\\Services\\Crm\\CrmObjects\\Fields\\DefinitionInterface;\nuse Jiminny\\Services\\Crm\\CrmObjects\\Fields\\FieldTransformerInterface;\nuse Jiminny\\Services\\Crm\\CrmObjects\\Jobs\\DeleteCrmFieldsJob;\n\n/**\n * A shared trait that holds common synchronisation logic.\n *\n * Currently sharing sunchronisation logic between Hubspot and Salesforce\n */\ntrait SharedSyncFieldsTrait\n{\n private const int DELETE_FIELDS_CHUNK_SIZE = 100;\n\n private ?Dispatcher $jobDispatcher = null;\n\n abstract protected function getFieldTypes(): array;\n\n abstract protected function getObjectFields(string $objectType): array;\n\n abstract protected function prepareTransformer(string $crmObjectType): FieldTransformerInterface;\n\n public function listSupportedObjectTypes(): array\n {\n return $this->getFieldTypes();\n }\n\n /**\n * @throws SocialAccountTokenInvalidException\n */\n public function syncFields(): void\n {\n $this->logger->info('Syncing fields for CRM', [\n 'provider' => $this->getDisplayName(),\n 'team_id' => $this->team->getId(),\n ]);\n\n $fieldRepository = app(FieldRepository::class);\n\n foreach ($this->getFieldTypes() as $objectType) {\n $this->syncSingleObjectType($fieldRepository, $objectType);\n }\n }\n\n /**\n * @throws SocialAccountTokenInvalidException\n */\n protected function syncSingleObjectType(FieldRepository $fieldRepository, string $objectType): void\n {\n $this->logger->info('Sync fields per type', [\n 'object_type' => $objectType,\n 'team_id' => $this->team->getId(),\n ]);\n\n $updatedFields = [];\n $existingFields = [];\n\n $existingFieldsCollection = $fieldRepository->getAllFieldsForObjectType($this->team, $objectType);\n $existingFieldsCollection->map(function ($field) use (&$existingFields) {\n $existingFields[] = $field->getCrmProviderId();\n });\n\n $currentFields = $this->getFields($objectType);\n foreach ($currentFields as $fieldData) {\n $updatedFields[] = $fieldData->name;\n\n $this->updateSingleField($fieldRepository, $fieldData);\n }\n\n /** Those fields are removed from the crm, and we need to stop working with them as well.*/\n $obsoletedFields = array_diff($existingFields, $updatedFields);\n\n /**\n * There are potentially a few special fields, that may exist only locally.\n * And yet they must not be deleted, since they are used for special internal purposes.\n * i.e. meetingOutcome, activityType, disposition\n */\n $obsoletedNonSpecialFields = array_diff($obsoletedFields, $this->getSpecialFieldsList());\n\n if (! empty($obsoletedNonSpecialFields)) {\n $this->logger->info('Clean up obsolete fields per object type', [\n 'object_type' => $objectType,\n 'team_id' => $this->team->getId(),\n 'obsolete_fields_count' => count($obsoletedNonSpecialFields),\n ]);\n\n $chunks = array_chunk($obsoletedNonSpecialFields, self::DELETE_FIELDS_CHUNK_SIZE);\n foreach ($chunks as $chunk) {\n $this->getDispatcher()\n ->dispatch(new DeleteCrmFieldsJob(\n teamId: $this->team->getId(),\n objectType: $objectType,\n crmProviderIds: $chunk,\n ));\n }\n }\n }\n\n protected function importFieldPicklistValue(\n FieldRepository $fieldRepository,\n Field $field,\n Definition $fieldDefinition,\n ): void {\n $this->logger->info('Import picklist values for field', [\n 'field_id' => $field->getId(),\n 'crm_provider_id' => $field->getCrmProviderId(),\n 'object_type' => $field->getObjectType(),\n 'team_id' => $this->team->getId(),\n ]);\n\n $existingPicklistItemsCollection = $fieldRepository->getPicklistValues($field);\n $existingPicklistItems = $existingPicklistItemsCollection->pluck('value')->toArray();\n\n $updatedPicklistItems = [];\n foreach ($fieldDefinition->getPicklistItems() as $eachPicklist) {\n $updatedPicklistItems[] = $eachPicklist->getValue();\n $fieldRepository->updatePicklistValue($field, $eachPicklist->export());\n }\n\n $notUpdatedPicklistItems = array_values(array_diff($existingPicklistItems, $updatedPicklistItems));\n\n $this->logger->info('Picklist items updated', [\n 'field_id' => $field->getId(),\n ]);\n\n // Nothing to delete, move to next field\n if (empty($notUpdatedPicklistItems)) {\n return;\n }\n\n // Delete the old values that are no longer used.\n // Get IDs of the values to be deleted\n $valuesToDelete = $fieldRepository->getPicklistValues($field, $notUpdatedPicklistItems);\n\n if ($valuesToDelete->isNotEmpty()) {\n $this->logger->info('Picklist items to be deleted', [\n 'field_id' => $field->getId(),\n 'values_to_delete' => $notUpdatedPicklistItems,\n ]);\n\n // Remove Record type field value associations\n $recordTypeFieldValuesRepository = app(RecordTypeFieldValuesRepository::class);\n $recordTypeFieldValuesRepository->deleteForCrmFieldValueIds(\n $valuesToDelete->pluck('id')->toArray(),\n );\n\n // Now safely delete from crm_field_values\n foreach ($valuesToDelete->all() as $eachFieldValue) {\n $eachFieldValue->delete();\n }\n }\n }\n\n private function updateSingleField(\n FieldRepository $fieldRepository,\n Definition $fieldData\n ): void {\n $field = $this->upsertField($fieldRepository, $fieldData);\n\n if ($fieldData->isPicklist()) {\n $this->importFieldPicklistValue($fieldRepository, $field, $fieldData);\n }\n }\n\n protected function upsertField(FieldRepository $fieldRepository, Definition $fieldData): Field\n {\n return $fieldRepository->upsertField(\n configuration: $this->team->getCrmConfiguration(),\n data: $fieldData->export(),\n );\n }\n\n /**\n * Gets the valid fields for a given Crm Object for a specific Crm object.\n *\n * @param string $crmObject The name of the target crm object. i.e. Account, Opportunity, Deal, etc.\n *\n * @return Definition[]\n */\n protected function getFields(string $crmObject): array\n {\n $fields = [];\n $transformer = $this->prepareTransformer($crmObject);\n foreach ($this->getObjectFields($crmObject) as $row) {\n /** @var DefinitionInterface&Definition $definition */\n $definition = $transformer->transform($row);\n\n $definitionFields = $this->handleDefinitionAlias($definition);\n\n /**\n * At least one field will be provided, potentially two, if the fields needs an alias, too.\n *\n * @var Definition $eachField\n */\n foreach ($definitionFields as $eachField) {\n $fields[] = $eachField;\n }\n }\n\n return $fields;\n }\n\n private function handleDefinitionAlias(Definition $definition): array\n {\n $fields = [];\n /** Overload special picklist items where applicable */\n $this->decorateWithSpecialPicklistItems($definition);\n $fields[] = $definition;\n\n /**\n * Alias fields are our internal representations for special fields\n * that some CRMs support (ActivityType -> task.hs_activity_type).\n *\n * Aliases are shorthands that remap external to internal fields\n */\n if ($this->shouldAddAliasFieldDefinition($definition)) {\n $fields[] = $this->addAliasFieldDefinition($definition);\n }\n\n return $fields;\n }\n\n private function getDispatcher(): Dispatcher\n {\n if ($this->jobDispatcher === null) {\n $this->jobDispatcher = app(Dispatcher::class);\n }\n\n return $this->jobDispatcher;\n }\n\n /**\n * If applicable, decorate the field with Special Picklist items.\n *\n * Currently applicable for Hubspot only. The current implementations are placeholders for other CRMs.\n */\n protected function decorateWithSpecialPicklistItems(Definition $fieldDefinition): void\n {\n // Nothing to do\n }\n\n protected function shouldAddAliasFieldDefinition(Definition $fieldDefinition): bool\n {\n return false;\n }\n\n protected function addAliasFieldDefinition(Definition $fieldDefinition): Definition\n {\n throw new RuntimeException('Method not implemented, nor required.');\n }\n\n /**\n * Get a list of special fields that shouldn't be deleted, even if they do not remotely exist\n */\n protected function getSpecialFieldsList(): array\n {\n return [];\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\CrmObjects\\ServiceTraits;\n\nuse Illuminate\\Bus\\Dispatcher;\nuse Jiminny\\Exceptions\\RuntimeException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\RecordTypeFieldValuesRepository;\nuse Jiminny\\Services\\Crm\\CrmObjects\\Fields\\Definition;\nuse Jiminny\\Services\\Crm\\CrmObjects\\Fields\\DefinitionInterface;\nuse Jiminny\\Services\\Crm\\CrmObjects\\Fields\\FieldTransformerInterface;\nuse Jiminny\\Services\\Crm\\CrmObjects\\Jobs\\DeleteCrmFieldsJob;\n\n/**\n * A shared trait that holds common synchronisation logic.\n *\n * Currently sharing sunchronisation logic between Hubspot and Salesforce\n */\ntrait SharedSyncFieldsTrait\n{\n private const int DELETE_FIELDS_CHUNK_SIZE = 100;\n\n private ?Dispatcher $jobDispatcher = null;\n\n abstract protected function getFieldTypes(): array;\n\n abstract protected function getObjectFields(string $objectType): array;\n\n abstract protected function prepareTransformer(string $crmObjectType): FieldTransformerInterface;\n\n public function listSupportedObjectTypes(): array\n {\n return $this->getFieldTypes();\n }\n\n /**\n * @throws SocialAccountTokenInvalidException\n */\n public function syncFields(): void\n {\n $this->logger->info('Syncing fields for CRM', [\n 'provider' => $this->getDisplayName(),\n 'team_id' => $this->team->getId(),\n ]);\n\n $fieldRepository = app(FieldRepository::class);\n\n foreach ($this->getFieldTypes() as $objectType) {\n $this->syncSingleObjectType($fieldRepository, $objectType);\n }\n }\n\n /**\n * @throws SocialAccountTokenInvalidException\n */\n protected function syncSingleObjectType(FieldRepository $fieldRepository, string $objectType): void\n {\n $this->logger->info('Sync fields per type', [\n 'object_type' => $objectType,\n 'team_id' => $this->team->getId(),\n ]);\n\n $updatedFields = [];\n $existingFields = [];\n\n $existingFieldsCollection = $fieldRepository->getAllFieldsForObjectType($this->team, $objectType);\n $existingFieldsCollection->map(function ($field) use (&$existingFields) {\n $existingFields[] = $field->getCrmProviderId();\n });\n\n $currentFields = $this->getFields($objectType);\n foreach ($currentFields as $fieldData) {\n $updatedFields[] = $fieldData->name;\n\n $this->updateSingleField($fieldRepository, $fieldData);\n }\n\n /** Those fields are removed from the crm, and we need to stop working with them as well.*/\n $obsoletedFields = array_diff($existingFields, $updatedFields);\n\n /**\n * There are potentially a few special fields, that may exist only locally.\n * And yet they must not be deleted, since they are used for special internal purposes.\n * i.e. meetingOutcome, activityType, disposition\n */\n $obsoletedNonSpecialFields = array_diff($obsoletedFields, $this->getSpecialFieldsList());\n\n if (! empty($obsoletedNonSpecialFields)) {\n $this->logger->info('Clean up obsolete fields per object type', [\n 'object_type' => $objectType,\n 'team_id' => $this->team->getId(),\n 'obsolete_fields_count' => count($obsoletedNonSpecialFields),\n ]);\n\n $chunks = array_chunk($obsoletedNonSpecialFields, self::DELETE_FIELDS_CHUNK_SIZE);\n foreach ($chunks as $chunk) {\n $this->getDispatcher()\n ->dispatch(new DeleteCrmFieldsJob(\n teamId: $this->team->getId(),\n objectType: $objectType,\n crmProviderIds: $chunk,\n ));\n }\n }\n }\n\n protected function importFieldPicklistValue(\n FieldRepository $fieldRepository,\n Field $field,\n Definition $fieldDefinition,\n ): void {\n $this->logger->info('Import picklist values for field', [\n 'field_id' => $field->getId(),\n 'crm_provider_id' => $field->getCrmProviderId(),\n 'object_type' => $field->getObjectType(),\n 'team_id' => $this->team->getId(),\n ]);\n\n $existingPicklistItemsCollection = $fieldRepository->getPicklistValues($field);\n $existingPicklistItems = $existingPicklistItemsCollection->pluck('value')->toArray();\n\n $updatedPicklistItems = [];\n foreach ($fieldDefinition->getPicklistItems() as $eachPicklist) {\n $updatedPicklistItems[] = $eachPicklist->getValue();\n $fieldRepository->updatePicklistValue($field, $eachPicklist->export());\n }\n\n $notUpdatedPicklistItems = array_values(array_diff($existingPicklistItems, $updatedPicklistItems));\n\n $this->logger->info('Picklist items updated', [\n 'field_id' => $field->getId(),\n ]);\n\n // Nothing to delete, move to next field\n if (empty($notUpdatedPicklistItems)) {\n return;\n }\n\n // Delete the old values that are no longer used.\n // Get IDs of the values to be deleted\n $valuesToDelete = $fieldRepository->getPicklistValues($field, $notUpdatedPicklistItems);\n\n if ($valuesToDelete->isNotEmpty()) {\n $this->logger->info('Picklist items to be deleted', [\n 'field_id' => $field->getId(),\n 'values_to_delete' => $notUpdatedPicklistItems,\n ]);\n\n // Remove Record type field value associations\n $recordTypeFieldValuesRepository = app(RecordTypeFieldValuesRepository::class);\n $recordTypeFieldValuesRepository->deleteForCrmFieldValueIds(\n $valuesToDelete->pluck('id')->toArray(),\n );\n\n // Now safely delete from crm_field_values\n foreach ($valuesToDelete->all() as $eachFieldValue) {\n $eachFieldValue->delete();\n }\n }\n }\n\n private function updateSingleField(\n FieldRepository $fieldRepository,\n Definition $fieldData\n ): void {\n $field = $this->upsertField($fieldRepository, $fieldData);\n\n if ($fieldData->isPicklist()) {\n $this->importFieldPicklistValue($fieldRepository, $field, $fieldData);\n }\n }\n\n protected function upsertField(FieldRepository $fieldRepository, Definition $fieldData): Field\n {\n return $fieldRepository->upsertField(\n configuration: $this->team->getCrmConfiguration(),\n data: $fieldData->export(),\n );\n }\n\n /**\n * Gets the valid fields for a given Crm Object for a specific Crm object.\n *\n * @param string $crmObject The name of the target crm object. i.e. Account, Opportunity, Deal, etc.\n *\n * @return Definition[]\n */\n protected function getFields(string $crmObject): array\n {\n $fields = [];\n $transformer = $this->prepareTransformer($crmObject);\n foreach ($this->getObjectFields($crmObject) as $row) {\n /** @var DefinitionInterface&Definition $definition */\n $definition = $transformer->transform($row);\n\n $definitionFields = $this->handleDefinitionAlias($definition);\n\n /**\n * At least one field will be provided, potentially two, if the fields needs an alias, too.\n *\n * @var Definition $eachField\n */\n foreach ($definitionFields as $eachField) {\n $fields[] = $eachField;\n }\n }\n\n return $fields;\n }\n\n private function handleDefinitionAlias(Definition $definition): array\n {\n $fields = [];\n /** Overload special picklist items where applicable */\n $this->decorateWithSpecialPicklistItems($definition);\n $fields[] = $definition;\n\n /**\n * Alias fields are our internal representations for special fields\n * that some CRMs support (ActivityType -> task.hs_activity_type).\n *\n * Aliases are shorthands that remap external to internal fields\n */\n if ($this->shouldAddAliasFieldDefinition($definition)) {\n $fields[] = $this->addAliasFieldDefinition($definition);\n }\n\n return $fields;\n }\n\n private function getDispatcher(): Dispatcher\n {\n if ($this->jobDispatcher === null) {\n $this->jobDispatcher = app(Dispatcher::class);\n }\n\n return $this->jobDispatcher;\n }\n\n /**\n * If applicable, decorate the field with Special Picklist items.\n *\n * Currently applicable for Hubspot only. The current implementations are placeholders for other CRMs.\n */\n protected function decorateWithSpecialPicklistItems(Definition $fieldDefinition): void\n {\n // Nothing to do\n }\n\n protected function shouldAddAliasFieldDefinition(Definition $fieldDefinition): bool\n {\n return false;\n }\n\n protected function addAliasFieldDefinition(Definition $fieldDefinition): Definition\n {\n throw new RuntimeException('Method not implemented, nor required.');\n }\n\n /**\n * Get a list of special fields that shouldn't be deleted, even if they do not remotely exist\n */\n protected function getSpecialFieldsList(): array\n {\n return [];\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","depth":4,"bounds":{"left":0.44547874,"top":0.09736632,"width":0.29022607,"height":0.8818835},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Helpers;\n\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\n\n/**\n * A collection of DB-related internal functionalities or all CRMs.\n */\nclass CrmHelperRepository\n{\n public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory\n {\n /** @var ?PlaybookCategory */\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->orderBy('id', 'desc')\n ->first();\n }\n\n public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue\n {\n /** @var ?FieldValue */\n return $activityField->values()\n ->where('label', $categoryName)\n ->first();\n }\n\n public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool\n {\n return $activityField->values()\n ->where('label', $categoryName)\n ->exists();\n }\n\n public function hasFeature(Activity $activity, FeatureEnum $featureName): bool\n {\n return $activity->getUser()\n ->getTeam()\n ->hasFeature($featureName);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
6897317249831886111
|
-4069264098828738957
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\CrmObjects\ServiceTraits;
use Illuminate\Bus\Dispatcher;
use Jiminny\Exceptions\RuntimeException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Models\Crm\Field;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\RecordTypeFieldValuesRepository;
use Jiminny\Services\Crm\CrmObjects\Fields\Definition;
use Jiminny\Services\Crm\CrmObjects\Fields\DefinitionInterface;
use Jiminny\Services\Crm\CrmObjects\Fields\FieldTransformerInterface;
use Jiminny\Services\Crm\CrmObjects\Jobs\DeleteCrmFieldsJob;
/**
* A shared trait that holds common synchronisation logic.
*
* Currently sharing sunchronisation logic between Hubspot and Salesforce
*/
trait SharedSyncFieldsTrait
{
private const int DELETE_FIELDS_CHUNK_SIZE = 100;
private ?Dispatcher $jobDispatcher = null;
abstract protected function getFieldTypes(): array;
abstract protected function getObjectFields(string $objectType): array;
abstract protected function prepareTransformer(string $crmObjectType): FieldTransformerInterface;
public function listSupportedObjectTypes(): array
{
return $this->getFieldTypes();
}
/**
* @throws SocialAccountTokenInvalidException
*/
public function syncFields(): void
{
$this->logger->info('Syncing fields for CRM', [
'provider' => $this->getDisplayName(),
'team_id' => $this->team->getId(),
]);
$fieldRepository = app(FieldRepository::class);
foreach ($this->getFieldTypes() as $objectType) {
$this->syncSingleObjectType($fieldRepository, $objectType);
}
}
/**
* @throws SocialAccountTokenInvalidException
*/
protected function syncSingleObjectType(FieldRepository $fieldRepository, string $objectType): void
{
$this->logger->info('Sync fields per type', [
'object_type' => $objectType,
'team_id' => $this->team->getId(),
]);
$updatedFields = [];
$existingFields = [];
$existingFieldsCollection = $fieldRepository->getAllFieldsForObjectType($this->team, $objectType);
$existingFieldsCollection->map(function ($field) use (&$existingFields) {
$existingFields[] = $field->getCrmProviderId();
});
$currentFields = $this->getFields($objectType);
foreach ($currentFields as $fieldData) {
$updatedFields[] = $fieldData->name;
$this->updateSingleField($fieldRepository, $fieldData);
}
/** Those fields are removed from the crm, and we need to stop working with them as well.*/
$obsoletedFields = array_diff($existingFields, $updatedFields);
/**
* There are potentially a few special fields, that may exist only locally.
* And yet they must not be deleted, since they are used for special internal purposes.
* i.e. meetingOutcome, activityType, disposition
*/
$obsoletedNonSpecialFields = array_diff($obsoletedFields, $this->getSpecialFieldsList());
if (! empty($obsoletedNonSpecialFields)) {
$this->logger->info('Clean up obsolete fields per object type', [
'object_type' => $objectType,
'team_id' => $this->team->getId(),
'obsolete_fields_count' => count($obsoletedNonSpecialFields),
]);
$chunks = array_chunk($obsoletedNonSpecialFields, self::DELETE_FIELDS_CHUNK_SIZE);
foreach ($chunks as $chunk) {
$this->getDispatcher()
->dispatch(new DeleteCrmFieldsJob(
teamId: $this->team->getId(),
objectType: $objectType,
crmProviderIds: $chunk,
));
}
}
}
protected function importFieldPicklistValue(
FieldRepository $fieldRepository,
Field $field,
Definition $fieldDefinition,
): void {
$this->logger->info('Import picklist values for field', [
'field_id' => $field->getId(),
'crm_provider_id' => $field->getCrmProviderId(),
'object_type' => $field->getObjectType(),
'team_id' => $this->team->getId(),
]);
$existingPicklistItemsCollection = $fieldRepository->getPicklistValues($field);
$existingPicklistItems = $existingPicklistItemsCollection->pluck('value')->toArray();
$updatedPicklistItems = [];
foreach ($fieldDefinition->getPicklistItems() as $eachPicklist) {
$updatedPicklistItems[] = $eachPicklist->getValue();
$fieldRepository->updatePicklistValue($field, $eachPicklist->export());
}
$notUpdatedPicklistItems = array_values(array_diff($existingPicklistItems, $updatedPicklistItems));
$this->logger->info('Picklist items updated', [
'field_id' => $field->getId(),
]);
// Nothing to delete, move to next field
if (empty($notUpdatedPicklistItems)) {
return;
}
// Delete the old values that are no longer used.
// Get IDs of the values to be deleted
$valuesToDelete = $fieldRepository->getPicklistValues($field, $notUpdatedPicklistItems);
if ($valuesToDelete->isNotEmpty()) {
$this->logger->info('Picklist items to be deleted', [
'field_id' => $field->getId(),
'values_to_delete' => $notUpdatedPicklistItems,
]);
// Remove Record type field value associations
$recordTypeFieldValuesRepository = app(RecordTypeFieldValuesRepository::class);
$recordTypeFieldValuesRepository->deleteForCrmFieldValueIds(
$valuesToDelete->pluck('id')->toArray(),
);
// Now safely delete from crm_field_values
foreach ($valuesToDelete->all() as $eachFieldValue) {
$eachFieldValue->delete();
}
}
}
private function updateSingleField(
FieldRepository $fieldRepository,
Definition $fieldData
): void {
$field = $this->upsertField($fieldRepository, $fieldData);
if ($fieldData->isPicklist()) {
$this->importFieldPicklistValue($fieldRepository, $field, $fieldData);
}
}
protected function upsertField(FieldRepository $fieldRepository, Definition $fieldData): Field
{
return $fieldRepository->upsertField(
configuration: $this->team->getCrmConfiguration(),
data: $fieldData->export(),
);
}
/**
* Gets the valid fields for a given Crm Object for a specific Crm object.
*
* @param string $crmObject The name of the target crm object. i.e. Account, Opportunity, Deal, etc.
*
* @return Definition[]
*/
protected function getFields(string $crmObject): array
{
$fields = [];
$transformer = $this->prepareTransformer($crmObject);
foreach ($this->getObjectFields($crmObject) as $row) {
/** @var DefinitionInterface&Definition $definition */
$definition = $transformer->transform($row);
$definitionFields = $this->handleDefinitionAlias($definition);
/**
* At least one field will be provided, potentially two, if the fields needs an alias, too.
*
* @var Definition $eachField
*/
foreach ($definitionFields as $eachField) {
$fields[] = $eachField;
}
}
return $fields;
}
private function handleDefinitionAlias(Definition $definition): array
{
$fields = [];
/** Overload special picklist items where applicable */
$this->decorateWithSpecialPicklistItems($definition);
$fields[] = $definition;
/**
* Alias fields are our internal representations for special fields
* that some CRMs support (ActivityType -> task.hs_activity_type).
*
* Aliases are shorthands that remap external to internal fields
*/
if ($this->shouldAddAliasFieldDefinition($definition)) {
$fields[] = $this->addAliasFieldDefinition($definition);
}
return $fields;
}
private function getDispatcher(): Dispatcher
{
if ($this->jobDispatcher === null) {
$this->jobDispatcher = app(Dispatcher::class);
}
return $this->jobDispatcher;
}
/**
* If applicable, decorate the field with Special Picklist items.
*
* Currently applicable for Hubspot only. The current implementations are placeholders for other CRMs.
*/
protected function decorateWithSpecialPicklistItems(Definition $fieldDefinition): void
{
// Nothing to do
}
protected function shouldAddAliasFieldDefinition(Definition $fieldDefinition): bool
{
return false;
}
protected function addAliasFieldDefinition(Definition $fieldDefinition): Definition
{
throw new RuntimeException('Method not implemented, nor required.');
}
/**
* Get a list of special fields that shouldn't be deleted, even if they do not remotely exist
*/
protected function getSpecialFieldsList(): array
{
return [];
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Helpers;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
/**
* A collection of DB-related internal functionalities or all CRMs.
*/
class CrmHelperRepository
{
public function getPlaybookCategory(Playbook $playbook, string $categoryName): ?PlaybookCategory
{
/** @var ?PlaybookCategory */
return $playbook->categories()
->where('name', trim($categoryName))
->orderBy('id', 'desc')
->first();
}
public function getActivityFieldValueByName(Field $activityField, string $categoryName): ?FieldValue
{
/** @var ?FieldValue */
return $activityField->values()
->where('label', $categoryName)
->first();
}
public function existsActivityFieldValueByName(Field $activityField, string $categoryName): bool
{
return $activityField->values()
->where('label', $categoryName)
->exists();
}
public function hasFeature(Activity $activity, FeatureEnum $featureName): bool
{
return $activity->getUser()
->getTeam()
->hasFeature($featureName);
}
}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
65468
|
2307
|
10
|
2026-05-21T07:40:07.876513+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-21/1779 /Users/lukas/.screenpipe/data/data/2026-05-21/1779349207876_m2.jpg...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>74 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_selected":false,"is_expanded":false}]...
|
-7429716278976468786
|
-8636355650190325311
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
slackFV [EMAIL]=.phounit.result.cacheE .prettierignore= windsurtrulesphpde neloer.onophpide heloer_models.ohophp artisanM'CLAUDE.mdcomooser.isoncomooser.lockdependency-checker.json8 dev ison= ids tytl=infection.ison.distMLINSTAlI.mdMLINTERNAI WERHOOK SFTUP mdEjiminny_storageMiliconsos mdllM Makefile1рackace-lock. sonE phpstan.neon.dist= phostan-baseline.neon<> phpunit.xmlTe raw sal query.saM+ README.mdsô sonar-proiect propertiesE test.ov‹> Untitled Diaaram.xmliusvetur.confio.isM+ WEBHOOK FILTERING_IMPLEMENTATION.mo>1h External Librariesv =° Scratches and Consolesv batabase Consolesv AEU# console (EUlI DEAL RISKS (SU1A DITEUlA EU (EU]v Ajiminny@localhostA console (jiminny@localhost]# Di [liminny@localhostlA HS local [iiminny@localhostlA SF ['iiminny@localhost]& zoho dev [iiminny@localhost]V & PRODA console [PROD]& console 1 [PROD1LDIIPRODCActivityController.ong© ConvertLeadActivities.php= laravel.log4 SF jiminny@localhost]4 HS_local [jiminny@localhost]& console (PROD] X# console [euyLeadkepository.ong© PurgeLookupCache.php© SyncPlanhat.phpo synerorlannatpnpA console [STAGING]AcuivityLeadConverted.php© UserAutomatedreporscontroller.phpx© PlaybackController.php)Inteqrationapp/service.onoC) LeadConverted.ono570571C) CreateCommentedEvent.php(C) CreateSmsSentEvent.phpC) PlanhatActivityListener.php© AskAnythingPromptService.php572(C) AutomatedReportsRepositorv.php© AutomatedReportsCommand.phpphp api_v2.phpC) RequestGenerateReportJob.php573574© AutomatedReportResult.php(C) AutomatedReport.oho575use Jiminny \Services \Kiosk \AutomatedReports \ReportSortDirection;A1422 ^ v 576use Jiminny \Services\PlanhatService;use ectumtnace hutp kequestuse Inrowable,class UserAutomatedReportsController extends Controllenpublic const int RESULTS PER_ PAGE = 25:public const string SORT COLUMN = 'sort column':public const strina SORT DIRECTION = "sort direction':public function constructprivate readonly AutomatedReportsRepository $automatedReportsRepository.private readonly AutomatedRenortsService SautomatedRenortsServicelorivate readoni.v AniResponseService samiResponseServi.ce.orivate readoni.v Resnonse Sresnonse.private readonly PlanhatService $planhatService1...poST lanilv1lautomated-renorts/interest 1usadepublic function trackInterest(Request $request): JsonResponse(...}* Othnows ApplicationException58(09 >GET /api/v1/automated-reportspublic function list(Request Srequest): JsonResponse(...}125 0)DELETE/api/vl/automated-reports/kuuidpublic function delete(Request Srequest. string Suuid): JsonResponsef...} -609610--611612613616Tx: AutovSo jiminny vCONCAT(u.id, CASE WHEN U.id = t.owner_id THEN' (owner)' ELSE'' END) AS USEr_i041 A1 A40 V65 ^sa.*t.owner_id FROM social_accounts saNoun usens u on u.ide sa.sociablle 1diJOIN teams t 1..n<->1: on t.id = u.team_idWHERE u.team_id = 581 and sa.provider = 'salesforce';SELECT * FROM automated_report_results order by id desc;select * from features;select * from team_features where feature_id = 40;select * from teams where id = 556:select * trom automated reports:where id = 54: # 4fdd41f6-dcf0-30d0-b339-7345381b6044|"pat", "podcast"SELECT * FROM automated report results WHERE uuid to bin( '822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;select * from automated_report_results order by id desc;SELECT * FROMWHERE id = 1919:select * fromautomated report results WHERE report id = 54:select * from opportunities where id = 7594349:SELECT * FROM teams WHERE name LIKE '%Lesg': # 711. 692. [EMAIL] * from playbooks where team_id = 711; # event 226147SELEd * FROM Dlavbook catedonies WHERE Dlavbook 1d = 55151SELECT * FROM crm_fields WHERE crm_configuration_id = 692 and object_type = 'event':SELECT * SROM eom fields WHEREI1d = 2261471SELECT * FROM crm_field_values WHERE crm_field_id = 226147;SELECT * FROM crm_configurations WHERE id = 692;SELSCTCONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '• END) AS user_id,v.emailsa.*,t.owner id FROM social accounts saJOIN users u on v.id = sa.sociable idJOIN teams t 1..n<->1: on t.id = u.team idWHERE U.team_id = 711 and sa.provider = 'salesforce";SELECT * FROM crm profiles cp JOIN users u 1..n<->1: on u.id = co.user id WHERE u.team_id = 711:select * from leadsselect * from calendarsSELECTS 0 hllsupoont Dally • In 4h 40m100% 52• Inu z1 May 10.10.34AskJiminnyReportActivityServiceTestvCascadePlaybook Categorie+0 ..connected. How isi. Can we vali eoneactivity tyee nith orit cabest aeeiewmane o, W dati anwsyggesinsingrow hohow to distinguishThoughts68 Fast Context How are playbook_categories populated and synced from crm_fields / crm_field_values... in 4.14s >Explored 4 files and searched 5 queriesRead ImportActivitvTypes.php #L95-104Searched olavbook cateaories in databaselmiarations (4) >egories|playbook_categories.*create in database/migrations (0)searched playoook_categor in database/migrations (<)Searched activity type in database/migrations (4)SurtingAsk anvthina (*4L)@ Codo Caudo Onue 17 ModiumNN Windeurf Toame 504.60...
|
65466
|
NULL
|
NULL
|
NULL
|