|
43591
|
1590
|
25
|
2026-05-14T13:01:53.488336+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763713488_m2.jpg...
|
Slack
|
Aneliya Angelova (DM) - Jiminny Inc - 3 new items Aneliya Angelova (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Aneliya Angelova
Apr 28th at 5:16:20 PM
5:16 PM
и за двете ли говориш
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
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
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:51:36 PM
2:51
трябва да се за всички, някъде не се ли попълва
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:52:10 PM
2:52
при зохо май беше hardcoded но май и там си връщаха две категории
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 4:00:37 PM
4:00 PM
Лукаш имаш ли време да се чуем за тестването на
https://jiminny.atlassian.net/browse/JY-20725
https://jiminny.atlassian.net/browse/JY-20725
Jira Cloud
Jira Cloud
Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise
[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts
Bug JY-20725 in Jira Cloud
Preview in Slack
Status
Ready for QA
Priority
Medium
Assignee
Aneliya Angelova
As of today at 4:00 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug JY-20725
View conversations
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
20 results
Channel...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.27593085,"top":1.0,"width":0.011968086,"height":-0.058260202},"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,"bounds":{"left":0.30718085,"top":1.0,"width":0.018949468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.01761968,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.02925532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.3587101,"top":1.0,"width":0.0026595744,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.024268618,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.043882977,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.04454787,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.022273935,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.012300532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.010638298,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.034574468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.027593086,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.025930852,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.016289894,"height":-0.09177971},"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":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","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,"bounds":{"left":0.3723404,"top":1.0,"width":0.030917553,"height":-0.09177971},"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":"Add canvas","depth":18,"bounds":{"left":0.40425533,"top":1.0,"width":0.034242023,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.43949467,"top":1.0,"width":0.020944148,"height":-0.09177971},"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":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.46176863,"top":1.0,"width":0.010638298,"height":-0.09177971},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:16:20 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:16 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и за двете ли говориш","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:16:54 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:16 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами ще го деплойна но ако нещо гръмне","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:04 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"аа разбрахте","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:07 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:14 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Галя каза че не се използва фичъра","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:22 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и няма проблем да гръмне","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:24:41 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:24 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш за Hubspot за синковете вече се използва тази команда нали?","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"crm:sync-hubspot-objects","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:32:50 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:32 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"да крон я пуска през 5 мин","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:30:26 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"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":25,"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":25,"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":25,"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":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"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":25,"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":25,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:30:45 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"при останалите CRMi трябва ръчно да се въведат","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:47:56 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:47 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:48:14 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:48","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами не знам по принцип се вика при всички","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:51:36 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:51","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"трябва да се за всички, някъде не се ли попълва","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:52:10 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"при зохо май беше hardcoded но май и там си връщаха две категории","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"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":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:00:37 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:00 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш имаш ли време да се чуем за тестването на","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20725","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20725","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Jira Cloud","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20725 in Jira Cloud","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Status","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ready for QA","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Priority","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Medium","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Assignee","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"As of today at 4:00 PM","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Refresh","depth":27,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open in Jira","depth":27,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"✨ Summarise","depth":27,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Open in browser","depth":26,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Open","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Share Bug JY-20725","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View conversations","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More actions","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"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":25,"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":25,"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":25,"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":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"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":25,"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":25,"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":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"20 results","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Channel","depth":11,"on_screen":false,"role_description":"text"}]...
|
852946530903914021
|
-1568565942158046380
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Aneliya Angelova
Apr 28th at 5:16:20 PM
5:16 PM
и за двете ли говориш
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
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
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:51:36 PM
2:51
трябва да се за всички, някъде не се ли попълва
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:52:10 PM
2:52
при зохо май беше hardcoded но май и там си връщаха две категории
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 4:00:37 PM
4:00 PM
Лукаш имаш ли време да се чуем за тестването на
https://jiminny.atlassian.net/browse/JY-20725
https://jiminny.atlassian.net/browse/JY-20725
Jira Cloud
Jira Cloud
Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise
[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts
Bug JY-20725 in Jira Cloud
Preview in Slack
Status
Ready for QA
Priority
Medium
Assignee
Aneliya Angelova
As of today at 4:00 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug JY-20725
View conversations
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
20 results
Channel
• Goodle geminiPlatform Sprint 4 02 - PlatformJY-20903 Update activity sta XSRD-6849) Recorded call doesUsage | Windsurf4(SRD-68481 Sidekick SMS issue1.lY-208911 Sidekick SMS issueJY-20891 add support for seconcR (SRD-6849) Recorded call does r[JY-20903] Recorded call does r[SRD-6853] Moxso - Potential d@ JY-20903 Update activity stage* Configure SSH access to multiple c* Useful commands - EngineeringA 1y-20004 Eiv HndateAotivituFlad(JY-20904) Fix UpdateActivityElaSJliminnv- New Tabhow to unpin slackmessaceUnpinning a message in Slack is straightforward,though the steps vary slightly depending onwhether you are using the desktop app or themobile version.On Desktop (Mac/Windows/Web)1. Open the channel or DM where themessage is pinned.2. Click the Pinned icon (the thumbtack)located just below the channel name orheader at the top of the screen. This opensa sidebar showing all pinned items.3. Find the message you want to unpin andhover over It4. Click the "X" icon that appears next to themessage in the sidebar, then click Removeto confirm.Alternative Method: Find themessade direct v in the chat historv.click the three-dot icon (Moreactions on the message, ano selectUnpin from channel.Enter a prompt for GeminiFastvAl lt can make mistakes so double check it Your orivacv &. G.Summarize pagejiminny / app &<> Code%? Pull requests 29G. Agents Actions M Wiki ® Security and qualityInsights ộ Settings© On April 24 we'll start using GitHub Copilot interaction data for Al model training unless you opt out. Review this update and manage your preferences in your GitHub account settingsJY-20903 Update activity stage when opportunity is changed #12077 •LakyLak wants to merge 2 commits into master from JY-20903-update_activity-stage-on-opportunity-changeW Conversation4• CommitsiE Checks 2Files changed 1• Filter files..~ E app/ModelsActivity.phpapp/Models/Activity-php d ++C0 -2119,12 +2119,14 @ public function updateActivityCrmData(array srecords): void2119sthis->account_id = saccount->id;21202121HEEEif (Sthis->stage_id === null && Sstage) €Sthis->stage_id = sstage->id;2127if (Sopportunity && Sthis->opportunitv id I== Sopportunitv->id) {sthis->opportunity_id = sopportunity->id;2128212921301if (Sopportunity && Sthis->value !== Sopportunity-›value) {2119212021212122212321282220 :213021312132100% .• Inu 14 May 10:01:03Q Type D to search• Checks pending• 0 I 1 viewedcode-+6 -4 00022Submit review - (ộ3+6 -4 manaa [ Viewed@ ..Sthis->account_id = Saccount->id:if (Sopportunity && $this->opportunity_id !== Sopportunity->id) {sthis->opportunity_id = sopportunity->id;// Reset stage_id when opportunity changes to avoid stale stage from previous opportunity matchsthis->stage_id = $stage?->id;if (Sthis->stage id === null && Sstage) ‹sthis->stage_id = sstage->id;if (Sopportunity && Sthis-›value !== Sopportunity->value) {...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43592
|
1589
|
25
|
2026-05-14T13:01:53.942483+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763713942_m1.jpg...
|
Slack
|
Aneliya Angelova (DM) - Jiminny Inc - 3 new items Aneliya Angelova (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Aneliya Angelova
Apr 28th at 5:16:20 PM
5:16 PM
и за двете ли говориш
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
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
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:51:36 PM
2:51
трябва да се за всички, някъде не се ли попълва
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:52:10 PM
2:52
при зохо май беше hardcoded но май и там си връщаха две категории
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 4:00:37 PM
4:00 PM
Лукаш имаш ли време да се чуем за тестването на
https://jiminny.atlassian.net/browse/JY-20725
https://jiminny.atlassian.net/browse/JY-20725
Jira Cloud
Jira Cloud
Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise
[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts
Bug JY-20725 in Jira Cloud
Preview in Slack
Status
Ready for QA
Priority
Medium
Assignee
Aneliya Angelova
As of today at 4:00 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug JY-20725
View conversations
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
20 results
Channel...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.011805556,"top":0.08111111,"width":0.025,"height":0.04},"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.00625,"top":0.14,"width":0.036111113,"height":0.075555556},"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.013888889,"top":0.19222222,"width":0.020833334,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.00625,"top":0.21555555,"width":0.036111113,"height":0.075555556},"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.015972223,"top":0.26777777,"width":0.016666668,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.00625,"top":0.2911111,"width":0.036111113,"height":0.075555556},"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.011111111,"top":0.34333333,"width":0.027083334,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.011111111,"top":0.34333333,"width":0.0055555557,"height":0.015555556}},{"char_start":1,"char_count":7,"bounds":{"left":0.015972223,"top":0.34333333,"width":0.022222223,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.00625,"top":0.36666667,"width":0.036111113,"height":0.075555556},"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.016666668,"top":0.4188889,"width":0.015972223,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.016666668,"top":0.4188889,"width":0.004166667,"height":0.015555556}},{"char_start":1,"char_count":4,"bounds":{"left":0.020833334,"top":0.4188889,"width":0.011805556,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.00625,"top":0.4422222,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.49444443,"width":0.018055556,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.00625,"top":0.5177778,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.57,"width":0.01875,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.039583333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.036805555,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.06111111,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.18472221,"top":0.12777779,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.050694443,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.09166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.093055554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.046527777,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.025694445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.022222223,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.072222225,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.057638887,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.054166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.034027778,"height":0.007777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.088194445,"top":0.14666666,"width":0.048611112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.072916664,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":15,"bounds":{"left":0.094444446,"top":0.17777778,"width":0.06666667,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.088194445,"top":0.20888889,"width":0.08055556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.088194445,"top":0.24,"width":0.035416666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.088194445,"top":0.2711111,"width":0.036805555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.05138889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":11,"bounds":{"left":0.093055554,"top":0.30222222,"width":0.045833334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.088194445,"top":0.33333334,"width":0.036111113,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.088194445,"top":0.36444443,"width":0.05138889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.094444446,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.004166667,"height":0.02}},{"char_start":1,"char_count":20,"bounds":{"left":0.09236111,"top":0.39555556,"width":0.09861111,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.088194445,"top":0.46888888,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.088194445,"top":0.5,"width":0.055555556,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.5,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.094444446,"top":0.5,"width":0.048611112,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.088194445,"top":0.5311111,"width":0.07361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.088194445,"top":0.56222224,"width":0.079166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"bounds":{"left":0.088194445,"top":0.5933333,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.6244444,"width":0.07152778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"bounds":{"left":0.088194445,"top":0.65555555,"width":0.06736111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.088194445,"top":0.68666667,"width":0.06666667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.088194445,"top":0.7177778,"width":0.060416665,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.7488889,"width":0.07986111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"bounds":{"left":0.088194445,"top":0.78,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.088194445,"top":0.8111111,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.15555556,"top":0.8111111,"width":0.013194445,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.15555556,"top":0.8111111,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":2,"bounds":{"left":0.16041666,"top":0.8111111,"width":0.011805556,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.088194445,"top":0.8844444,"width":0.025694445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.088194445,"top":0.91555554,"width":0.045833334,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.21319444,"top":0.12777779,"width":0.06458333,"height":0.04222222},"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.2326389,"top":0.14,"width":0.039583333,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.27986112,"top":0.12777779,"width":0.07152778,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"bounds":{"left":0.29930556,"top":0.14,"width":0.046527777,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.35347223,"top":0.12777779,"width":0.04375,"height":0.04222222},"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.37291667,"top":0.14,"width":0.01875,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.37291667,"top":0.14,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":4,"bounds":{"left":0.3784722,"top":0.14,"width":0.013194445,"height":0.017777778}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.4,"top":0.12777779,"width":0.022222223,"height":0.04222222},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5465278,"top":0.16111112,"width":0.10555556,"height":0.0011111111},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.08125,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:16:20 PM","depth":23,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:16 PM","depth":24,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и за двете ли говориш","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.10763889,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:16:54 PM","depth":23,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:16 PM","depth":24,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами ще го деплойна но ако нещо гръмне","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.19791667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.08125,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:04 PM","depth":23,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17 PM","depth":24,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"аа разбрахте","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.061805554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:07 PM","depth":24,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:14 PM","depth":24,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Галя каза че не се използва фичъра","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.16875,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:22 PM","depth":24,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и няма проблем да гръмне","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.12916666,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5472222,"top":0.17666666,"width":0.104166664,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.08125,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:24:41 PM","depth":23,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:24 PM","depth":24,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш за Hubspot за синковете вече се използва тази команда нали?","depth":24,"bounds":{"left":0.24652778,"top":0.16222222,"width":0.3326389,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"crm:sync-hubspot-objects","depth":25,"bounds":{"left":0.24930556,"top":0.19,"width":0.12013889,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.21777777,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.22,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:32:50 PM","depth":23,"bounds":{"left":0.31666666,"top":0.22333333,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:32 PM","depth":24,"bounds":{"left":0.31666666,"top":0.22333333,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"да крон я пуска през 5 мин","depth":24,"bounds":{"left":0.24652778,"top":0.24444444,"width":0.12986112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5729167,"top":0.28666666,"width":0.05277778,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.33,"width":0.08125,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.33222222,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:30:26 PM","depth":23,"bounds":{"left":0.33333334,"top":0.33555555,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30 PM","depth":24,"bounds":{"left":0.33333334,"top":0.33555555,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?","depth":24,"bounds":{"left":0.24652778,"top":0.35666665,"width":0.5069444,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8041667,"top":0.3122222,"width":0.022222223,"height":0.035555556},"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":25,"bounds":{"left":0.8263889,"top":0.3122222,"width":0.022222223,"height":0.035555556},"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":25,"bounds":{"left":0.8486111,"top":0.3122222,"width":0.022222223,"height":0.035555556},"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":25,"bounds":{"left":0.87083334,"top":0.3122222,"width":0.022222223,"height":0.035555556},"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":25,"bounds":{"left":0.89305556,"top":0.3122222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"bounds":{"left":0.9152778,"top":0.3122222,"width":0.022222223,"height":0.035555556},"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":25,"bounds":{"left":0.9375,"top":0.3122222,"width":0.022222223,"height":0.035555556},"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":25,"bounds":{"left":0.9597222,"top":0.3122222,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:30:45 PM","depth":24,"bounds":{"left":0.22430556,"top":0.39333335,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30","depth":25,"bounds":{"left":0.22430556,"top":0.39333335,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"при останалите CRMi трябва ръчно да се въведат","depth":24,"bounds":{"left":0.24652778,"top":0.39,"width":0.24166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.4211111,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.42333335,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:47:56 PM","depth":23,"bounds":{"left":0.31666666,"top":0.42666668,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:47 PM","depth":24,"bounds":{"left":0.31666666,"top":0.42666668,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти","depth":24,"bounds":{"left":0.24652778,"top":0.44777778,"width":0.03888889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:48:14 PM","depth":24,"bounds":{"left":0.22430556,"top":0.48444444,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:48","depth":25,"bounds":{"left":0.22430556,"top":0.48444444,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами не знам по принцип се вика при всички","depth":24,"bounds":{"left":0.24652778,"top":0.4811111,"width":0.21111111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:51:36 PM","depth":24,"bounds":{"left":0.22430556,"top":0.5177778,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:51","depth":25,"bounds":{"left":0.22430556,"top":0.5177778,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"трябва да се за всички, някъде не се ли попълва","depth":24,"bounds":{"left":0.24652778,"top":0.5144445,"width":0.2326389,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:52:10 PM","depth":24,"bounds":{"left":0.22430556,"top":0.5511111,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"bounds":{"left":0.22430556,"top":0.5511111,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"при зохо май беше hardcoded но май и там си връщаха две категории","depth":24,"bounds":{"left":0.24652778,"top":0.5477778,"width":0.3361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"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.96458334,"top":0.5655556,"width":0.01875,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.5788889,"width":0.08125,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.58111113,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:00:37 PM","depth":23,"bounds":{"left":0.33333334,"top":0.58444446,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:00 PM","depth":24,"bounds":{"left":0.33333334,"top":0.58444446,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш имаш ли време да се чуем за тестването на","depth":24,"bounds":{"left":0.24652778,"top":0.60555553,"width":0.24722221,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20725","depth":24,"bounds":{"left":0.49305555,"top":0.60555553,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20725","depth":25,"bounds":{"left":0.49305555,"top":0.60555553,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.24652778,"top":0.6377778,"width":0.039583333,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.24652778,"top":0.6377778,"width":0.004166667,"height":0.017777778}},{"char_start":1,"char_count":9,"bounds":{"left":0.25069445,"top":0.6377778,"width":0.035416666,"height":0.017777778}}],"role_description":"text"},{"role":"AXButton","text":"Jira Cloud","depth":23,"bounds":{"left":0.2888889,"top":0.6377778,"width":0.011111111,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise","depth":25,"bounds":{"left":0.24652778,"top":0.6611111,"width":0.33333334,"height":0.19111112},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts","depth":26,"bounds":{"left":0.2888889,"top":0.68,"width":0.28055555,"height":0.04},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.2888889,"top":0.68,"width":0.0034722222,"height":0.02}},{"char_start":1,"char_count":68,"bounds":{"left":0.2888889,"top":0.68,"width":0.27708334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20725 in Jira Cloud","depth":27,"bounds":{"left":0.2888889,"top":0.7022222,"width":0.108333334,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"bounds":{"left":0.2888889,"top":0.7022222,"width":0.06527778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Status","depth":26,"bounds":{"left":0.2888889,"top":0.73444444,"width":0.025,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ready for QA","depth":26,"bounds":{"left":0.29166666,"top":0.76111114,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Priority","depth":26,"bounds":{"left":0.37222221,"top":0.73444444,"width":0.029861111,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.37222221,"top":0.73444444,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":7,"bounds":{"left":0.37777779,"top":0.73444444,"width":0.024305556,"height":0.017777778}}],"role_description":"text"},{"role":"AXStaticText","text":"Medium","depth":26,"bounds":{"left":0.3888889,"top":0.76111114,"width":0.038194444,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Assignee","depth":26,"bounds":{"left":0.44652778,"top":0.73444444,"width":0.035416666,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":26,"bounds":{"left":0.46319443,"top":0.76111114,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"As of today at 4:00 PM","depth":27,"bounds":{"left":0.25555557,"top":0.81777775,"width":0.09166667,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Refresh","depth":27,"bounds":{"left":0.34930557,"top":0.82222223,"width":0.030555556,"height":0.008888889},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open in Jira","depth":27,"bounds":{"left":0.43333334,"top":0.8111111,"width":0.06458333,"height":0.031111112},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"✨ Summarise","depth":27,"bounds":{"left":0.5,"top":0.8111111,"width":0.07361111,"height":0.031111112},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Open in browser","depth":26,"bounds":{"left":0.44791666,"top":0.68,"width":0.047222223,"height":0.035555556},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Open","depth":27,"bounds":{"left":0.46736112,"top":0.6888889,"width":0.022222223,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Share Bug JY-20725","depth":26,"bounds":{"left":0.5013889,"top":0.68,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View conversations","depth":26,"bounds":{"left":0.5236111,"top":0.68,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More actions","depth":26,"bounds":{"left":0.54583335,"top":0.68,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8041667,"top":0.5611111,"width":0.022222223,"height":0.035555556},"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":25,"bounds":{"left":0.8263889,"top":0.5611111,"width":0.022222223,"height":0.035555556},"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":25,"bounds":{"left":0.8486111,"top":0.5611111,"width":0.022222223,"height":0.035555556},"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":25,"bounds":{"left":0.87083334,"top":0.5611111,"width":0.022222223,"height":0.035555556},"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":25,"bounds":{"left":0.89305556,"top":0.5611111,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"bounds":{"left":0.9152778,"top":0.5611111,"width":0.022222223,"height":0.035555556},"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":25,"bounds":{"left":0.9375,"top":0.5611111,"width":0.022222223,"height":0.035555556},"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":25,"bounds":{"left":0.9597222,"top":0.5611111,"width":0.022222223,"height":0.035555556},"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.21666667,"top":0.88,"width":0.7652778,"height":0.04222222},"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"20 results","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Channel","depth":11,"on_screen":false,"role_description":"text"}]...
|
852946530903914021
|
-1568565942158046380
|
visual_change
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Aneliya Angelova
Apr 28th at 5:16:20 PM
5:16 PM
и за двете ли говориш
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
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
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:51:36 PM
2:51
трябва да се за всички, някъде не се ли попълва
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:52:10 PM
2:52
при зохо май беше hardcoded но май и там си връщаха две категории
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 4:00:37 PM
4:00 PM
Лукаш имаш ли време да се чуем за тестването на
https://jiminny.atlassian.net/browse/JY-20725
https://jiminny.atlassian.net/browse/JY-20725
Jira Cloud
Jira Cloud
Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise
[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts
Bug JY-20725 in Jira Cloud
Preview in Slack
Status
Ready for QA
Priority
Medium
Assignee
Aneliya Angelova
As of today at 4:00 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug JY-20725
View conversations
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
20 results
Channel
HomeDMsActivityFilesLater..•MoreSlackFileEditViewEDJiminny ...scnicre.# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Direct messagesP. Aneliya Angelova€. Vasil Vasilev E. Galya Dimitrova&. Stefka Stoyanova: Todor StamatovMario GeorgievNikolay IvanovLo James Graham8 Stoyan TanevSteliyan GeorgievPetko KashinskiLukas Kovalik y...AppsToastJira CloudGoHistoryWindowHelpQDescribe what you are looking forAneliya AngelovaMessagesAdd canvas© Files+у лукаш за нuDspot за синковете вече се използва тази команда нали«crm: sync-hubspot-objectsLukas Kovalik 1:32 PMда крон я пуска през 5 минlallA100% <8•Thu 14 May 16:01:53Monday, May 11th ~Today ~Aneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?при останалите CRMi трябва рьчно да се въведатLukas Kovalik 2:47 PMздрастиами не знам по принцип се вика при всичкитрябва да се за всички, някъде не се ли попълвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725Jira Cloud*.[HubSpot] Optimise CRM rematct# Preview in Slack& OpenStatusReady for QAPriority= MediumAssigneeAA Aneliya AngelovaAs of today at 4:00 PM RefreshOpen in JiraSummariseMessage Aneliya Angelova+V9939 Ha...
|
43590
|
NULL
|
NULL
|
NULL
|
|
43593
|
1589
|
26
|
2026-05-14T13:01:57.604928+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763717604_m1.jpg...
|
Slack
|
Aneliya Angelova (DM) - Jiminny Inc - 3 new items Aneliya Angelova (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Aneliya Angelova
Apr 28th at 5:16:20 PM
5:16 PM
и за двете ли говориш
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
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
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.011805556,"top":0.08111111,"width":0.025,"height":0.04},"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.00625,"top":0.14,"width":0.036111113,"height":0.075555556},"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.013888889,"top":0.19222222,"width":0.020833334,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.00625,"top":0.21555555,"width":0.036111113,"height":0.075555556},"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.015972223,"top":0.26777777,"width":0.016666668,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.00625,"top":0.2911111,"width":0.036111113,"height":0.075555556},"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.011111111,"top":0.34333333,"width":0.027083334,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.011111111,"top":0.34333333,"width":0.0055555557,"height":0.015555556}},{"char_start":1,"char_count":7,"bounds":{"left":0.015972223,"top":0.34333333,"width":0.022222223,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.00625,"top":0.36666667,"width":0.036111113,"height":0.075555556},"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.016666668,"top":0.4188889,"width":0.015972223,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.016666668,"top":0.4188889,"width":0.004166667,"height":0.015555556}},{"char_start":1,"char_count":4,"bounds":{"left":0.020833334,"top":0.4188889,"width":0.011805556,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.00625,"top":0.4422222,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.49444443,"width":0.018055556,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.00625,"top":0.5177778,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.57,"width":0.01875,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.039583333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.036805555,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.06111111,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.18472221,"top":0.12777779,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.050694443,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.09166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.093055554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.046527777,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.025694445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.022222223,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.072222225,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.057638887,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.054166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.034027778,"height":0.007777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.088194445,"top":0.14666666,"width":0.048611112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.072916664,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":15,"bounds":{"left":0.094444446,"top":0.17777778,"width":0.06666667,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.088194445,"top":0.20888889,"width":0.08055556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.088194445,"top":0.24,"width":0.035416666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.088194445,"top":0.2711111,"width":0.036805555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.05138889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":11,"bounds":{"left":0.093055554,"top":0.30222222,"width":0.045833334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.088194445,"top":0.33333334,"width":0.036111113,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.088194445,"top":0.36444443,"width":0.05138889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.094444446,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.004166667,"height":0.02}},{"char_start":1,"char_count":20,"bounds":{"left":0.09236111,"top":0.39555556,"width":0.09861111,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.088194445,"top":0.46888888,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.088194445,"top":0.5,"width":0.055555556,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.5,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.094444446,"top":0.5,"width":0.048611112,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.088194445,"top":0.5311111,"width":0.07361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.088194445,"top":0.56222224,"width":0.079166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"bounds":{"left":0.088194445,"top":0.5933333,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.6244444,"width":0.07152778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"bounds":{"left":0.088194445,"top":0.65555555,"width":0.06736111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.088194445,"top":0.68666667,"width":0.06666667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.088194445,"top":0.7177778,"width":0.060416665,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.7488889,"width":0.07986111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"bounds":{"left":0.088194445,"top":0.78,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.088194445,"top":0.8111111,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.15555556,"top":0.8111111,"width":0.013194445,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.15555556,"top":0.8111111,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":2,"bounds":{"left":0.16041666,"top":0.8111111,"width":0.011805556,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.088194445,"top":0.8844444,"width":0.025694445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.088194445,"top":0.91555554,"width":0.045833334,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.21319444,"top":0.12777779,"width":0.06458333,"height":0.04222222},"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.2326389,"top":0.14,"width":0.039583333,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.27986112,"top":0.12777779,"width":0.07152778,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"bounds":{"left":0.29930556,"top":0.14,"width":0.046527777,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.35347223,"top":0.12777779,"width":0.04375,"height":0.04222222},"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.37291667,"top":0.14,"width":0.01875,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.37291667,"top":0.14,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":4,"bounds":{"left":0.3784722,"top":0.14,"width":0.013194445,"height":0.017777778}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.4,"top":0.12777779,"width":0.022222223,"height":0.04222222},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5465278,"top":0.16111112,"width":0.10555556,"height":0.0011111111},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.08125,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:16:20 PM","depth":23,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:16 PM","depth":24,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и за двете ли говориш","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.10763889,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:16:54 PM","depth":23,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:16 PM","depth":24,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами ще го деплойна но ако нещо гръмне","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.19791667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.08125,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:04 PM","depth":23,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17 PM","depth":24,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"аа разбрахте","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.061805554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:07 PM","depth":24,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:14 PM","depth":24,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Галя каза че не се използва фичъра","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.16875,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:22 PM","depth":24,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и няма проблем да гръмне","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.12916666,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5472222,"top":0.17666666,"width":0.104166664,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.08125,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:24:41 PM","depth":23,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:24 PM","depth":24,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш за Hubspot за синковете вече се използва тази команда нали?","depth":24,"bounds":{"left":0.24652778,"top":0.16222222,"width":0.3326389,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"crm:sync-hubspot-objects","depth":25,"bounds":{"left":0.24930556,"top":0.19,"width":0.12013889,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.21777777,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.22,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:32:50 PM","depth":23,"bounds":{"left":0.31666666,"top":0.22333333,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:32 PM","depth":24,"bounds":{"left":0.31666666,"top":0.22333333,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"да крон я пуска през 5 мин","depth":24,"bounds":{"left":0.24652778,"top":0.24444444,"width":0.12986112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5729167,"top":0.28666666,"width":0.05277778,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.33,"width":0.08125,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.33222222,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:30:26 PM","depth":23,"bounds":{"left":0.33333334,"top":0.33555555,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30 PM","depth":24,"bounds":{"left":0.33333334,"top":0.33555555,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?","depth":24,"bounds":{"left":0.24652778,"top":0.35666665,"width":0.5069444,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:30:45 PM","depth":24,"bounds":{"left":0.22430556,"top":0.39333335,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30","depth":25,"bounds":{"left":0.22430556,"top":0.39333335,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"при останалите CRMi трябва ръчно да се въведат","depth":24,"bounds":{"left":0.24652778,"top":0.39,"width":0.24166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.4211111,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.42333335,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:47:56 PM","depth":23,"bounds":{"left":0.31666666,"top":0.42666668,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:47 PM","depth":24,"bounds":{"left":0.31666666,"top":0.42666668,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти","depth":24,"bounds":{"left":0.24652778,"top":0.44777778,"width":0.03888889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:48:14 PM","depth":24,"bounds":{"left":0.22430556,"top":0.48444444,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:48","depth":25,"bounds":{"left":0.22430556,"top":0.48444444,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами не знам по принцип се вика при всички","depth":24,"bounds":{"left":0.24652778,"top":0.4811111,"width":0.21111111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
551527086426477591
|
-3874268041984030378
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Aneliya Angelova
Apr 28th at 5:16:20 PM
5:16 PM
и за двете ли говориш
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
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
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
HomeDMsActivityFilesLater..•MoreSlackFileEditViewEDJiminny ...scnicre.# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Direct messagesP. Aneliya Angelova€. Vasil Vasilev E. Galya Dimitrova&. Stefka Stoyanova: Todor StamatovMario GeorgievNikolay IvanovLo James Graham2 Stoyan TanevSteliyan GeorgievPetko KashinskiLukas Kovalik y...AppsToastJira CloudGoHistoryWindowHelpQDescribe what you are looking forAneliya AngelovaMessagesAdd canvas© Files+у лукаш за нuDspot за синковете вече се използва тази команда нали«crm: sync-hubspot-objectsLukas Kovalik 1:32 PMда крон я пуска през 5 минlallA100% <8•Thu 14 May 16:01:57Monday, May 11th ~Today ~Aneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?при останалите CRMi трябва рьчно да се въведатLukas Kovalik 2:47 PMздрастиами не знам по принцип се вика при всичкитрябва да се за всички, някъде не се ли попълвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725Jira Cloud[HubSpot) Optimise CRM rematching on delete hubspot ac...Bug JY-20725 in Jira CloudStatusReady for QAPriority= MediumAssigneeAA Aneliya AngelovaAs of today at 4:00 PMOpen in Jira* SummariseV9939 HaMessage Aneliya Angelova+...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43594
|
1590
|
26
|
2026-05-14T13:01:57.644074+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763717644_m2.jpg...
|
Slack
|
Aneliya Angelova (DM) - Jiminny Inc - 3 new items Aneliya Angelova (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Aneliya Angelova
Apr 28th at 5:16:20 PM
5:16 PM
и за двете ли говориш
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.27593085,"top":1.0,"width":0.011968086,"height":-0.058260202},"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,"bounds":{"left":0.30718085,"top":1.0,"width":0.018949468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.01761968,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.02925532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.3587101,"top":1.0,"width":0.0026595744,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.024268618,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.043882977,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.04454787,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.022273935,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.012300532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.010638298,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.034574468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.027593086,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.025930852,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.016289894,"height":-0.09177971},"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":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","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,"bounds":{"left":0.3723404,"top":1.0,"width":0.030917553,"height":-0.09177971},"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":"Add canvas","depth":18,"bounds":{"left":0.40425533,"top":1.0,"width":0.034242023,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.43949467,"top":1.0,"width":0.020944148,"height":-0.09177971},"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":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.46176863,"top":1.0,"width":0.010638298,"height":-0.09177971},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:16:20 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:16 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и за двете ли говориш","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:16:54 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:16 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами ще го деплойна но ако нещо гръмне","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:04 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"аа разбрахте","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:07 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:14 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Галя каза че не се използва фичъра","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:22 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и няма проблем да гръмне","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:24:41 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:24 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш за Hubspot за синковете вече се използва тази команда нали?","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"crm:sync-hubspot-objects","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:32:50 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:32 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"да крон я пуска през 5 мин","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7233846723462943307
|
-8166199672216121514
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Aneliya Angelova
Apr 28th at 5:16:20 PM
5:16 PM
и за двете ли говориш
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
• Goodle geminiPlatform Sprint 4 02 - PlatformJY-20903 Update activity sta XSRD-6849) Recorded call doesUsage | Windsurf4(SRD-68481 Sidekick SMS issue1.lY-208911 Sidekick SMS issueJY-20891 add support for seconcR (SRD-6849) Recorded call does r[JY-20903] Recorded call does r[SRD-6853] Moxso - Potential d@ JY-20903 Update activity stage* Configure SSH access to multiple c* Useful commands - EngineeringA 1y-20004 Eiv HndateAotivituFlad(JY-20904) Fix UpdateActivityElaSJliminnv- New Tabhow to unpin slackmessaceUnpinning a message in Slack is straightforward,though the steps vary slightly depending onwhether you are using the desktop app or themobile version.On Desktop (Mac/Windows/Web)1. Open the channel or DM where themessage is pinned.2. Click the Pinned icon (the thumbtack)located just below the channel name orheader at the top of the screen. This opensa sidebar showing all pinned items.3. Find the message you want to unpin andhover over It4. Click the "X" icon that appears next to themessage in the sidebar, then click Removeto confirm.Alternative Method: Find themessade direct v in the chat historv.click the three-dot icon (Moreactions on the message, ano selectUnpin from channel.Enter a prompt for GeminiFastvAl lt can make mistakes so double check it Your orivacv &. G.Summarize pagejiminny / app &<> Code%? Pull requests 29G. Agents Actions M Wiki ® Security and qualityInsights ộ Settings© On April 24 we'll start using GitHub Copilot interaction data for Al model training unless you opt out. Review this update and manage your preferences in your GitHub account settingsJY-20903 Update activity stage when opportunity is changed #12077 •LakyLak wants to merge 2 commits into master from JY-20903-update_activity-stage-on-opportunity-changeW Conversation4• CommitsiE Checks 2Files changed 1• Filter files..~ E app/ModelsActivity.phpapp/Models/Activity-php d ++C0 -2119,12 +2119,14 @ public function updateActivityCrmData(array srecords): void2119sthis->account_id = saccount->id;21202121HEEEif (Sthis->stage_id === null && Sstage) €Sthis->stage_id = sstage->id;2127if (Sopportunity && Sthis->opportunitv id I== Sopportunitv->id) {sthis->opportunity_id = sopportunity->id;2128212921301if (Sopportunity && Sthis->value !== Sopportunity-›value) {2119212021212122212321282220 :213021312132100% .• Inu 14 May 16:01:0/Q Type D to search• Checks pending• 0 I 1 viewedcode-+6 -4 00022Submit review - (ộ3+6 -4 manaa [ Viewed@ ..Sthis->account_id = Saccount->id:if (Sopportunity && $this->opportunity_id !== Sopportunity->id) {sthis->opportunity_id = sopportunity->id;// Reset stage_id when opportunity changes to avoid stale stage from previous opportunity matchsthis->stage_id = $stage?->id;if (Sthis->stage id === null && Sstage) ‹sthis->stage_id = sstage->id;if (Sopportunity && Sthis-›value !== Sopportunity->value) {...
|
43591
|
NULL
|
NULL
|
NULL
|
|
43595
|
1589
|
27
|
2026-05-14T13:02:00.035092+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763720035_m1.jpg...
|
Slack
|
Aneliya Angelova (DM) - Jiminny Inc - 3 new items Aneliya Angelova (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Aneliya Angelova
Apr 28th at 5:16:20 PM
5:16 PM
и за двете ли говориш
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
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
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:51:36 PM
2:51
трябва да се за всички, някъде не се ли попълва
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:52:10 PM
2:52
при зохо май беше hardcoded но май и там си връщаха две категории
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 4:00:37 PM
4:00 PM
Лукаш имаш ли време да се чуем за тестването на
https://jiminny.atlassian.net/browse/JY-20725
https://jiminny.atlassian.net/browse/JY-20725
Jira Cloud
Jira Cloud
Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise
[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts
Bug JY-20725 in Jira Cloud
Preview in Slack
Status
Ready for QA
Priority
Medium
Assignee
Aneliya Angelova
As of today at 4:00 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug JY-20725
View conversations
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
20 results
Channel...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.011805556,"top":0.08111111,"width":0.025,"height":0.04},"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.00625,"top":0.14,"width":0.036111113,"height":0.075555556},"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.013888889,"top":0.19222222,"width":0.020833334,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.00625,"top":0.21555555,"width":0.036111113,"height":0.075555556},"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.015972223,"top":0.26777777,"width":0.016666668,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.00625,"top":0.2911111,"width":0.036111113,"height":0.075555556},"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.011111111,"top":0.34333333,"width":0.027083334,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.011111111,"top":0.34333333,"width":0.0055555557,"height":0.015555556}},{"char_start":1,"char_count":7,"bounds":{"left":0.015972223,"top":0.34333333,"width":0.022222223,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.00625,"top":0.36666667,"width":0.036111113,"height":0.075555556},"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.016666668,"top":0.4188889,"width":0.015972223,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.016666668,"top":0.4188889,"width":0.004166667,"height":0.015555556}},{"char_start":1,"char_count":4,"bounds":{"left":0.020833334,"top":0.4188889,"width":0.011805556,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.00625,"top":0.4422222,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.49444443,"width":0.018055556,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.00625,"top":0.5177778,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.57,"width":0.01875,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.039583333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.036805555,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.06111111,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.18472221,"top":0.12777779,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.050694443,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.09166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.093055554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.046527777,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.025694445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.022222223,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.072222225,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.057638887,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.054166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.034027778,"height":0.007777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.088194445,"top":0.14666666,"width":0.048611112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.072916664,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":15,"bounds":{"left":0.094444446,"top":0.17777778,"width":0.06666667,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.088194445,"top":0.20888889,"width":0.08055556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.088194445,"top":0.24,"width":0.035416666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.088194445,"top":0.2711111,"width":0.036805555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.05138889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":11,"bounds":{"left":0.093055554,"top":0.30222222,"width":0.045833334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.088194445,"top":0.33333334,"width":0.036111113,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.088194445,"top":0.36444443,"width":0.05138889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.094444446,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.004166667,"height":0.02}},{"char_start":1,"char_count":20,"bounds":{"left":0.09236111,"top":0.39555556,"width":0.09861111,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.088194445,"top":0.46888888,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.088194445,"top":0.5,"width":0.055555556,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.5,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.094444446,"top":0.5,"width":0.048611112,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.088194445,"top":0.5311111,"width":0.07361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.088194445,"top":0.56222224,"width":0.079166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"bounds":{"left":0.088194445,"top":0.5933333,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.6244444,"width":0.07152778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"bounds":{"left":0.088194445,"top":0.65555555,"width":0.06736111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.088194445,"top":0.68666667,"width":0.06666667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.088194445,"top":0.7177778,"width":0.060416665,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.7488889,"width":0.07986111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"bounds":{"left":0.088194445,"top":0.78,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.088194445,"top":0.8111111,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.15555556,"top":0.8111111,"width":0.013194445,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.15555556,"top":0.8111111,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":2,"bounds":{"left":0.16041666,"top":0.8111111,"width":0.011805556,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.088194445,"top":0.8844444,"width":0.025694445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.088194445,"top":0.91555554,"width":0.045833334,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.21319444,"top":0.12777779,"width":0.06458333,"height":0.04222222},"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.2326389,"top":0.14,"width":0.039583333,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.27986112,"top":0.12777779,"width":0.07152778,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"bounds":{"left":0.29930556,"top":0.14,"width":0.046527777,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.35347223,"top":0.12777779,"width":0.04375,"height":0.04222222},"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.37291667,"top":0.14,"width":0.01875,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.37291667,"top":0.14,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":4,"bounds":{"left":0.3784722,"top":0.14,"width":0.013194445,"height":0.017777778}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.4,"top":0.12777779,"width":0.022222223,"height":0.04222222},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5465278,"top":0.16111112,"width":0.10555556,"height":0.0011111111},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.08125,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:16:20 PM","depth":23,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:16 PM","depth":24,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и за двете ли говориш","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.10763889,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:16:54 PM","depth":23,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:16 PM","depth":24,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами ще го деплойна но ако нещо гръмне","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.19791667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.08125,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:04 PM","depth":23,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17 PM","depth":24,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"аа разбрахте","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.061805554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:07 PM","depth":24,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:14 PM","depth":24,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Галя каза че не се използва фичъра","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.16875,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:22 PM","depth":24,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и няма проблем да гръмне","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.12916666,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5472222,"top":0.17666666,"width":0.104166664,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.08125,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:24:41 PM","depth":23,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:24 PM","depth":24,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш за Hubspot за синковете вече се използва тази команда нали?","depth":24,"bounds":{"left":0.24652778,"top":0.16222222,"width":0.3326389,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"crm:sync-hubspot-objects","depth":25,"bounds":{"left":0.24930556,"top":0.19,"width":0.12013889,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.21777777,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.22,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:32:50 PM","depth":23,"bounds":{"left":0.31666666,"top":0.22333333,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:32 PM","depth":24,"bounds":{"left":0.31666666,"top":0.22333333,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"да крон я пуска през 5 мин","depth":24,"bounds":{"left":0.24652778,"top":0.24444444,"width":0.12986112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5729167,"top":0.28666666,"width":0.05277778,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.33,"width":0.08125,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.33222222,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:30:26 PM","depth":23,"bounds":{"left":0.33333334,"top":0.33555555,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30 PM","depth":24,"bounds":{"left":0.33333334,"top":0.33555555,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?","depth":24,"bounds":{"left":0.24652778,"top":0.35666665,"width":0.5069444,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:30:45 PM","depth":24,"bounds":{"left":0.22430556,"top":0.39333335,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30","depth":25,"bounds":{"left":0.22430556,"top":0.39333335,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"при останалите CRMi трябва ръчно да се въведат","depth":24,"bounds":{"left":0.24652778,"top":0.39,"width":0.24166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.4211111,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.42333335,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:47:56 PM","depth":23,"bounds":{"left":0.31666666,"top":0.42666668,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:47 PM","depth":24,"bounds":{"left":0.31666666,"top":0.42666668,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти","depth":24,"bounds":{"left":0.24652778,"top":0.44777778,"width":0.03888889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:48:14 PM","depth":24,"bounds":{"left":0.22430556,"top":0.48444444,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:48","depth":25,"bounds":{"left":0.22430556,"top":0.48444444,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами не знам по принцип се вика при всички","depth":24,"bounds":{"left":0.24652778,"top":0.4811111,"width":0.21111111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:51:36 PM","depth":24,"bounds":{"left":0.22430556,"top":0.5177778,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:51","depth":25,"bounds":{"left":0.22430556,"top":0.5177778,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"трябва да се за всички, някъде не се ли попълва","depth":24,"bounds":{"left":0.24652778,"top":0.5144445,"width":0.2326389,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:52:10 PM","depth":24,"bounds":{"left":0.22430556,"top":0.5511111,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"bounds":{"left":0.22430556,"top":0.5511111,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"при зохо май беше hardcoded но май и там си връщаха две категории","depth":24,"bounds":{"left":0.24652778,"top":0.5477778,"width":0.3361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"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.96458334,"top":0.5655556,"width":0.01875,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.5788889,"width":0.08125,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.58111113,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:00:37 PM","depth":23,"bounds":{"left":0.33333334,"top":0.58444446,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:00 PM","depth":24,"bounds":{"left":0.33333334,"top":0.58444446,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш имаш ли време да се чуем за тестването на","depth":24,"bounds":{"left":0.24652778,"top":0.60555553,"width":0.24722221,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20725","depth":24,"bounds":{"left":0.49305555,"top":0.60555553,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20725","depth":25,"bounds":{"left":0.49305555,"top":0.60555553,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.24652778,"top":0.6377778,"width":0.039583333,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.24652778,"top":0.6377778,"width":0.004166667,"height":0.017777778}},{"char_start":1,"char_count":9,"bounds":{"left":0.25069445,"top":0.6377778,"width":0.035416666,"height":0.017777778}}],"role_description":"text"},{"role":"AXButton","text":"Jira Cloud","depth":23,"bounds":{"left":0.2888889,"top":0.6377778,"width":0.011111111,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise","depth":25,"bounds":{"left":0.24652778,"top":0.6611111,"width":0.33333334,"height":0.19111112},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts","depth":26,"bounds":{"left":0.2888889,"top":0.68,"width":0.28055555,"height":0.04},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.2888889,"top":0.68,"width":0.0034722222,"height":0.02}},{"char_start":1,"char_count":68,"bounds":{"left":0.2888889,"top":0.68,"width":0.27708334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20725 in Jira Cloud","depth":27,"bounds":{"left":0.2888889,"top":0.7022222,"width":0.108333334,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"bounds":{"left":0.2888889,"top":0.7022222,"width":0.06527778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Status","depth":26,"bounds":{"left":0.2888889,"top":0.73444444,"width":0.025,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ready for QA","depth":26,"bounds":{"left":0.29166666,"top":0.76111114,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Priority","depth":26,"bounds":{"left":0.37222221,"top":0.73444444,"width":0.029861111,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.37222221,"top":0.73444444,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":7,"bounds":{"left":0.37777779,"top":0.73444444,"width":0.024305556,"height":0.017777778}}],"role_description":"text"},{"role":"AXStaticText","text":"Medium","depth":26,"bounds":{"left":0.3888889,"top":0.76111114,"width":0.038194444,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Assignee","depth":26,"bounds":{"left":0.44652778,"top":0.73444444,"width":0.035416666,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":26,"bounds":{"left":0.46319443,"top":0.76111114,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"As of today at 4:00 PM","depth":27,"bounds":{"left":0.25555557,"top":0.81777775,"width":0.09166667,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Refresh","depth":27,"bounds":{"left":0.34930557,"top":0.82222223,"width":0.030555556,"height":0.008888889},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open in Jira","depth":27,"bounds":{"left":0.43333334,"top":0.8111111,"width":0.06458333,"height":0.031111112},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"✨ Summarise","depth":27,"bounds":{"left":0.5,"top":0.8111111,"width":0.07361111,"height":0.031111112},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Open in browser","depth":26,"bounds":{"left":0.44791666,"top":0.68,"width":0.047222223,"height":0.035555556},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Open","depth":27,"bounds":{"left":0.46736112,"top":0.6888889,"width":0.022222223,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Share Bug JY-20725","depth":26,"bounds":{"left":0.5013889,"top":0.68,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View conversations","depth":26,"bounds":{"left":0.5236111,"top":0.68,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More actions","depth":26,"bounds":{"left":0.54583335,"top":0.68,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"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.21666667,"top":0.88,"width":0.7652778,"height":0.04222222},"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"20 results","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Channel","depth":11,"on_screen":false,"role_description":"text"}]...
|
852946530903914021
|
-1568565942158046380
|
visual_change
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Aneliya Angelova
Apr 28th at 5:16:20 PM
5:16 PM
и за двете ли говориш
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
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
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:51:36 PM
2:51
трябва да се за всички, някъде не се ли попълва
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:52:10 PM
2:52
при зохо май беше hardcoded но май и там си връщаха две категории
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 4:00:37 PM
4:00 PM
Лукаш имаш ли време да се чуем за тестването на
https://jiminny.atlassian.net/browse/JY-20725
https://jiminny.atlassian.net/browse/JY-20725
Jira Cloud
Jira Cloud
Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise
[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts
Bug JY-20725 in Jira Cloud
Preview in Slack
Status
Ready for QA
Priority
Medium
Assignee
Aneliya Angelova
As of today at 4:00 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug JY-20725
View conversations
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
20 results
Channel
HomeDMsActivityFilesLater..•MoreSlackFileEditViewEDJiminny ...scnicre.# jiminny-bg# platform-tickets#product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Direct messagesP. Aneliya Angelova€. Vasil Vasilev E. Galya Dimitrova&. Stefka Stoyanova: Todor StamatovMario GeorgievNikolay IvanovLo James Graham2 Stoyan TanevSteliyan GeorgievPetko KashinskiLukas Kovalik y...AppsToastJira CloudGoHistoryWindowHelpQDescribe what you are looking forAneliya AngelovaMessagesAdd canvas@ Files+у лукаш за нuDspot за синковете вече се използва тази команда нали«crm: sync-hubspot-objectsLukas Kovalik 1:32 PMда крон я пуска през 5 минlall100% C8•Thu 14 May 16:01:59Monday, May 11th ~Today ~Aneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?при останалите CRMi трябва рьчно да се въведатLukas Kovalik 2:47 PMздрастиами не знам по принцип се вика при всичкитрябва да се за всички, някъде не се ли попълвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725Jira Cloud[HubSpot] Optimise CRM rematching on delete hubspot ac...Bug JY-20725 in Jira CloudStatusReady for QAPriority= MediumAssigneeAA Aneliya AngelovaAs of today at 4:00 PMOpen in JiraSummariseNewMessage Aneliya Angelova+...
|
43593
|
NULL
|
NULL
|
NULL
|
|
43596
|
1590
|
27
|
2026-05-14T13:02:01.012527+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763721012_m2.jpg...
|
Slack
|
Aneliya Angelova (DM) - Jiminny Inc - 3 new items Aneliya Angelova (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Aneliya Angelova
Apr 28th at 5:16:20 PM
5:16 PM
и за двете ли говориш
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
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
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:51:36 PM
2:51
трябва да се за всички, някъде не се ли попълва
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:52:10 PM
2:52
при зохо май беше hardcoded но май и там си връщаха две категории
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 4:00:37 PM
4:00 PM
Лукаш имаш ли време да се чуем за тестването на
https://jiminny.atlassian.net/browse/JY-20725...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.27593085,"top":1.0,"width":0.011968086,"height":-0.058260202},"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,"bounds":{"left":0.30718085,"top":1.0,"width":0.018949468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.01761968,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.02925532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.3587101,"top":1.0,"width":0.0026595744,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.024268618,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.043882977,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.04454787,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.022273935,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.012300532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.010638298,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.034574468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.027593086,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.025930852,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.016289894,"height":-0.09177971},"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":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","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,"bounds":{"left":0.3723404,"top":1.0,"width":0.030917553,"height":-0.09177971},"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":"Add canvas","depth":18,"bounds":{"left":0.40425533,"top":1.0,"width":0.034242023,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.43949467,"top":1.0,"width":0.020944148,"height":-0.09177971},"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":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.46176863,"top":1.0,"width":0.010638298,"height":-0.09177971},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":23,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:16:20 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:16 PM","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и за двете ли говориш","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:16:54 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:16 PM","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами ще го деплойна но ако нещо гръмне","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:04 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17 PM","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"аа разбрахте","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:07 PM","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:14 PM","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Галя каза че не се използва фичъра","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:22 PM","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и няма проблем да гръмне","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":23,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:24:41 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:24 PM","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш за Hubspot за синковете вече се използва тази команда нали?","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"crm:sync-hubspot-objects","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:32:50 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:32 PM","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"да крон я пуска през 5 мин","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":23,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:30:26 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30 PM","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:30:45 PM","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"при останалите CRMi трябва ръчно да се въведат","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:47:56 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:47 PM","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:48:14 PM","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:48","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами не знам по принцип се вика при всички","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:51:36 PM","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:51","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"трябва да се за всички, някъде не се ли попълва","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:52:10 PM","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"при зохо май беше hardcoded но май и там си връщаха две категории","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"New","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:00:37 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:00 PM","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш имаш ли време да се чуем за тестването на","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20725","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
2369440443160554225
|
-1712540220795729580
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Aneliya Angelova
Apr 28th at 5:16:20 PM
5:16 PM
и за двете ли говориш
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
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
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:51:36 PM
2:51
трябва да се за всички, някъде не се ли попълва
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:52:10 PM
2:52
при зохо май беше hardcoded но май и там си връщаха две категории
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 4:00:37 PM
4:00 PM
Лукаш имаш ли време да се чуем за тестването на
https://jiminny.atlassian.net/browse/JY-20725
• Goodle geminiPlatform Sprint 4 02 - PlatformJY-20903 Update activity sta XSRD-6849) Recorded call doesUsage | Windsurf4(SRD-68481 Sidekick SMS issue1.lY-208911 Sidekick SMS issueJY-20891 add support for seconcR (SRD-6849) Recorded call does r[JY-20903] Recorded call does r[SRD-6853] Moxso - Potential d@ JY-20903 Update activity stage* Configure SSH access to multiple c* Useful commands - EngineeringA 1y-20004 Eiv HndateAotivituFlad(JY-20904) Fix UpdateActivityElaSJliminnv- New Tabhow to unpin slackmessaceUnpinning a message in Slack is straightforward,though the steps vary slightly depending onwhether you are using the desktop app or themobile version.On Desktop (Mac/Windows/Web)1. Open the channel or DM where themessage is pinned.2. Click the Pinned icon (the thumbtack)located just below the channel name orheader at the top of the screen. This opensa sidebar showing all pinned items.3. Find the message you want to unpin andhover over It4. Click the "X" icon that appears next to themessage in the sidebar, then click Removeto confirm.Alternative Method: Find themessade direct v in the chat historv.click the three-dot icon (Moreactions on the message, ano selectUnpin from channel.Enter a prompt for GeminiFastvAl lt can make mistakes so double check it Your orivacv &. G.Summarize pagejiminny / app &<> Code%? Pull requests 29G. Agents Actions M Wiki ® Security and qualityInsights ộ Settings© On April 24 we'll start using GitHub Copilot interaction data for Al model training unless you opt out. Review this update and manage your preferences in your GitHub account settingsJY-20903 Update activity stage when opportunity is changed #12077 •LakyLak wants to merge 2 commits into master from JY-20903-update_activity-stage-on-opportunity-changeW Conversation4• CommitsiE Checks 2Files changed 1• Filter files..~ E app/ModelsActivity.phpapp/Models/Activity-php d ++C0 -2119,12 +2119,14 @ public function updateActivityCrmData(array srecords): void2119sthis->account_id = saccount->id;21202121HEEEif (Sthis->stage_id === null && Sstage) €Sthis->stage_id = sstage->id;2127if (Sopportunity && Sthis->opportunitv id I== Sopportunitv->id) {sthis->opportunity_id = sopportunity->id;2128212921301if (Sopportunity && Sthis->value !== Sopportunity-›value) {2119212021212122212321282220 :213021312132100% • Inu 14 May 10:02-0UQ Type D to search• Checks pending• 0 I 1 viewedcode-+6 -4 00022Submit review - (ộ3+6 -4 manaa [ Viewed@ ..Sthis->account_id = Saccount->id:if (Sopportunity && $this->opportunity_id !== Sopportunity->id) {sthis->opportunity_id = sopportunity->id;// Reset stage_id when opportunity changes to avoid stale stage from previous opportunity matchsthis->stage_id = $stage?->id;if (Sthis->stage id === null && Sstage) ‹sthis->stage_id = sstage->id;if (Sopportunity && Sthis-›value !== Sopportunity->value) {...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43597
|
1589
|
28
|
2026-05-14T13:02:03.041473+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763723041_m1.jpg...
|
Slack
|
Aneliya Angelova (DM) - Jiminny Inc - 3 new items Aneliya Angelova (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Aneliya Angelova
Apr 28th at 5:16:20 PM
5:16 PM
и за двете ли говориш
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
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
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:51:36 PM
2:51
трябва да се за всички, някъде не се ли попълва
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:52:10 PM
2:52
при зохо май беше hardcoded но май и там си връщаха две категории
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 4:00:37 PM
4:00 PM
Лукаш имаш ли време да се чуем за тестването на
https://jiminny.atlassian.net/browse/JY-20725
https://jiminny.atlassian.net/browse/JY-20725
Jira Cloud
Jira Cloud
Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise
[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts
Bug JY-20725 in Jira Cloud
Preview in Slack
Status
Ready for QA
Priority
Medium
Assignee
Aneliya Angelova
As of today at 4:00 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug JY-20725
View conversations
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
да
да
20 results
Channel...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.011805556,"top":0.08111111,"width":0.025,"height":0.04},"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.00625,"top":0.14,"width":0.036111113,"height":0.075555556},"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.013888889,"top":0.19222222,"width":0.020833334,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.00625,"top":0.21555555,"width":0.036111113,"height":0.075555556},"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.015972223,"top":0.26777777,"width":0.016666668,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.00625,"top":0.2911111,"width":0.036111113,"height":0.075555556},"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.011111111,"top":0.34333333,"width":0.027083334,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.011111111,"top":0.34333333,"width":0.0055555557,"height":0.015555556}},{"char_start":1,"char_count":7,"bounds":{"left":0.015972223,"top":0.34333333,"width":0.022222223,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.00625,"top":0.36666667,"width":0.036111113,"height":0.075555556},"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.016666668,"top":0.4188889,"width":0.015972223,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.016666668,"top":0.4188889,"width":0.004166667,"height":0.015555556}},{"char_start":1,"char_count":4,"bounds":{"left":0.020833334,"top":0.4188889,"width":0.011805556,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.00625,"top":0.4422222,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.49444443,"width":0.018055556,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.00625,"top":0.5177778,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.57,"width":0.01875,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.039583333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.036805555,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.06111111,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.18472221,"top":0.12777779,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.050694443,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.09166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.093055554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.046527777,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.025694445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.022222223,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.072222225,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.057638887,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.054166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.034027778,"height":0.007777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.088194445,"top":0.14666666,"width":0.048611112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.072916664,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":15,"bounds":{"left":0.094444446,"top":0.17777778,"width":0.06666667,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.088194445,"top":0.20888889,"width":0.08055556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.088194445,"top":0.24,"width":0.035416666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.088194445,"top":0.2711111,"width":0.036805555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.05138889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":11,"bounds":{"left":0.093055554,"top":0.30222222,"width":0.045833334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.088194445,"top":0.33333334,"width":0.036111113,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.088194445,"top":0.36444443,"width":0.05138889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.094444446,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.004166667,"height":0.02}},{"char_start":1,"char_count":20,"bounds":{"left":0.09236111,"top":0.39555556,"width":0.09861111,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.088194445,"top":0.46888888,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.088194445,"top":0.5,"width":0.055555556,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.5,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.094444446,"top":0.5,"width":0.048611112,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.088194445,"top":0.5311111,"width":0.07361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.088194445,"top":0.56222224,"width":0.079166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"bounds":{"left":0.088194445,"top":0.5933333,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.6244444,"width":0.07152778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"bounds":{"left":0.088194445,"top":0.65555555,"width":0.06736111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.088194445,"top":0.68666667,"width":0.06666667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.088194445,"top":0.7177778,"width":0.060416665,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.7488889,"width":0.07986111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"bounds":{"left":0.088194445,"top":0.78,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.088194445,"top":0.8111111,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.15555556,"top":0.8111111,"width":0.013194445,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.15555556,"top":0.8111111,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":2,"bounds":{"left":0.16041666,"top":0.8111111,"width":0.011805556,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.088194445,"top":0.8844444,"width":0.025694445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.088194445,"top":0.91555554,"width":0.045833334,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.21319444,"top":0.12777779,"width":0.06458333,"height":0.04222222},"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.2326389,"top":0.14,"width":0.039583333,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.27986112,"top":0.12777779,"width":0.07152778,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"bounds":{"left":0.29930556,"top":0.14,"width":0.046527777,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.35347223,"top":0.12777779,"width":0.04375,"height":0.04222222},"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.37291667,"top":0.14,"width":0.01875,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.37291667,"top":0.14,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":4,"bounds":{"left":0.3784722,"top":0.14,"width":0.013194445,"height":0.017777778}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.4,"top":0.12777779,"width":0.022222223,"height":0.04222222},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":23,"bounds":{"left":0.5465278,"top":0.16111112,"width":0.10555556,"height":0.0011111111},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.08125,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"bounds":{"left":0.32777777,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:16:20 PM","depth":24,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:16 PM","depth":25,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и за двете ли говориш","depth":25,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.10763889,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"bounds":{"left":0.31111112,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:16:54 PM","depth":24,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:16 PM","depth":25,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами ще го деплойна но ако нещо гръмне","depth":25,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.19791667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.08125,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"bounds":{"left":0.32777777,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:04 PM","depth":24,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17 PM","depth":25,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"аа разбрахте","depth":25,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.061805554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:07 PM","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17","depth":26,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:14 PM","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":26,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Галя каза че не се използва фичъра","depth":25,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.16875,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:22 PM","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":26,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и няма проблем да гръмне","depth":25,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.12916666,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":23,"bounds":{"left":0.5472222,"top":0.17666666,"width":0.104166664,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.08125,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"bounds":{"left":0.32777777,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:24:41 PM","depth":24,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:24 PM","depth":25,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш за Hubspot за синковете вече се използва тази команда нали?","depth":25,"bounds":{"left":0.24652778,"top":0.16222222,"width":0.3326389,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"crm:sync-hubspot-objects","depth":26,"bounds":{"left":0.24930556,"top":0.19,"width":0.12013889,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":24,"bounds":{"left":0.24652778,"top":0.21777777,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"bounds":{"left":0.31111112,"top":0.22,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:32:50 PM","depth":24,"bounds":{"left":0.31666666,"top":0.22333333,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:32 PM","depth":25,"bounds":{"left":0.31666666,"top":0.22333333,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"да крон я пуска през 5 мин","depth":25,"bounds":{"left":0.24652778,"top":0.24444444,"width":0.12986112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":23,"bounds":{"left":0.5729167,"top":0.28666666,"width":0.05277778,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":24,"bounds":{"left":0.24652778,"top":0.33,"width":0.08125,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"bounds":{"left":0.32777777,"top":0.33222222,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:30:26 PM","depth":24,"bounds":{"left":0.33333334,"top":0.33555555,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30 PM","depth":25,"bounds":{"left":0.33333334,"top":0.33555555,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?","depth":25,"bounds":{"left":0.24652778,"top":0.35666665,"width":0.5069444,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:30:45 PM","depth":25,"bounds":{"left":0.22430556,"top":0.39333335,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30","depth":26,"bounds":{"left":0.22430556,"top":0.39333335,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"при останалите CRMi трябва ръчно да се въведат","depth":25,"bounds":{"left":0.24652778,"top":0.39,"width":0.24166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":24,"bounds":{"left":0.24652778,"top":0.4211111,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"bounds":{"left":0.31111112,"top":0.42333335,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:47:56 PM","depth":24,"bounds":{"left":0.31666666,"top":0.42666668,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:47 PM","depth":25,"bounds":{"left":0.31666666,"top":0.42666668,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти","depth":25,"bounds":{"left":0.24652778,"top":0.44777778,"width":0.03888889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:48:14 PM","depth":25,"bounds":{"left":0.22430556,"top":0.48444444,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:48","depth":26,"bounds":{"left":0.22430556,"top":0.48444444,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами не знам по принцип се вика при всички","depth":25,"bounds":{"left":0.24652778,"top":0.4811111,"width":0.21111111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:51:36 PM","depth":25,"bounds":{"left":0.22430556,"top":0.5177778,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:51","depth":26,"bounds":{"left":0.22430556,"top":0.5177778,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"трябва да се за всички, някъде не се ли попълва","depth":25,"bounds":{"left":0.24652778,"top":0.5144445,"width":0.2326389,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:52:10 PM","depth":25,"bounds":{"left":0.22430556,"top":0.5511111,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":26,"bounds":{"left":0.22430556,"top":0.5511111,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"при зохо май беше hardcoded но май и там си връщаха две категории","depth":25,"bounds":{"left":0.24652778,"top":0.5477778,"width":0.3361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"New","depth":22,"bounds":{"left":0.96458334,"top":0.5655556,"width":0.01875,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":24,"bounds":{"left":0.24652778,"top":0.5788889,"width":0.08125,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"bounds":{"left":0.32777777,"top":0.58111113,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:00:37 PM","depth":24,"bounds":{"left":0.33333334,"top":0.58444446,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:00 PM","depth":25,"bounds":{"left":0.33333334,"top":0.58444446,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш имаш ли време да се чуем за тестването на","depth":25,"bounds":{"left":0.24652778,"top":0.60555553,"width":0.24722221,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20725","depth":25,"bounds":{"left":0.49305555,"top":0.60555553,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20725","depth":26,"bounds":{"left":0.49305555,"top":0.60555553,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":24,"bounds":{"left":0.24652778,"top":0.6377778,"width":0.039583333,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.24652778,"top":0.6377778,"width":0.004166667,"height":0.017777778}},{"char_start":1,"char_count":9,"bounds":{"left":0.25069445,"top":0.6377778,"width":0.035416666,"height":0.017777778}}],"role_description":"text"},{"role":"AXButton","text":"Jira Cloud","depth":24,"bounds":{"left":0.2888889,"top":0.6377778,"width":0.011111111,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise","depth":26,"bounds":{"left":0.24652778,"top":0.6611111,"width":0.33333334,"height":0.19111112},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts","depth":27,"bounds":{"left":0.2888889,"top":0.68,"width":0.28055555,"height":0.04},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.2888889,"top":0.68,"width":0.0034722222,"height":0.02}},{"char_start":1,"char_count":68,"bounds":{"left":0.2888889,"top":0.68,"width":0.27708334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20725 in Jira Cloud","depth":28,"bounds":{"left":0.2888889,"top":0.7022222,"width":0.108333334,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":28,"bounds":{"left":0.2888889,"top":0.7022222,"width":0.06527778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Status","depth":27,"bounds":{"left":0.2888889,"top":0.73444444,"width":0.025,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ready for QA","depth":27,"bounds":{"left":0.29166666,"top":0.76111114,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Priority","depth":27,"bounds":{"left":0.37222221,"top":0.73444444,"width":0.029861111,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.37222221,"top":0.73444444,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":7,"bounds":{"left":0.37777779,"top":0.73444444,"width":0.024305556,"height":0.017777778}}],"role_description":"text"},{"role":"AXStaticText","text":"Medium","depth":27,"bounds":{"left":0.3888889,"top":0.76111114,"width":0.038194444,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Assignee","depth":27,"bounds":{"left":0.44652778,"top":0.73444444,"width":0.035416666,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":27,"bounds":{"left":0.46319443,"top":0.76111114,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"As of today at 4:00 PM","depth":28,"bounds":{"left":0.25555557,"top":0.81777775,"width":0.09166667,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Refresh","depth":28,"bounds":{"left":0.34930557,"top":0.82222223,"width":0.030555556,"height":0.008888889},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open in Jira","depth":28,"bounds":{"left":0.43333334,"top":0.8111111,"width":0.06458333,"height":0.031111112},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"✨ Summarise","depth":28,"bounds":{"left":0.5,"top":0.8111111,"width":0.07361111,"height":0.031111112},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Open in browser","depth":27,"bounds":{"left":0.44791666,"top":0.68,"width":0.047222223,"height":0.035555556},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Open","depth":28,"bounds":{"left":0.46736112,"top":0.6888889,"width":0.022222223,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Share Bug JY-20725","depth":27,"bounds":{"left":0.5013889,"top":0.68,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View conversations","depth":27,"bounds":{"left":0.5236111,"top":0.68,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More actions","depth":27,"bounds":{"left":0.54583335,"top":0.68,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"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.21666667,"top":0.88,"width":0.7652778,"height":0.04222222},"on_screen":true,"value":"да","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"да","depth":25,"bounds":{"left":0.225,"top":0.89111114,"width":0.011805556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"20 results","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Channel","depth":11,"on_screen":false,"role_description":"text"}]...
|
8632182743796168260
|
-1280335566006336684
|
visual_change
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Aneliya Angelova
Apr 28th at 5:16:20 PM
5:16 PM
и за двете ли говориш
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
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
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:51:36 PM
2:51
трябва да се за всички, някъде не се ли попълва
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:52:10 PM
2:52
при зохо май беше hardcoded но май и там си връщаха две категории
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 4:00:37 PM
4:00 PM
Лукаш имаш ли време да се чуем за тестването на
https://jiminny.atlassian.net/browse/JY-20725
https://jiminny.atlassian.net/browse/JY-20725
Jira Cloud
Jira Cloud
Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise
[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts
Bug JY-20725 in Jira Cloud
Preview in Slack
Status
Ready for QA
Priority
Medium
Assignee
Aneliya Angelova
As of today at 4:00 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug JY-20725
View conversations
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
да
да
20 results
Channel
HomeDMsActivityFilesLater..•MoreSlackFileEditViewEDJiminny ...scnicre# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Direct messagesP. Aneliya Angelova€. Vasil Vasilev E. Galya DimitrovaStefka Stoyanova: Todor StamatovMario GeorgievNikolay IvanovLo James Graham2 Stoyan TanevSteliyan GeorgievPetko KashinskiLukas Kovalik y...AppsToastJira CloudGoHistoryWindowHelpQDescribe what you are looking forAneliya AngelovaMessagesAdd canvas@ Files+у лукаш за нuDspot за синковете вече се използва тази команда нали«crm: sync-hubspot-objectsLukas Kovalik 1:32 PMда крон я пуска през 5 минlall100% C8•Thu 14 May 16:02:02Monday, May 11th ~Today ~Aneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?при останалите CRMi трябва рьчно да се въведатLukas Kovalik 2:47 PMздрастиами не знам по принцип се вика при всичкитрябва да се за всички, някъде не се ли попълвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725Jira Cloud[HubSpot] Optimise CRM rematching on delete hubspot ac...Bug JY-20725 in Jira CloudStatusReady for QAPriority= MediumAssigneeAA Aneliya AngelovaAs of today at 4:00 PMOpen in JiraSummariseNewда+Aa...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43598
|
1589
|
29
|
2026-05-14T13:02:06.237053+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763726237_m1.jpg...
|
Slack
|
Aneliya Angelova (DM) - Jiminny Inc - 3 new items Aneliya Angelova (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
Jump to date
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:51:36 PM
2:51
трябва да се за всички, някъде не се ли попълва
React with white_check_mark
React with eyes...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.011805556,"top":0.08111111,"width":0.025,"height":0.04},"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.00625,"top":0.14,"width":0.036111113,"height":0.075555556},"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.013888889,"top":0.19222222,"width":0.020833334,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.00625,"top":0.21555555,"width":0.036111113,"height":0.075555556},"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.015972223,"top":0.26777777,"width":0.016666668,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.00625,"top":0.2911111,"width":0.036111113,"height":0.075555556},"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.011111111,"top":0.34333333,"width":0.027083334,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.011111111,"top":0.34333333,"width":0.0055555557,"height":0.015555556}},{"char_start":1,"char_count":7,"bounds":{"left":0.015972223,"top":0.34333333,"width":0.022222223,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.00625,"top":0.36666667,"width":0.036111113,"height":0.075555556},"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.016666668,"top":0.4188889,"width":0.015972223,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.016666668,"top":0.4188889,"width":0.004166667,"height":0.015555556}},{"char_start":1,"char_count":4,"bounds":{"left":0.020833334,"top":0.4188889,"width":0.011805556,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.00625,"top":0.4422222,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.49444443,"width":0.018055556,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.00625,"top":0.5177778,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.57,"width":0.01875,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.039583333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.036805555,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.06111111,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.18472221,"top":0.12777779,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.050694443,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.09166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.093055554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.046527777,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.025694445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.022222223,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.072222225,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.057638887,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.054166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.034027778,"height":0.007777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.088194445,"top":0.14666666,"width":0.048611112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.072916664,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":15,"bounds":{"left":0.094444446,"top":0.17777778,"width":0.06666667,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.088194445,"top":0.20888889,"width":0.08055556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.088194445,"top":0.24,"width":0.035416666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.088194445,"top":0.2711111,"width":0.036805555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.05138889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":11,"bounds":{"left":0.093055554,"top":0.30222222,"width":0.045833334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.088194445,"top":0.33333334,"width":0.036111113,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.088194445,"top":0.36444443,"width":0.05138889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.094444446,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.004166667,"height":0.02}},{"char_start":1,"char_count":20,"bounds":{"left":0.09236111,"top":0.39555556,"width":0.09861111,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.088194445,"top":0.46888888,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.088194445,"top":0.5,"width":0.055555556,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.5,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.094444446,"top":0.5,"width":0.048611112,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.088194445,"top":0.5311111,"width":0.07361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.088194445,"top":0.56222224,"width":0.079166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"bounds":{"left":0.088194445,"top":0.5933333,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.6244444,"width":0.07152778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"bounds":{"left":0.088194445,"top":0.65555555,"width":0.06736111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.088194445,"top":0.68666667,"width":0.06666667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.088194445,"top":0.7177778,"width":0.060416665,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.7488889,"width":0.07986111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"bounds":{"left":0.088194445,"top":0.78,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.088194445,"top":0.8111111,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.15555556,"top":0.8111111,"width":0.013194445,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.15555556,"top":0.8111111,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":2,"bounds":{"left":0.16041666,"top":0.8111111,"width":0.011805556,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.088194445,"top":0.8844444,"width":0.025694445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.088194445,"top":0.91555554,"width":0.045833334,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.21319444,"top":0.12777779,"width":0.06458333,"height":0.04222222},"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.2326389,"top":0.14,"width":0.039583333,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.27986112,"top":0.12777779,"width":0.07152778,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"bounds":{"left":0.29930556,"top":0.14,"width":0.046527777,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.35347223,"top":0.12777779,"width":0.04375,"height":0.04222222},"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.37291667,"top":0.14,"width":0.01875,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.37291667,"top":0.14,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":4,"bounds":{"left":0.3784722,"top":0.14,"width":0.013194445,"height":0.017777778}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.4,"top":0.12777779,"width":0.022222223,"height":0.04222222},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":23,"bounds":{"left":0.5465278,"top":0.16111112,"width":0.10555556,"height":0.0011111111},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"bounds":{"left":0.31111112,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:16:54 PM","depth":24,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:16 PM","depth":25,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами ще го деплойна но ако нещо гръмне","depth":25,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.19791667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.08125,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"bounds":{"left":0.32777777,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:04 PM","depth":24,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17 PM","depth":25,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"аа разбрахте","depth":25,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.061805554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:07 PM","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17","depth":26,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:14 PM","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":26,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Галя каза че не се използва фичъра","depth":25,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.16875,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:22 PM","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":26,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и няма проблем да гръмне","depth":25,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.12916666,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":23,"bounds":{"left":0.5472222,"top":0.17666666,"width":0.104166664,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.08125,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"bounds":{"left":0.32777777,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:24:41 PM","depth":24,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:24 PM","depth":25,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш за Hubspot за синковете вече се използва тази команда нали?","depth":25,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.3326389,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"crm:sync-hubspot-objects","depth":26,"bounds":{"left":0.24930556,"top":0.16111112,"width":0.12013889,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.06458333,"height":0.023333333},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"bounds":{"left":0.31111112,"top":0.16222222,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:32:50 PM","depth":24,"bounds":{"left":0.31666666,"top":0.16555555,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:32 PM","depth":25,"bounds":{"left":0.31666666,"top":0.16555555,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"да крон я пуска през 5 мин","depth":25,"bounds":{"left":0.24652778,"top":0.18666667,"width":0.12986112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":23,"bounds":{"left":0.5729167,"top":0.22888888,"width":0.05277778,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":24,"bounds":{"left":0.24652778,"top":0.27222222,"width":0.08125,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"bounds":{"left":0.32777777,"top":0.27444443,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:30:26 PM","depth":24,"bounds":{"left":0.33333334,"top":0.2777778,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30 PM","depth":25,"bounds":{"left":0.33333334,"top":0.2777778,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?","depth":25,"bounds":{"left":0.24652778,"top":0.2988889,"width":0.5069444,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:30:45 PM","depth":25,"bounds":{"left":0.22430556,"top":0.33555555,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30","depth":26,"bounds":{"left":0.22430556,"top":0.33555555,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"при останалите CRMi трябва ръчно да се въведат","depth":25,"bounds":{"left":0.24652778,"top":0.33222222,"width":0.24166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":24,"bounds":{"left":0.24652778,"top":0.36333334,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"bounds":{"left":0.31111112,"top":0.36555555,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:47:56 PM","depth":24,"bounds":{"left":0.31666666,"top":0.36888888,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:47 PM","depth":25,"bounds":{"left":0.31666666,"top":0.36888888,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти","depth":25,"bounds":{"left":0.24652778,"top":0.39,"width":0.03888889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:48:14 PM","depth":25,"bounds":{"left":0.22430556,"top":0.42666668,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:48","depth":26,"bounds":{"left":0.22430556,"top":0.42666668,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами не знам по принцип се вика при всички","depth":25,"bounds":{"left":0.24652778,"top":0.42333335,"width":0.21111111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:51:36 PM","depth":25,"bounds":{"left":0.22430556,"top":0.46,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:51","depth":26,"bounds":{"left":0.22430556,"top":0.46,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"трябва да се за всички, някъде не се ли попълва","depth":25,"bounds":{"left":0.24652778,"top":0.45666668,"width":0.2326389,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-6570503125874196360
|
-4018383230026192810
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
Jump to date
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:51:36 PM
2:51
трябва да се за всички, някъде не се ли попълва
React with white_check_mark
React with eyes
HomeDMsActivityFilesLater..•MoreSlackFileEditViewGoHistoryEDJiminny ...scnicre.# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Direct messagesP. Aneliya Angelova€. Vasil Vasilev E. Galya Dimitrova&. Stefka Stoyanova: Todor StamatovMario GeorgievNikolay IvanovLo James Graham2 Stoyan TanevSteliyan GeorgievPetko KashinskiLukas Kovalik y...AppsToastJira CloudWindowHelpQDescribe what you are looking forAneliya Angelova• MessagesAdd canvas© FilesLukas KovaliK 1:32 PMда крон я пуска през 5 мин+‹$0hhl100% C8• Thu 14 May 16:02:05Monday, May 11th ~Today ~Aneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?при останалите CRMi трябва ръчно да се въведатLukas Kovalik 2:47 PMздрастиами не знам по принцип се вика при всичкитрябва да се за всички, някъде не се ли попълвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725Jira Cloud -[HubSpot) Optimise CRM rematching on delete hubspot ac...T Bug JY-20725 in Jira CloudStatusReady for QAPriority= MediumAssigneeAA Aneliya AngelovaAs of today at 4:00 PMOpen in Jira. SummariseLukas Kovalik 4:02 PMдаMessage Aneliya Angelova+New...
|
43597
|
NULL
|
NULL
|
NULL
|
|
43599
|
1590
|
28
|
2026-05-14T13:02:06.267851+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763726267_m2.jpg...
|
Slack
|
Aneliya Angelova (DM) - Jiminny Inc - 3 new items Aneliya Angelova (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
Jump to date
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
React with eyes...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.27593085,"top":1.0,"width":0.011968086,"height":-0.058260202},"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,"bounds":{"left":0.30718085,"top":1.0,"width":0.018949468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.01761968,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.02925532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.3587101,"top":1.0,"width":0.0026595744,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.024268618,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.043882977,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.04454787,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.022273935,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.012300532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.010638298,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.034574468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.027593086,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.025930852,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.016289894,"height":-0.09177971},"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":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","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,"bounds":{"left":0.3723404,"top":1.0,"width":0.030917553,"height":-0.09177971},"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":"Add canvas","depth":18,"bounds":{"left":0.40425533,"top":1.0,"width":0.034242023,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.43949467,"top":1.0,"width":0.020944148,"height":-0.09177971},"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":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.46176863,"top":1.0,"width":0.010638298,"height":-0.09177971},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":23,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:16:54 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:16 PM","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами ще го деплойна но ако нещо гръмне","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:04 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17 PM","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"аа разбрахте","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:07 PM","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:14 PM","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Галя каза че не се използва фичъра","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:22 PM","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и няма проблем да гръмне","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":23,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:24:41 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:24 PM","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш за Hubspot за синковете вече се използва тази команда нали?","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"crm:sync-hubspot-objects","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:32:50 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:32 PM","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"да крон я пуска през 5 мин","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":23,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:30:26 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30 PM","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:30:45 PM","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"при останалите CRMi трябва ръчно да се въведат","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":24,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:47:56 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:47 PM","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:48:14 PM","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:48","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами не знам по принцип се вика при всички","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-153697898793875418
|
-3838239244965074858
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
Jump to date
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
React with eyes
• Goodle geminiPlatform Sprint 4 02 - PlatformJY-20903 Update activity sta XSRD-6849) Recorded call doesUsage | Windsurf4(SRD-68481 Sidekick SMS issue1.lY-208911 Sidekick SMS issueJY-20891 add support for seconcR (SRD-6849) Recorded call does r[JY-20903] Recorded call does r[SRD-6853] Moxso - Potential d@ JY-20903 Update activity stage* Configure SSH access to multiple c* Useful commands - EngineeringA 1y-20004 Eiv HndateAotivituFlad(JY-20904) Fix UpdateActivityElaSJliminnv- New Tabhow to unpin slackmessaceUnpinning a message in Slack is straightforward,though the steps vary slightly depending onwhether you are using the desktop app or themobile version.On Desktop (Mac/Windows/Web)1. Open the channel or DM where themessage is pinned.2. Click the Pinned icon (the thumbtack)located just below the channel name orheader at the top of the screen. This opensa sidebar showing all pinned items.3. Find the message you want to unpin andhover over It4. Click the "X" icon that appears next to themessage in the sidebar, then click Removeto confirm.Alternative Method: Find themessade direct v in the chat historv.click the three-dot icon (Moreactions on the message, ano selectUnpin from channel.Enter a prompt for GeminiFastvAl lt can make mistakes so double check it Your orivacv &. G.Summarize pagejiminny / app &<> Code%? Pull requests 29G. Agents Actions M Wiki ® Security and qualityInsights ộ Settings© On April 24 we'll start using GitHub Copilot interaction data for Al model training unless you opt out. Review this update and manage your preferences in your GitHub account settingsJY-20903 Update activity stage when opportunity is changed #12077 •LakyLak wants to merge 2 commits into master from JY-20903-update_activity-stage-on-opportunity-changeW Conversation4• CommitsiE Checks 2Files changed 1• Filter files..~ E app/ModelsActivity.phpapp/Models/Activity-php d ++C0 -2119,12 +2119,14 @ public function updateActivityCrmData(array srecords): void2119sthis->account_id = saccount->id;21202121HEEEif (Sthis->stage_id === null && Sstage) €Sthis->stage_id = sstage->id;2127if (Sopportunity && Sthis->opportunitv id I== Sopportunitv->id) {sthis->opportunity_id = sopportunity->id;2128212921301if (Sopportunity && Sthis->value !== Sopportunity-›value) {2119212021212122212321282220 :213021312132100% • Inu 14 May 10:02•00Q Type D to search• Checks pending• 0 I 1 viewedcode-+6 -4 00022Submit review - (ộ3+6 -4 manaa [ Viewed@ ..Sthis->account_id = Saccount->id:if (Sopportunity && $this->opportunity_id !== Sopportunity->id) {sthis->opportunity_id = sopportunity->id;// Reset stage_id when opportunity changes to avoid stale stage from previous opportunity matchsthis->stage_id = $stage?->id;if (Sthis->stage id === null && Sstage) ‹sthis->stage_id = sstage->id;if (Sopportunity && Sthis-›value !== Sopportunity->value) {...
|
43596
|
NULL
|
NULL
|
NULL
|
|
43600
|
1589
|
30
|
2026-05-14T13:02:07.355958+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763727355_m1.jpg...
|
Control Centre
|
Control Centre
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Wi‑Fi
Focus
Bluetooth
AirDrop
Stage Manager
Screen Wi‑Fi
Focus
Bluetooth
AirDrop
Stage Manager
Screen Mirroring
Display
Sound
Airplay Audio
Music.app
play
next...
|
[{"role":"AXCheckBox","text [{"role":"AXCheckBox","text":"Wi‑Fi","depth":2,"bounds":{"left":0.79583335,"top":0.093888886,"width":0.093055554,"height":0.045555554},"on_screen":true,"automation_id":"controlcenter-wifi","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXCheckBox","text":"Focus","depth":2,"bounds":{"left":0.8958333,"top":0.086666666,"width":0.093055554,"height":0.06888889},"on_screen":true,"automation_id":"controlcenter-focus-modes","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXCheckBox","text":"Bluetooth","depth":2,"bounds":{"left":0.79583335,"top":0.13833334,"width":0.0875,"height":0.045555554},"on_screen":true,"automation_id":"controlcenter-bluetooth","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXCheckBox","text":"AirDrop","depth":2,"bounds":{"left":0.79583335,"top":0.18277778,"width":0.093055554,"height":0.045555554},"on_screen":true,"automation_id":"controlcenter-airdrop","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXButton","text":"Stage Manager","depth":2,"bounds":{"left":0.90260416,"top":0.17722222,"width":0.029513888,"height":0.050555557},"on_screen":true,"automation_id":"controlcenter-stagemanager","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXButton","text":"Screen Mirroring","depth":2,"bounds":{"left":0.9458333,"top":0.16666667,"width":0.043055557,"height":0.06888889},"on_screen":true,"automation_id":"controlcenter-screen-mirroring","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXStaticText","text":"Display","depth":3,"bounds":{"left":0.80277777,"top":0.25388888,"width":0.029513888,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sound","depth":2,"bounds":{"left":0.80277777,"top":0.3338889,"width":0.025694445,"height":0.016666668},"on_screen":true,"automation_id":"controlcenter-volume","role_description":"text"},{"role":"AXCheckBox","text":"Airplay Audio","depth":2,"bounds":{"left":0.9638889,"top":0.35555556,"width":0.018055556,"height":0.028888889},"on_screen":true,"automation_id":"controlcenter-airplay","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXStaticText","text":"Music.app","depth":2,"bounds":{"left":0.8375,"top":0.4327778,"width":0.041666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"play","depth":2,"bounds":{"left":0.9458333,"top":0.42666668,"width":0.018055556,"height":0.028888889},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"next","depth":2,"bounds":{"left":0.9638889,"top":0.42666668,"width":0.018055556,"height":0.028888889},"on_screen":true,"role_description":"button","is_enabled":false}]...
|
-8871609275972961978
|
9172942166022350908
|
click
|
hybrid
|
NULL
|
Wi‑Fi
Focus
Bluetooth
AirDrop
Stage Manager
Screen Wi‑Fi
Focus
Bluetooth
AirDrop
Stage Manager
Screen Mirroring
Display
Sound
Airplay Audio
Music.app
play
next
HomeDMsActivityFilesLater..•MoreSlackFileEditViewGoHistoryWindowHelpEDQDescribe what you are looking forJiminny ...scnicre.# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Aneliya Angelova• MessagesAdd canvas© FilesLukas KovaliK 1:32 PMда крон я пуска през 5 мин+Direct messagesP. Aneliya Angelova€. Vasil Vasilev E. Galya Dimitrova&. Stefka Stoyanova: Todor StamatovMario GeorgievNikolay IvanovLo James Graham2 Stoyan TanevSteliyan GeorgievPetko KashinskiLukas Kovalik y...AppsToastJira Cloudlahl19Monday, May 11th ~Today ~Aneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?при останалите CRMi трябва ръчно да се въведатLukas Kovalik 2:47 PMздрастиами не знам по принцип се вика при всичкитрябва да се за всички, някъде не се ли попълвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725Jira Cloud -[HubSpot) Optimise CRM rematching on delete hubspot ac...T Bug JY-20725 in Jira CloudStatusReady for QAPriority= MediumAssigneeAA Aneliya AngelovaAs of today at 4:00 PMOpen in Jira. SummariseLukas Kovalik 4:02 PMдаMessage Aneliya Angelova+100% C478•Thu 14 May 16:02:06iTermWi-FiOffBluetoothOnAirDropOffDisplaySoundFOCusStageManagerScreenMirroringMusic.appNew...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43601
|
1590
|
29
|
2026-05-14T13:02:07.382219+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763727382_m2.jpg...
|
Control Centre
|
Control Centre
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Wi‑Fi
Focus
Bluetooth
AirDrop
Stage Manager
Screen Wi‑Fi
Focus
Bluetooth
AirDrop
Stage Manager
Screen Mirroring
Display
Sound
Airplay Audio
Music.app
play
next...
|
[{"role":"AXCheckBox","text [{"role":"AXCheckBox","text":"Wi‑Fi","depth":2,"bounds":{"left":0.6512633,"top":1.0,"width":0.04454787,"height":-0.067438126},"on_screen":true,"automation_id":"controlcenter-wifi","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXCheckBox","text":"Focus","depth":2,"bounds":{"left":0.69913566,"top":1.0,"width":0.04454787,"height":-0.062250614},"on_screen":true,"automation_id":"controlcenter-focus-modes","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXCheckBox","text":"Bluetooth","depth":2,"bounds":{"left":0.6512633,"top":1.0,"width":0.041888297,"height":-0.09936154},"on_screen":true,"automation_id":"controlcenter-bluetooth","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXCheckBox","text":"AirDrop","depth":2,"on_screen":true,"automation_id":"controlcenter-airdrop","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXButton","text":"Stage Manager","depth":2,"on_screen":true,"automation_id":"controlcenter-stagemanager","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXButton","text":"Screen Mirroring","depth":2,"on_screen":true,"automation_id":"controlcenter-screen-mirroring","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXStaticText","text":"Display","depth":3,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sound","depth":2,"on_screen":true,"automation_id":"controlcenter-volume","role_description":"text"},{"role":"AXCheckBox","text":"Airplay Audio","depth":2,"on_screen":true,"automation_id":"controlcenter-airplay","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXStaticText","text":"Music.app","depth":2,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"play","depth":2,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"next","depth":2,"on_screen":true,"role_description":"button","is_enabled":false}]...
|
-8871609275972961978
|
9172942166022350908
|
click
|
hybrid
|
NULL
|
Wi‑Fi
Focus
Bluetooth
AirDrop
Stage Manager
Screen Wi‑Fi
Focus
Bluetooth
AirDrop
Stage Manager
Screen Mirroring
Display
Sound
Airplay Audio
Music.app
play
next
• Goodle geminiPlatform Sprint 4 02 - PlatformJY-20903 Update activity sta XSRD-6849) Recorded call doesUsage | Windsurf4(SRD-68481 Sidekick SMS issue1.lY-208911 Sidekick SMS issueJY-20891 add support for seconcR (SRD-6849) Recorded call does r[JY-20903] Recorded call does r[SRD-6853] Moxso - Potential d@ JY-20903 Update activity stage* Configure SSH access to multiple c* Useful commands - EngineeringA 1y-20004 Eiv HndateAotivituFlad(JY-20904) Fix UpdateActivityElaSJliminnv- New Tabhow to unpin slackmessaceUnpinning a message in Slack is straightforward,though the steps vary slightly depending onwhether you are using the desktop app or themobile version.On Desktop (Mac/Windows/Web)1. Open the channel or DM where themessage is pinned.2. Click the Pinned icon (the thumbtack)located just below the channel name orheader at the top of the screen. This opensa sidebar showing all pinned items.3. Find the message you want to unpin andhover over It4. Click the "X" icon that appears next to themessage in the sidebar, then click Removeto confirm.Alternative Method: Find themessade direct v in the chat historv.click the three-dot icon (Moreactions on the message, ano selectUnpin from channel.Enter a prompt for GeminiFastvAl lt can make mistakes so double check it Your orivacv &. G.Summarize pagejiminny / app &<> Code%? Pull requests 29G. Agents Actions M Wiki ® Security and qualityInsights ộ Settings© On April 24 we'll start using GitHub Copilot interaction data for Al model training unless you opt out. Review this update and manage your preferences in your GitHub account settingsJY-20903 Update activity stage when opportunity is changed #12077 •LakyLak wants to merge 2 commits into master from JY-20903-update_activity-stage-on-opportunity-changeW Conversation4• CommitsiE Checks 2Files changed 1• Filter files..~ E app/ModelsActivity.phpapp/Models/Activity-php d ++C0 -2119,12 +2119,14 @ public function updateActivityCrmData(array srecords): void2119sthis->account_id = saccount->id;21202121HEEEif (Sthis->stage_id === null && Sstage) €Sthis->stage_id = sstage->id;2127if (Sopportunity && Sthis->opportunitv id I== Sopportunitv->id) {sthis->opportunity_id = sopportunity->id;2128212921301if (Sopportunity && Sthis->value !== Sopportunity-›value) {2119212021212122212321282220 :213021312132100% • Inu 14 May 10:02•0/Q Type D to search• Checks pending• 0 I 1 viewedcode-+6 -4 00022Submit review - (ộ3+6 -4 manaa [ Viewed@ ..Sthis->account_id = Saccount->id:if (Sopportunity && $this->opportunity_id !== Sopportunity->id) {sthis->opportunity_id = sopportunity->id;// Reset stage_id when opportunity changes to avoid stale stage from previous opportunity matchsthis->stage_id = $stage?->id;if (Sthis->stage id === null && Sstage) ‹sthis->stage_id = sstage->id;if (Sopportunity && Sthis-›value !== Sopportunity->value) {...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43602
|
1589
|
31
|
2026-05-14T13:02:09.108690+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763729108_m1.jpg...
|
Control Centre
|
Control Centre
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Bluetooth
Bluetooth
Devices
Lukas’s Magic Mouse, 2 Bluetooth
Bluetooth
Devices
Lukas’s Magic Mouse, 24%
LakyLak bose qc35 II
M720 Triathlon
Magic Keyboard
Magic Keyboard
soundcore AeroClip
Soundcore Life Dot 2 NC
Bluetooth Settings…...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Bluetooth","depth":2,"bounds":{"left":0.7916667,"top":0.04777778,"width":0.042708334,"height":0.017777778},"on_screen":true,"automation_id":"bluetooth-header","role_description":"text"},{"role":"AXCheckBox","text":"Bluetooth","depth":2,"bounds":{"left":0.9527778,"top":0.044444446,"width":0.02638889,"height":0.024444444},"on_screen":true,"automation_id":"bluetooth-header","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false},{"role":"AXHeading","text":"Devices","depth":3,"bounds":{"left":0.7916667,"top":0.090555556,"width":0.032291666,"height":0.016666668},"on_screen":true,"role_description":"heading"},{"role":"AXCheckBox","text":"Lukas’s Magic Mouse, 24%","depth":3,"bounds":{"left":0.78541666,"top":0.11111111,"width":0.2,"height":0.035555556},"on_screen":true,"automation_id":"bluetooth-device-Lukas’s Magic Mouse","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXCheckBox","text":"LakyLak bose qc35 II","depth":3,"bounds":{"left":0.78541666,"top":0.14666666,"width":0.2,"height":0.035555556},"on_screen":true,"automation_id":"bluetooth-device-LakyLak bose qc35 II","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXCheckBox","text":"M720 Triathlon","depth":3,"bounds":{"left":0.78541666,"top":0.18222222,"width":0.2,"height":0.035555556},"on_screen":true,"automation_id":"bluetooth-device-M720 Triathlon","role_description":"toggle button","subrole":"AXToggle","is_enabled":false},{"role":"AXCheckBox","text":"Magic Keyboard","depth":3,"bounds":{"left":0.78541666,"top":0.21777777,"width":0.2,"height":0.035555556},"on_screen":true,"automation_id":"bluetooth-device-Magic Keyboard","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXCheckBox","text":"Magic Keyboard","depth":3,"bounds":{"left":0.78541666,"top":0.25333333,"width":0.2,"height":0.035555556},"on_screen":true,"automation_id":"bluetooth-device-Magic Keyboard","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXCheckBox","text":"soundcore AeroClip","depth":3,"bounds":{"left":0.78541666,"top":0.2888889,"width":0.2,"height":0.035555556},"on_screen":true,"automation_id":"bluetooth-device-soundcore AeroClip","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXCheckBox","text":"Soundcore Life Dot 2 NC","depth":3,"bounds":{"left":0.78541666,"top":0.32444444,"width":0.2,"height":0.035555556},"on_screen":true,"automation_id":"bluetooth-device-Soundcore Life Dot 2 NC","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXButton","text":"Bluetooth Settings…","depth":2,"bounds":{"left":0.78541666,"top":0.37555555,"width":0.09791667,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false}]...
|
-5958019404780460135
|
-3633298540936623419
|
visual_change
|
hybrid
|
NULL
|
Bluetooth
Bluetooth
Devices
Lukas’s Magic Mouse, 2 Bluetooth
Bluetooth
Devices
Lukas’s Magic Mouse, 24%
LakyLak bose qc35 II
M720 Triathlon
Magic Keyboard
Magic Keyboard
soundcore AeroClip
Soundcore Life Dot 2 NC
Bluetooth Settings…
HomeDMsActivityFilesLater..•MoreSlackFileEditViewGoHistoryEDJiminny ...scnicre.# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Direct messagesP. Aneliya Angelova€. Vasil Vasilev E. Galya Dimitrova&. Stefka Stoyanova: Todor StamatovMario GeorgievNikolay IvanovLo James Graham2 Stoyan TanevSteliyan GeorgievPetko KashinskiLukas Kovalik y...AppsToastJira CloudWindowHelpQDescribe what you are looking forAneliya Angelova• MessagesAdd canvas© FilesLukas KovaliK 1:32 PMда крон я пуска през 5 мин+lahl19Monday, May 11th ~Today ~Aneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?при останалите CRMi трябва ръчно да се въведатLukas Kovalik 2:47 PMздрастиами не знам по принцип се вика при всичкитрябва да се за всички, някъде не се ли попълвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725Jira Cloud -[HubSpot) Optimise CRM rematching on delete hubspot ac...T Bug JY-20725 in Jira CloudStatusReady for QAPriority= MediumAssigneeAA Aneliya AngelovaAs of today at 4:00 PMOpen in Jira. SummariseLukas Kovalik 4:02 PMдаMessage Aneliya Angelova+100% C478•Thu 14 May 16:02:08BluetoothDevicesLukas's Magic Mouse24% 0LakyLak bose qc35 llM720 TriathionMagic KeyboardMagic Keyboardsoundcore AeroClipSoundcore Life Dot 2 NCBluetooth Settings...New...
|
43600
|
NULL
|
NULL
|
NULL
|
|
43603
|
1590
|
30
|
2026-05-14T13:02:09.538834+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763729538_m2.jpg...
|
Control Centre
|
Control Centre
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Bluetooth
Bluetooth
Devices
Lukas’s Magic Mouse, 2 Bluetooth
Bluetooth
Devices
Lukas’s Magic Mouse, 24%
LakyLak bose qc35 II
M720 Triathlon
Magic Keyboard
Magic Keyboard
soundcore AeroClip
Soundcore Life Dot 2 NC
Bluetooth Settings…...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Bluetooth","depth":2,"bounds":{"left":0.6492686,"top":1.0,"width":0.02044548,"height":-0.034317613},"on_screen":true,"automation_id":"bluetooth-header","role_description":"text"},{"role":"AXCheckBox","text":"Bluetooth","depth":2,"bounds":{"left":0.72639626,"top":1.0,"width":0.012632979,"height":-0.031923413},"on_screen":true,"automation_id":"bluetooth-header","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false},{"role":"AXHeading","text":"Devices","depth":3,"bounds":{"left":0.6492686,"top":1.0,"width":0.015458777,"height":-0.065043926},"on_screen":true,"role_description":"heading"},{"role":"AXCheckBox","text":"Lukas’s Magic Mouse, 24%","depth":3,"bounds":{"left":0.6462766,"top":1.0,"width":0.095744684,"height":-0.07980847},"on_screen":true,"automation_id":"bluetooth-device-Lukas’s Magic Mouse","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXCheckBox","text":"LakyLak bose qc35 II","depth":3,"on_screen":true,"automation_id":"bluetooth-device-LakyLak bose qc35 II","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXCheckBox","text":"M720 Triathlon","depth":3,"on_screen":true,"automation_id":"bluetooth-device-M720 Triathlon","role_description":"toggle button","subrole":"AXToggle","is_enabled":false},{"role":"AXCheckBox","text":"Magic Keyboard","depth":3,"on_screen":true,"automation_id":"bluetooth-device-Magic Keyboard","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXCheckBox","text":"Magic Keyboard","depth":3,"on_screen":true,"automation_id":"bluetooth-device-Magic Keyboard","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXCheckBox","text":"soundcore AeroClip","depth":3,"on_screen":true,"automation_id":"bluetooth-device-soundcore AeroClip","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXCheckBox","text":"Soundcore Life Dot 2 NC","depth":3,"on_screen":true,"automation_id":"bluetooth-device-Soundcore Life Dot 2 NC","role_description":"toggle button","subrole":"AXToggle","is_enabled":true},{"role":"AXButton","text":"Bluetooth Settings…","depth":2,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false}]...
|
-5958019404780460135
|
-3633298540936623419
|
click
|
hybrid
|
NULL
|
Bluetooth
Bluetooth
Devices
Lukas’s Magic Mouse, 2 Bluetooth
Bluetooth
Devices
Lukas’s Magic Mouse, 24%
LakyLak bose qc35 II
M720 Triathlon
Magic Keyboard
Magic Keyboard
soundcore AeroClip
Soundcore Life Dot 2 NC
Bluetooth Settings…
• Goodle geminiPlatform Sprint 4 02 - PlatformJY-20903 Update activity sta XSRD-6849) Recorded call doesUsage | Windsurf4(SRD-68481 Sidekick SMS issue1.lY-208911 Sidekick SMS issueJY-20891 add support for seconcR (SRD-6849) Recorded call does r[JY-20903] Recorded call does r[SRD-6853] Moxso - Potential d@ JY-20903 Update activity stage* Configure SSH access to multiple c* Useful commands - EngineeringA 1y-20004 Eiv HndateAotivituFlad(JY-20904) Fix UpdateActivityElaSJliminnv- New Tabhow to unpin slackmessaceUnpinning a message in Slack is straightforward,though the steps vary slightly depending onwhether you are using the desktop app or themobile version.On Desktop (Mac/Windows/Web)1. Open the channel or DM where themessage is pinned.2. Click the Pinned icon (the thumbtack)located just below the channel name orheader at the top of the screen. This opensa sidebar showing all pinned items.3. Find the message you want to unpin andhover over It4. Click the "X" icon that appears next to themessage in the sidebar, then click Removeto confirm.Alternative Method: Find themessade direct v in the chat historv.click the three-dot icon (Moreactions on the message, ano selectUnpin from channel.Enter a prompt for GeminiFastvAl lt can make mistakes so double check it Your orivacv &. G.Summarize pagejiminny / app &<> Code%? Pull requests 29G. Agents Actions M Wiki ® Security and qualityInsights ộ Settings© On April 24 we'll start using GitHub Copilot interaction data for Al model training unless you opt out. Review this update and manage your preferences in your GitHub account settingsJY-20903 Update activity stage when opportunity is changed #12077 •LakyLak wants to merge 2 commits into master from JY-20903-update_activity-stage-on-opportunity-changeW Conversation4• CommitsiE Checks 2Files changed 1• Filter files..~ E app/ModelsActivity.phpapp/Models/Activity-php d ++C0 -2119,12 +2119,14 @ public function updateActivityCrmData(array srecords): void2119sthis->account_id = saccount->id;21202121HEEEif (Sthis->stage_id === null && Sstage) €Sthis->stage_id = sstage->id;2127if (Sopportunity && Sthis->opportunitv id I== Sopportunitv->id) {sthis->opportunity_id = sopportunity->id;2128212921301if (Sopportunity && Sthis->value !== Sopportunity-›value) {2119212021212122212321282220 :213021312132100% • Inu 14 May 16:02-09Q Type D to search• Checks pending• 0 I 1 viewedcode-+6 -4 00022Submit review - (ộ3+6 -4 manaa [ Viewed@ ..Sthis->account_id = Saccount->id:if (Sopportunity && $this->opportunity_id !== Sopportunity->id) {sthis->opportunity_id = sopportunity->id;// Reset stage_id when opportunity changes to avoid stale stage from previous opportunity matchsthis->stage_id = $stage?->id;if (Sthis->stage id === null && Sstage) ‹sthis->stage_id = sstage->id;if (Sopportunity && Sthis-›value !== Sopportunity->value) {...
|
43601
|
NULL
|
NULL
|
NULL
|
|
43605
|
1590
|
31
|
2026-05-14T13:02:14.325069+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763734325_m2.jpg...
|
Slack
|
Aneliya Angelova (DM) - Jiminny Inc - 3 new items Aneliya Angelova (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
Jump to date
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.27593085,"top":1.0,"width":0.011968086,"height":-0.058260202},"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,"bounds":{"left":0.30718085,"top":1.0,"width":0.018949468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.01761968,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.02925532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.3587101,"top":1.0,"width":0.0026595744,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.024268618,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.043882977,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.04454787,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.022273935,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.012300532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.010638298,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.034574468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.027593086,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.025930852,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.016289894,"height":-0.09177971},"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":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","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,"bounds":{"left":0.3723404,"top":1.0,"width":0.030917553,"height":-0.09177971},"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":"Add canvas","depth":18,"bounds":{"left":0.40425533,"top":1.0,"width":0.034242023,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.43949467,"top":1.0,"width":0.020944148,"height":-0.09177971},"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":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.46176863,"top":1.0,"width":0.010638298,"height":-0.09177971},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:16:54 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:16 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами ще го деплойна но ако нещо гръмне","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:04 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"аа разбрахте","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:07 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:14 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Галя каза че не се използва фичъра","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:22 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и няма проблем да гръмне","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:24:41 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:24 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш за Hubspot за синковете вече се използва тази команда нали?","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"crm:sync-hubspot-objects","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:32:50 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:32 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"да крон я пуска през 5 мин","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:30:26 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:30:45 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"при останалите CRMi трябва ръчно да се въведат","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:47:56 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:47 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-323990574448926052
|
-3694124056826304170
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
Jump to date
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
• Goodle geminiPlatform Sprint 4 02 - PlatformJY-20903 Update activity sta XSRD-6849) Recorded call doesUsage | Windsurf4(SRD-68481 Sidekick SMS issue1.lY-208911 Sidekick SMS issueJY-20891 add support for seconcR (SRD-6849) Recorded call does r[JY-20903] Recorded call does r[SRD-6853] Moxso - Potential d@ JY-20903 Update activity stage* Configure SSH access to multiple c* Useful commands - EngineeringA 1y-20004 Eiv HndateAotivituFlad(JY-20904) Fix UpdateActivityElaSJliminnv- New Tabhow to unpin slackmessaceUnpinning a message in Slack is straightforward,though the steps vary slightly depending onwhether you are using the desktop app or themobile version.On Desktop (Mac/Windows/Web)1. Open the channel or DM where themessage is pinned.2. Click the Pinned icon (the thumbtack)located just below the channel name orheader at the top of the screen. This opensa sidebar showing all pinned items.3. Find the message you want to unpin andhover over It4. Click the "X" icon that appears next to themessage in the sidebar, then click Removeto confirm.Alternative Method: Find themessade direct v in the chat historv.click the three-dot icon (Moreactions on the message, ano selectUnpin from channel.Enter a prompt for GeminiFastvAl lt can make mistakes so double check it Your orivacv &. G.Summarize pagejiminny / app &<> Code%? Pull requests 29G. Agents Actions M Wiki ® Security and qualityInsights ộ Settings© On April 24 we'll start using GitHub Copilot interaction data for Al model training unless you opt out. Review this update and manage your preferences in your GitHub account settingsJY-20903 Update activity stage when opportunity is changed #12077 •LakyLak wants to merge 2 commits into master from JY-20903-update_activity-stage-on-opportunity-changeW Conversation4• CommitsiE Checks 2Files changed 1• Filter files..~ E app/ModelsActivity.phpapp/Models/Activity-php d ++C0 -2119,12 +2119,14 @ public function updateActivityCrmData(array srecords): void2119sthis->account_id = saccount->id;21202121HEEEif (Sthis->stage_id === null && Sstage) €Sthis->stage_id = sstage->id;2127if (Sopportunity && Sthis->opportunitv id I== Sopportunitv->id) {sthis->opportunity_id = sopportunity->id;2128212921301if (Sopportunity && Sthis->value !== Sopportunity-›value) {2119212021212122212321282220 :213021312132100% • Inu 14 May 10:02-13Q Type D to search• Checks pending• 0 I 1 viewedcode-+6 -4 00022Submit review - (ộ3+6 -4 manaa [ Viewed@ ..Sthis->account_id = Saccount->id:if (Sopportunity && $this->opportunity_id !== Sopportunity->id) {sthis->opportunity_id = sopportunity->id;// Reset stage_id when opportunity changes to avoid stale stage from previous opportunity matchsthis->stage_id = $stage?->id;if (Sthis->stage id === null && Sstage) ‹sthis->stage_id = sstage->id;if (Sopportunity && Sthis-›value !== Sopportunity->value) {...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43604
|
1589
|
32
|
2026-05-14T13:02:14.325126+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763734325_m1.jpg...
|
Slack
|
Aneliya Angelova (DM) - Jiminny Inc - 3 new items Aneliya Angelova (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
Jump to date
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:51:36 PM
2:51
трябва да се за всички, някъде не се ли попълва
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:52:10 PM
2:52
при зохо май беше hardcoded но май и там си връщаха две категории
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 4:00:37 PM
4:00 PM
Лукаш имаш ли време да се чуем за тестването на
https://jiminny.atlassian.net/browse/JY-20725
https://jiminny.atlassian.net/browse/JY-20725
Jira Cloud
Jira Cloud
Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise
[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts
Bug JY-20725 in Jira Cloud
Preview in Slack
Status
Ready for QA
Priority
Medium
Assignee
Aneliya Angelova
As of today at 4:00 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug JY-20725
View conversations
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...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.011805556,"top":0.08111111,"width":0.025,"height":0.04},"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.00625,"top":0.14,"width":0.036111113,"height":0.075555556},"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.013888889,"top":0.19222222,"width":0.020833334,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.00625,"top":0.21555555,"width":0.036111113,"height":0.075555556},"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.015972223,"top":0.26777777,"width":0.016666668,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.00625,"top":0.2911111,"width":0.036111113,"height":0.075555556},"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.011111111,"top":0.34333333,"width":0.027083334,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.011111111,"top":0.34333333,"width":0.0055555557,"height":0.015555556}},{"char_start":1,"char_count":7,"bounds":{"left":0.015972223,"top":0.34333333,"width":0.022222223,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.00625,"top":0.36666667,"width":0.036111113,"height":0.075555556},"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.016666668,"top":0.4188889,"width":0.015972223,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.016666668,"top":0.4188889,"width":0.004166667,"height":0.015555556}},{"char_start":1,"char_count":4,"bounds":{"left":0.020833334,"top":0.4188889,"width":0.011805556,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.00625,"top":0.4422222,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.49444443,"width":0.018055556,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.00625,"top":0.5177778,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.57,"width":0.01875,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.039583333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.036805555,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.06111111,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.18472221,"top":0.12777779,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.050694443,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.09166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.093055554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.046527777,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.025694445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.022222223,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.072222225,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.057638887,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.054166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.034027778,"height":0.007777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.088194445,"top":0.14666666,"width":0.048611112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.072916664,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":15,"bounds":{"left":0.094444446,"top":0.17777778,"width":0.06666667,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.088194445,"top":0.20888889,"width":0.08055556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.088194445,"top":0.24,"width":0.035416666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.088194445,"top":0.2711111,"width":0.036805555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.05138889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":11,"bounds":{"left":0.093055554,"top":0.30222222,"width":0.045833334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.088194445,"top":0.33333334,"width":0.036111113,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.088194445,"top":0.36444443,"width":0.05138889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.094444446,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.004166667,"height":0.02}},{"char_start":1,"char_count":20,"bounds":{"left":0.09236111,"top":0.39555556,"width":0.09861111,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.088194445,"top":0.46888888,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.088194445,"top":0.5,"width":0.055555556,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.5,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.094444446,"top":0.5,"width":0.048611112,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.088194445,"top":0.5311111,"width":0.07361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.088194445,"top":0.56222224,"width":0.079166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"bounds":{"left":0.088194445,"top":0.5933333,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.6244444,"width":0.07152778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"bounds":{"left":0.088194445,"top":0.65555555,"width":0.06736111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.088194445,"top":0.68666667,"width":0.06666667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.088194445,"top":0.7177778,"width":0.060416665,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.7488889,"width":0.07986111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"bounds":{"left":0.088194445,"top":0.78,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.088194445,"top":0.8111111,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.15555556,"top":0.8111111,"width":0.013194445,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.15555556,"top":0.8111111,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":2,"bounds":{"left":0.16041666,"top":0.8111111,"width":0.011805556,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.088194445,"top":0.8844444,"width":0.025694445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.088194445,"top":0.91555554,"width":0.045833334,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.21319444,"top":0.12777779,"width":0.06458333,"height":0.04222222},"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.2326389,"top":0.14,"width":0.039583333,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.27986112,"top":0.12777779,"width":0.07152778,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"bounds":{"left":0.29930556,"top":0.14,"width":0.046527777,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.35347223,"top":0.12777779,"width":0.04375,"height":0.04222222},"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.37291667,"top":0.14,"width":0.01875,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.37291667,"top":0.14,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":4,"bounds":{"left":0.3784722,"top":0.14,"width":0.013194445,"height":0.017777778}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.4,"top":0.12777779,"width":0.022222223,"height":0.04222222},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5465278,"top":0.16111112,"width":0.10555556,"height":0.0011111111},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:16:54 PM","depth":23,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:16 PM","depth":24,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами ще го деплойна но ако нещо гръмне","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.19791667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.08125,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:04 PM","depth":23,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17 PM","depth":24,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"аа разбрахте","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.061805554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:07 PM","depth":24,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:14 PM","depth":24,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Галя каза че не се използва фичъра","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.16875,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:22 PM","depth":24,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и няма проблем да гръмне","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.12916666,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5472222,"top":0.17666666,"width":0.104166664,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.08125,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:24:41 PM","depth":23,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:24 PM","depth":24,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш за Hubspot за синковете вече се използва тази команда нали?","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.3326389,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"crm:sync-hubspot-objects","depth":25,"bounds":{"left":0.24930556,"top":0.16111112,"width":0.12013889,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.06458333,"height":0.023333333},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.16222222,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:32:50 PM","depth":23,"bounds":{"left":0.31666666,"top":0.16555555,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:32 PM","depth":24,"bounds":{"left":0.31666666,"top":0.16555555,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"да крон я пуска през 5 мин","depth":24,"bounds":{"left":0.24652778,"top":0.18666667,"width":0.12986112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5729167,"top":0.22888888,"width":0.05277778,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.27222222,"width":0.08125,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.27444443,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:30:26 PM","depth":23,"bounds":{"left":0.33333334,"top":0.2777778,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30 PM","depth":24,"bounds":{"left":0.33333334,"top":0.2777778,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?","depth":24,"bounds":{"left":0.24652778,"top":0.2988889,"width":0.5069444,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:30:45 PM","depth":24,"bounds":{"left":0.22430556,"top":0.33555555,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30","depth":25,"bounds":{"left":0.22430556,"top":0.33555555,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"при останалите CRMi трябва ръчно да се въведат","depth":24,"bounds":{"left":0.24652778,"top":0.33222222,"width":0.24166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.36333334,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.36555555,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:47:56 PM","depth":23,"bounds":{"left":0.31666666,"top":0.36888888,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:47 PM","depth":24,"bounds":{"left":0.31666666,"top":0.36888888,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти","depth":24,"bounds":{"left":0.24652778,"top":0.39,"width":0.03888889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:48:14 PM","depth":24,"bounds":{"left":0.22430556,"top":0.42666668,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:48","depth":25,"bounds":{"left":0.22430556,"top":0.42666668,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами не знам по принцип се вика при всички","depth":24,"bounds":{"left":0.24652778,"top":0.42333335,"width":0.21111111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:51:36 PM","depth":24,"bounds":{"left":0.22430556,"top":0.46,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:51","depth":25,"bounds":{"left":0.22430556,"top":0.46,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"трябва да се за всички, някъде не се ли попълва","depth":24,"bounds":{"left":0.24652778,"top":0.45666668,"width":0.2326389,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:52:10 PM","depth":24,"bounds":{"left":0.22430556,"top":0.49333334,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"bounds":{"left":0.22430556,"top":0.49333334,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"при зохо май беше hardcoded но май и там си връщаха две категории","depth":24,"bounds":{"left":0.24652778,"top":0.49,"width":0.3361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"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.96458334,"top":0.50777775,"width":0.01875,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.52111113,"width":0.08125,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.5233333,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:00:37 PM","depth":23,"bounds":{"left":0.33333334,"top":0.52666664,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:00 PM","depth":24,"bounds":{"left":0.33333334,"top":0.52666664,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш имаш ли време да се чуем за тестването на","depth":24,"bounds":{"left":0.24652778,"top":0.5477778,"width":0.24722221,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20725","depth":24,"bounds":{"left":0.49305555,"top":0.5477778,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20725","depth":25,"bounds":{"left":0.49305555,"top":0.5477778,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.24652778,"top":0.58,"width":0.039583333,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.24652778,"top":0.58,"width":0.004166667,"height":0.017777778}},{"char_start":1,"char_count":9,"bounds":{"left":0.25069445,"top":0.58,"width":0.035416666,"height":0.017777778}}],"role_description":"text"},{"role":"AXButton","text":"Jira Cloud","depth":23,"bounds":{"left":0.2888889,"top":0.58,"width":0.011111111,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise","depth":25,"bounds":{"left":0.24652778,"top":0.60333335,"width":0.33333334,"height":0.19111112},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts","depth":26,"bounds":{"left":0.2888889,"top":0.62222224,"width":0.28055555,"height":0.04},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.2888889,"top":0.62222224,"width":0.0034722222,"height":0.02}},{"char_start":1,"char_count":68,"bounds":{"left":0.2888889,"top":0.62222224,"width":0.27708334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20725 in Jira Cloud","depth":27,"bounds":{"left":0.2888889,"top":0.64444447,"width":0.108333334,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"bounds":{"left":0.2888889,"top":0.64444447,"width":0.06527778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Status","depth":26,"bounds":{"left":0.2888889,"top":0.6766667,"width":0.025,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ready for QA","depth":26,"bounds":{"left":0.29166666,"top":0.7033333,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Priority","depth":26,"bounds":{"left":0.37222221,"top":0.6766667,"width":0.029861111,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.37222221,"top":0.6766667,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":7,"bounds":{"left":0.37777779,"top":0.6766667,"width":0.024305556,"height":0.017777778}}],"role_description":"text"},{"role":"AXStaticText","text":"Medium","depth":26,"bounds":{"left":0.3888889,"top":0.7033333,"width":0.038194444,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Assignee","depth":26,"bounds":{"left":0.44652778,"top":0.6766667,"width":0.035416666,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":26,"bounds":{"left":0.46319443,"top":0.7033333,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"As of today at 4:00 PM","depth":27,"bounds":{"left":0.25555557,"top":0.76,"width":0.09166667,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Refresh","depth":27,"bounds":{"left":0.34930557,"top":0.7644445,"width":0.030555556,"height":0.008888889},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open in Jira","depth":27,"bounds":{"left":0.43333334,"top":0.75333333,"width":0.06458333,"height":0.031111112},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"✨ Summarise","depth":27,"bounds":{"left":0.5,"top":0.75333333,"width":0.07361111,"height":0.031111112},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Open in browser","depth":26,"bounds":{"left":0.44791666,"top":0.62222224,"width":0.047222223,"height":0.035555556},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Open","depth":27,"bounds":{"left":0.46736112,"top":0.6311111,"width":0.022222223,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Share Bug JY-20725","depth":26,"bounds":{"left":0.5013889,"top":0.62222224,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View conversations","depth":26,"bounds":{"left":0.5236111,"top":0.62222224,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More actions","depth":26,"bounds":{"left":0.54583335,"top":0.62222224,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1303159874844392738
|
-1424450754082206892
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
Jump to date
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:51:36 PM
2:51
трябва да се за всички, някъде не се ли попълва
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:52:10 PM
2:52
при зохо май беше hardcoded но май и там си връщаха две категории
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 4:00:37 PM
4:00 PM
Лукаш имаш ли време да се чуем за тестването на
https://jiminny.atlassian.net/browse/JY-20725
https://jiminny.atlassian.net/browse/JY-20725
Jira Cloud
Jira Cloud
Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise
[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts
Bug JY-20725 in Jira Cloud
Preview in Slack
Status
Ready for QA
Priority
Medium
Assignee
Aneliya Angelova
As of today at 4:00 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug JY-20725
View conversations
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
HomeDMsActivityFilesLater..•MoreSlackFileEditViewGoHistoryEDJiminny ...scnicre.# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Direct messagesP. Aneliya Angelova€. Vasil Vasilev E. Galya Dimitrova&. Stefka Stoyanova: Todor StamatovMario GeorgievNikolay IvanovLo James Graham2 Stoyan TanevSteliyan GeorgievPetko KashinskiLukas Kovalik y...AppsToastJira CloudWindowHelpQDescribe what you are looking forAneliya Angelova• MessagesAdd canvas© FilesLukas KovaliK 1:32 PMда крон я пуска през 5 мин+lahl19Monday, May 11th ~Today ~Aneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?при останалите CRMi трябва ръчно да се въведатLukas Kovalik 2:47 PMздрастиами не знам по принцип се вика при всичкитрябва да се за всички, някъде не се ли попълвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725Jira Cloud -[HubSpot) Optimise CRM rematching on delete hubspot ac...T Bug JY-20725 in Jira CloudStatusReady for QAPriority= MediumAssigneeAA Aneliya AngelovaAs of today at 4:00 PMOpen in Jira. SummariseLukas Kovalik 4:02 PMдаMessage Aneliya Angelova+100% C478•Thu 14 May 16:02:13BluetoothDevicesLukas's Magic Mouse24% 0LakyLak bose qc35 llM720 TriathionMagic KeyboardMagic Keyboardsoundcore AeroClipSoundcore Life Dot 2 NCBluetooth Settings...New...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43606
|
1589
|
33
|
2026-05-14T13:02:15.158410+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763735158_m1.jpg...
|
Slack
|
Aneliya Angelova (DM) - Jiminny Inc - 3 new items Aneliya Angelova (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
Jump to date
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:51:36 PM
2:51
трябва да се за всички, някъде не се ли попълва
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:52:10 PM
2:52
при зохо май беше hardcoded но май и там си връщаха две категории
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 4:00:37 PM
4:00 PM
Лукаш имаш ли време да се чуем за тестването на
https://jiminny.atlassian.net/browse/JY-20725
https://jiminny.atlassian.net/browse/JY-20725
Jira Cloud
Jira Cloud
Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise
[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts
Bug JY-20725 in Jira Cloud
Preview in Slack
Status
Ready for QA
Priority
Medium
Assignee
Aneliya Angelova
As of today at 4:00 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug JY-20725
View conversations
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
Lukas Kovalik
Today at 4:02:04 PM
4:02 PM
да
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
20 results
Channel...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.011805556,"top":0.08111111,"width":0.025,"height":0.04},"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.00625,"top":0.14,"width":0.036111113,"height":0.075555556},"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.013888889,"top":0.19222222,"width":0.020833334,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.00625,"top":0.21555555,"width":0.036111113,"height":0.075555556},"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.015972223,"top":0.26777777,"width":0.016666668,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.00625,"top":0.2911111,"width":0.036111113,"height":0.075555556},"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.011111111,"top":0.34333333,"width":0.027083334,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.011111111,"top":0.34333333,"width":0.0055555557,"height":0.015555556}},{"char_start":1,"char_count":7,"bounds":{"left":0.015972223,"top":0.34333333,"width":0.022222223,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.00625,"top":0.36666667,"width":0.036111113,"height":0.075555556},"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.016666668,"top":0.4188889,"width":0.015972223,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.016666668,"top":0.4188889,"width":0.004166667,"height":0.015555556}},{"char_start":1,"char_count":4,"bounds":{"left":0.020833334,"top":0.4188889,"width":0.011805556,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.00625,"top":0.4422222,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.49444443,"width":0.018055556,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.00625,"top":0.5177778,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.57,"width":0.01875,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.039583333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.036805555,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.06111111,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.18472221,"top":0.12777779,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.050694443,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.09166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.093055554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.046527777,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.025694445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.022222223,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.072222225,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.057638887,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.054166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.034027778,"height":0.007777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.088194445,"top":0.14666666,"width":0.048611112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.072916664,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":15,"bounds":{"left":0.094444446,"top":0.17777778,"width":0.06666667,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.088194445,"top":0.20888889,"width":0.08055556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.088194445,"top":0.24,"width":0.035416666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.088194445,"top":0.2711111,"width":0.036805555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.05138889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":11,"bounds":{"left":0.093055554,"top":0.30222222,"width":0.045833334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.088194445,"top":0.33333334,"width":0.036111113,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.088194445,"top":0.36444443,"width":0.05138889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.094444446,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.004166667,"height":0.02}},{"char_start":1,"char_count":20,"bounds":{"left":0.09236111,"top":0.39555556,"width":0.09861111,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.088194445,"top":0.46888888,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.088194445,"top":0.5,"width":0.055555556,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.5,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.094444446,"top":0.5,"width":0.048611112,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.088194445,"top":0.5311111,"width":0.07361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.088194445,"top":0.56222224,"width":0.079166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"bounds":{"left":0.088194445,"top":0.5933333,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.6244444,"width":0.07152778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"bounds":{"left":0.088194445,"top":0.65555555,"width":0.06736111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.088194445,"top":0.68666667,"width":0.06666667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.088194445,"top":0.7177778,"width":0.060416665,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.7488889,"width":0.07986111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"bounds":{"left":0.088194445,"top":0.78,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.088194445,"top":0.8111111,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.15555556,"top":0.8111111,"width":0.013194445,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.15555556,"top":0.8111111,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":2,"bounds":{"left":0.16041666,"top":0.8111111,"width":0.011805556,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.088194445,"top":0.8844444,"width":0.025694445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.088194445,"top":0.91555554,"width":0.045833334,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.21319444,"top":0.12777779,"width":0.06458333,"height":0.04222222},"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.2326389,"top":0.14,"width":0.039583333,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.27986112,"top":0.12777779,"width":0.07152778,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"bounds":{"left":0.29930556,"top":0.14,"width":0.046527777,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.35347223,"top":0.12777779,"width":0.04375,"height":0.04222222},"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.37291667,"top":0.14,"width":0.01875,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.37291667,"top":0.14,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":4,"bounds":{"left":0.3784722,"top":0.14,"width":0.013194445,"height":0.017777778}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.4,"top":0.12777779,"width":0.022222223,"height":0.04222222},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5465278,"top":0.16111112,"width":0.10555556,"height":0.0011111111},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:16:54 PM","depth":23,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:16 PM","depth":24,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами ще го деплойна но ако нещо гръмне","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.19791667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.08125,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:04 PM","depth":23,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17 PM","depth":24,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"аа разбрахте","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.061805554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:07 PM","depth":24,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:14 PM","depth":24,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Галя каза че не се използва фичъра","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.16875,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:22 PM","depth":24,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и няма проблем да гръмне","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.12916666,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5472222,"top":0.17666666,"width":0.104166664,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.08125,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:24:41 PM","depth":23,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:24 PM","depth":24,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш за Hubspot за синковете вече се използва тази команда нали?","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.3326389,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"crm:sync-hubspot-objects","depth":25,"bounds":{"left":0.24930556,"top":0.16111112,"width":0.12013889,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.06458333,"height":0.023333333},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.16222222,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:32:50 PM","depth":23,"bounds":{"left":0.31666666,"top":0.16555555,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:32 PM","depth":24,"bounds":{"left":0.31666666,"top":0.16555555,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"да крон я пуска през 5 мин","depth":24,"bounds":{"left":0.24652778,"top":0.18666667,"width":0.12986112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5729167,"top":0.22888888,"width":0.05277778,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.27222222,"width":0.08125,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.27444443,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:30:26 PM","depth":23,"bounds":{"left":0.33333334,"top":0.2777778,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30 PM","depth":24,"bounds":{"left":0.33333334,"top":0.2777778,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?","depth":24,"bounds":{"left":0.24652778,"top":0.2988889,"width":0.5069444,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:30:45 PM","depth":24,"bounds":{"left":0.22430556,"top":0.33555555,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30","depth":25,"bounds":{"left":0.22430556,"top":0.33555555,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"при останалите CRMi трябва ръчно да се въведат","depth":24,"bounds":{"left":0.24652778,"top":0.33222222,"width":0.24166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.36333334,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.36555555,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:47:56 PM","depth":23,"bounds":{"left":0.31666666,"top":0.36888888,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:47 PM","depth":24,"bounds":{"left":0.31666666,"top":0.36888888,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти","depth":24,"bounds":{"left":0.24652778,"top":0.39,"width":0.03888889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:48:14 PM","depth":24,"bounds":{"left":0.22430556,"top":0.42666668,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:48","depth":25,"bounds":{"left":0.22430556,"top":0.42666668,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами не знам по принцип се вика при всички","depth":24,"bounds":{"left":0.24652778,"top":0.42333335,"width":0.21111111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:51:36 PM","depth":24,"bounds":{"left":0.22430556,"top":0.46,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:51","depth":25,"bounds":{"left":0.22430556,"top":0.46,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"трябва да се за всички, някъде не се ли попълва","depth":24,"bounds":{"left":0.24652778,"top":0.45666668,"width":0.2326389,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:52:10 PM","depth":24,"bounds":{"left":0.22430556,"top":0.49333334,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"bounds":{"left":0.22430556,"top":0.49333334,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"при зохо май беше hardcoded но май и там си връщаха две категории","depth":24,"bounds":{"left":0.24652778,"top":0.49,"width":0.3361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"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.96458334,"top":0.50777775,"width":0.01875,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.52111113,"width":0.08125,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.5233333,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:00:37 PM","depth":23,"bounds":{"left":0.33333334,"top":0.52666664,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:00 PM","depth":24,"bounds":{"left":0.33333334,"top":0.52666664,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш имаш ли време да се чуем за тестването на","depth":24,"bounds":{"left":0.24652778,"top":0.5477778,"width":0.24722221,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20725","depth":24,"bounds":{"left":0.49305555,"top":0.5477778,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20725","depth":25,"bounds":{"left":0.49305555,"top":0.5477778,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.24652778,"top":0.58,"width":0.039583333,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.24652778,"top":0.58,"width":0.004166667,"height":0.017777778}},{"char_start":1,"char_count":9,"bounds":{"left":0.25069445,"top":0.58,"width":0.035416666,"height":0.017777778}}],"role_description":"text"},{"role":"AXButton","text":"Jira Cloud","depth":23,"bounds":{"left":0.2888889,"top":0.58,"width":0.011111111,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise","depth":25,"bounds":{"left":0.24652778,"top":0.60333335,"width":0.33333334,"height":0.19111112},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts","depth":26,"bounds":{"left":0.2888889,"top":0.62222224,"width":0.28055555,"height":0.04},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.2888889,"top":0.62222224,"width":0.0034722222,"height":0.02}},{"char_start":1,"char_count":68,"bounds":{"left":0.2888889,"top":0.62222224,"width":0.27708334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20725 in Jira Cloud","depth":27,"bounds":{"left":0.2888889,"top":0.64444447,"width":0.108333334,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"bounds":{"left":0.2888889,"top":0.64444447,"width":0.06527778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Status","depth":26,"bounds":{"left":0.2888889,"top":0.6766667,"width":0.025,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ready for QA","depth":26,"bounds":{"left":0.29166666,"top":0.7033333,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Priority","depth":26,"bounds":{"left":0.37222221,"top":0.6766667,"width":0.029861111,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.37222221,"top":0.6766667,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":7,"bounds":{"left":0.37777779,"top":0.6766667,"width":0.024305556,"height":0.017777778}}],"role_description":"text"},{"role":"AXStaticText","text":"Medium","depth":26,"bounds":{"left":0.3888889,"top":0.7033333,"width":0.038194444,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Assignee","depth":26,"bounds":{"left":0.44652778,"top":0.6766667,"width":0.035416666,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":26,"bounds":{"left":0.46319443,"top":0.7033333,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"As of today at 4:00 PM","depth":27,"bounds":{"left":0.25555557,"top":0.76,"width":0.09166667,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Refresh","depth":27,"bounds":{"left":0.34930557,"top":0.7644445,"width":0.030555556,"height":0.008888889},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open in Jira","depth":27,"bounds":{"left":0.43333334,"top":0.75333333,"width":0.06458333,"height":0.031111112},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"✨ Summarise","depth":27,"bounds":{"left":0.5,"top":0.75333333,"width":0.07361111,"height":0.031111112},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Open in browser","depth":26,"bounds":{"left":0.44791666,"top":0.62222224,"width":0.047222223,"height":0.035555556},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Open","depth":27,"bounds":{"left":0.46736112,"top":0.6311111,"width":0.022222223,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Share Bug JY-20725","depth":26,"bounds":{"left":0.5013889,"top":0.62222224,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View conversations","depth":26,"bounds":{"left":0.5236111,"top":0.62222224,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More actions","depth":26,"bounds":{"left":0.54583335,"top":0.62222224,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.80777776,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.81,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:02:04 PM","depth":23,"bounds":{"left":0.31666666,"top":0.81333333,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:02 PM","depth":24,"bounds":{"left":0.31666666,"top":0.81333333,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"да","depth":24,"bounds":{"left":0.24652778,"top":0.83444446,"width":0.011805556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"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.21666667,"top":0.88,"width":0.7652778,"height":0.04222222},"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"20 results","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Channel","depth":11,"on_screen":false,"role_description":"text"}]...
|
-2475778446504125654
|
-1712681130233904300
|
visual_change
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
Jump to date
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:51:36 PM
2:51
трябва да се за всички, някъде не се ли попълва
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:52:10 PM
2:52
при зохо май беше hardcoded но май и там си връщаха две категории
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 4:00:37 PM
4:00 PM
Лукаш имаш ли време да се чуем за тестването на
https://jiminny.atlassian.net/browse/JY-20725
https://jiminny.atlassian.net/browse/JY-20725
Jira Cloud
Jira Cloud
Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise
[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts
Bug JY-20725 in Jira Cloud
Preview in Slack
Status
Ready for QA
Priority
Medium
Assignee
Aneliya Angelova
As of today at 4:00 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug JY-20725
View conversations
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
Lukas Kovalik
Today at 4:02:04 PM
4:02 PM
да
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
20 results
Channel
HomeDMsActivityFilesLater..•MoreSlackFileEditViewGoHistoryEDJiminny ...scnicre.# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Direct messagesP. Aneliya Angelova€. Vasil Vasilev E. Galya Dimitrova&. Stefka Stoyanova: Todor StamatovMario GeorgievNikolay IvanovLo James Graham2 Stoyan TanevSteliyan GeorgievPetko KashinskiLukas Kovalik y...AppsToastJira CloudWindowHelpQDescribe what you are looking forAneliya Angelova• MessagesAdd canvas© FilesLukas KovaliK 1:32 PMда крон я пуска през 5 мин+‹$0hhl100% С8• Thu 14 May 16:02:14Monday, May 11th ~Today ~Aneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?при останалите CRMi трябва ръчно да се въведатLukas Kovalik 2:47 PMздрастиами не знам по принцип се вика при всичкитрябва да се за всички, някъде не се ли попълвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725Jira Cloud -[HubSpot) Optimise CRM rematching on delete hubspot ac...T Bug JY-20725 in Jira CloudStatusReady for QAPriority= MediumAssigneeAA Aneliya AngelovaAs of today at 4:00 PMOpen in Jira. SummariseLukas Kovalik 4:02 PMдаMessage Aneliya Angelova+New...
|
43604
|
NULL
|
NULL
|
NULL
|
|
43608
|
1590
|
32
|
2026-05-14T13:02:25.161146+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763745161_m2.jpg...
|
Firefox
|
JY-20903 Update activity stage when opportunity is JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12077/changes
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
• Goodle geminiPlatform Sprint 4 02 - PlatformJY-2 • Goodle geminiPlatform Sprint 4 02 - PlatformJY-20903 Update activity sta XSRD-6849) Recorded call doesUsage | Windsurf4(SRD-68481 Sidekick SMS issue1.lY-208911 Sidekick SMS issueJY-20891 add support for seconcR (SRD-6849) Recorded call does r[JY-20903] Recorded call does r[SRD-6853] Moxso - Potential d@ JY-20903 Update activity stage* Configure SSH access to multiple c* Useful commands - EngineeringA 1y-20004 Eiv HndateAotivituFlad(JY-20904) Fix UpdateActivityElaSJliminnv- New Tabhow to unpin slackmessaceUnpinning a message in Slack is straightforward,though the steps vary slightly depending onwhether you are using the desktop app or themobile version.On Desktop (Mac/Windows/Web)1. Open the channel or DM where themessage is pinned.2. Click the Pinned icon (the thumbtack)located just below the channel name orheader at the top of the screen. This opensa sidebar showing all pinned items.3. Find the message you want to unpin andhover over It4. Click the "X" icon that appears next to themessage in the sidebar, then click Removeto confirm.Alternative Method: Find themessade direct v in the chat historv.click the three-dot icon (Moreactions on the message, ano selectUnpin from channel.Enter a prompt for GeminiFastvAl lt can make mistakes so double check it Your orivacv &. G.Summarize pagejiminny / app &<> Code%? Pull requests 29G. Agents Actions M Wiki ® Security and qualityInsights ộ Settings© On April 24 we'll start using GitHub Copilot interaction data for Al model training unless you opt out. Review this update and manage your preferences in your GitHub account settingsJY-20903 Update activity stage when opportunity is changed #12077 •LakyLak wants to merge 2 commits into master from JY-20903-update_activity-stage-on-opportunity-changeW Conversation4• CommitsiE Checks 2Files changed 1• Filter files..~ E app/ModelsActivity.phpapp/Models/Activity-php d +C0 -2119,12 +2119,14 @ public function updateActivityCrmData(array srecords): void2119sthis->account_id = saccount->id;21202121HEEEif (Sthis->stage_id === null && Sstage) €Sthis->stage_id = sstage->id;2127if (Sopportunity && Sthis->opportunitv id I== Sopportunitv->id) {sthis->opportunity_id = sopportunity->id;2128212921301if (Sopportunity && Sthis->value !== Sopportunity-›value) {2119212021212122212321282220 :213021312132100% • Inu 14 May 10:02-24Q Type D to search• Checks pending• 0 I 1 viewedcode-+6 -4 00022Submit review - (ộ3+6 -4 manaa [ Viewed@ ..Sthis->account_id = Saccount->id:if (Sopportunity && $this->opportunity_id !== Sopportunity->id) {sthis->opportunity_id = sopportunity->id;// Reset stage_id when opportunity changes to avoid stale stage from previous opportunity matchsthis->stage_id = $stage?->id;if (Sthis->stage id === null && Sstage) ‹sthis->stage_id = sstage->id;if (Sopportunity && Sthis-›value !== Sopportunity->value) {...
|
NULL
|
-5918014028895118593
|
NULL
|
click
|
ocr
|
NULL
|
• Goodle geminiPlatform Sprint 4 02 - PlatformJY-2 • Goodle geminiPlatform Sprint 4 02 - PlatformJY-20903 Update activity sta XSRD-6849) Recorded call doesUsage | Windsurf4(SRD-68481 Sidekick SMS issue1.lY-208911 Sidekick SMS issueJY-20891 add support for seconcR (SRD-6849) Recorded call does r[JY-20903] Recorded call does r[SRD-6853] Moxso - Potential d@ JY-20903 Update activity stage* Configure SSH access to multiple c* Useful commands - EngineeringA 1y-20004 Eiv HndateAotivituFlad(JY-20904) Fix UpdateActivityElaSJliminnv- New Tabhow to unpin slackmessaceUnpinning a message in Slack is straightforward,though the steps vary slightly depending onwhether you are using the desktop app or themobile version.On Desktop (Mac/Windows/Web)1. Open the channel or DM where themessage is pinned.2. Click the Pinned icon (the thumbtack)located just below the channel name orheader at the top of the screen. This opensa sidebar showing all pinned items.3. Find the message you want to unpin andhover over It4. Click the "X" icon that appears next to themessage in the sidebar, then click Removeto confirm.Alternative Method: Find themessade direct v in the chat historv.click the three-dot icon (Moreactions on the message, ano selectUnpin from channel.Enter a prompt for GeminiFastvAl lt can make mistakes so double check it Your orivacv &. G.Summarize pagejiminny / app &<> Code%? Pull requests 29G. Agents Actions M Wiki ® Security and qualityInsights ộ Settings© On April 24 we'll start using GitHub Copilot interaction data for Al model training unless you opt out. Review this update and manage your preferences in your GitHub account settingsJY-20903 Update activity stage when opportunity is changed #12077 •LakyLak wants to merge 2 commits into master from JY-20903-update_activity-stage-on-opportunity-changeW Conversation4• CommitsiE Checks 2Files changed 1• Filter files..~ E app/ModelsActivity.phpapp/Models/Activity-php d +C0 -2119,12 +2119,14 @ public function updateActivityCrmData(array srecords): void2119sthis->account_id = saccount->id;21202121HEEEif (Sthis->stage_id === null && Sstage) €Sthis->stage_id = sstage->id;2127if (Sopportunity && Sthis->opportunitv id I== Sopportunitv->id) {sthis->opportunity_id = sopportunity->id;2128212921301if (Sopportunity && Sthis->value !== Sopportunity-›value) {2119212021212122212321282220 :213021312132100% • Inu 14 May 10:02-24Q Type D to search• Checks pending• 0 I 1 viewedcode-+6 -4 00022Submit review - (ộ3+6 -4 manaa [ Viewed@ ..Sthis->account_id = Saccount->id:if (Sopportunity && $this->opportunity_id !== Sopportunity->id) {sthis->opportunity_id = sopportunity->id;// Reset stage_id when opportunity changes to avoid stale stage from previous opportunity matchsthis->stage_id = $stage?->id;if (Sthis->stage id === null && Sstage) ‹sthis->stage_id = sstage->id;if (Sopportunity && Sthis-›value !== Sopportunity->value) {...
|
43605
|
NULL
|
NULL
|
NULL
|
|
43607
|
1589
|
34
|
2026-05-14T13:02:25.161218+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763745161_m1.jpg...
|
Firefox
|
JY-20903 Update activity stage when opportunity is JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12077/changes
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Unnamed Group
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Unnamed Group","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true}]...
|
4647491290173057106
|
3879294778649249660
|
click
|
hybrid
|
NULL
|
Unnamed Group
HomeDMsActivityFilesLater..•MoreSlac Unnamed Group
HomeDMsActivityFilesLater..•MoreSlackFileEditViewEDJiminny ...scnicre.# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Direct messagesP. Aneliya Angelova€. Vasil Vasilev E. Galya Dimitrova&. Stefka Stoyanova: Todor StamatovMario GeorgievNikolay IvanovLo James Graham2 Stoyan TanevSteliyan GeorgievPetko KashinskiLukas Kovalik y...AppsToastJira CloudGoHistoryWindowHelpQDescribe what you are looking forAneliya AngelovaMessagest Add canvas@ Files+lall100% С8•Thu 14 May 16:02:25Monday, May 11th ~Today ~Aneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?при останалите CRMi трябва ръчно да се въведатLukas Kovalik 2:47 PMздрастиами не знам по принцип се вика при всичкитрябва да се за всички, някъде не се ли попьлвапри зохо май беше hardcoded но май и там си врьщаха две категорииAneliya Angelova 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725Jira CloudX Bug IV-20725 in Jira Cloud[HubSpot] Optimise CRM rematching on delete hubspot ac...StatusReady for QAPriority= MediumAssigneeAA Aneliya AngelovaAs of today at 4:00 PMOpen in Jirait SummariseLukas Kovalik 4:02 PMдазвьни направоMessage Aneliya AngelovaNew...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43610
|
1590
|
33
|
2026-05-14T13:02:27.269631+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763747269_m2.jpg...
|
Firefox
|
JY-20903 Update activity stage when opportunity is JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12077/changes
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Unnamed Group
Platform Sprint 4 Q2 - Platform Team Unnamed Group
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app
JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app
Close tab
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Usage | Windsurf
Usage | Windsurf
Unnamed Group
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app
JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app
Unnamed Group
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Unnamed Group
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app
JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Unnamed Group
JY-20904 Fix UpdateActivityElasticSearchDocumentCommand find activity… by LakyLak · Pull Request #12078 · jiminny/app
JY-20904 Fix UpdateActivityElasticSearchDocumentCommand find activity… by LakyLak · Pull Request #12078 · jiminny/app
[JY-20904] Fix UpdateActivityElasticSearchDocumentCommand - Jira
[JY-20904] Fix UpdateActivityElasticSearchDocumentCommand - Jira
Jiminny
Jiminny
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (29)
Pull requests
(
29
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality
Security and quality
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20903 Update activity stage when opportunity is changed #12077 Edit title
JY-20903 Update activity stage when opportunity is changed
#
12077
Edit title
Preview
Preview
Checks pending
Checks pending
Code
Code
Open
LakyLak
LakyLak
wants to merge 2 commits into
master
master
from
JY-20903-update_activity-stage-on-opportunity-change
JY-20903-update_activity-stage-on-opportunity-change
Copy head branch name to clipboard
Lines changed: 6 additions & 4 deletions
Conversation (4)
Conversation
(
4
)
Commits (2)
Commits
(
2
)
Checks (2)
Checks
(
2
)
Files changed (1)
Files changed
(
1
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
All commits
All commits
0 of 1 file viewed
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel
(
1
)
Filter files…
Filter options
File tree
File tree
app/Models
Activity.php
Activity.php
Collapse file
app/Models/Activity.php
app/Models/Activity.php
app/Models/Activity.php
Copy file name to clipboard
Expand all lines: app/Models/Activity.php
Lines changed: 6 additions & 4 deletions
Not Viewed
Viewed
Comment on this file
More options
Original file line number
Original file line
Diff line number
Diff line change
@@ -2119,12 +2119,14 @@ public function updateActivityCrmData(array $records): void
2119
$
this
->
account_id
=
$
account
->
id
;
2119
$
this
->
account_id
=
$
account
->
id
;
2120
}
2120
}
2121
2121
2122
-
if
(
$
this
->
stage_id
===
null
&&...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Unnamed Group","depth":4,"bounds":{"left":0.0028257978,"top":0.057063047,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0028257978,"top":0.08060654,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.015957447,"top":0.09217877,"width":0.101230055,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app","depth":4,"bounds":{"left":0.0028257978,"top":0.11332801,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app","depth":5,"bounds":{"left":0.015957447,"top":0.12490024,"width":0.18932846,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.12051077,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":4,"bounds":{"left":0.0028257978,"top":0.14604948,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.015957447,"top":0.15762171,"width":0.11735372,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Usage | Windsurf","depth":4,"bounds":{"left":0.0,"top":0.17877094,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Usage | Windsurf","depth":5,"bounds":{"left":0.013297873,"top":0.19034317,"width":0.029920213,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Unnamed Group","depth":4,"bounds":{"left":0.0028257978,"top":0.21667998,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"[SRD-6848] Sidekick SMS issue - Jira","depth":4,"bounds":{"left":0.0028257978,"top":0.24022347,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6848] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.015957447,"top":0.25179568,"width":0.06632314,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20891] Sidekick SMS issue - Jira","depth":4,"bounds":{"left":0.0028257978,"top":0.27294493,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20891] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.015957447,"top":0.28451717,"width":0.064494684,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app","depth":4,"bounds":{"left":0.0028257978,"top":0.3056664,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app","depth":5,"bounds":{"left":0.015957447,"top":0.31723863,"width":0.15658244,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Unnamed Group","depth":4,"bounds":{"left":0.0028257978,"top":0.34357542,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":4,"bounds":{"left":0.0028257978,"top":0.36711892,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.015957447,"top":0.37869114,"width":0.11735372,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20903] Recorded call does not appear on the dashboard - Jira","depth":4,"bounds":{"left":0.0028257978,"top":0.39984038,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20903] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.015957447,"top":0.4114126,"width":0.11619016,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0028257978,"top":0.43256184,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.015957447,"top":0.4441341,"width":0.013297873,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0028257978,"top":0.46528333,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.015957447,"top":0.47685555,"width":0.013297873,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0028257978,"top":0.4980048,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.015957447,"top":0.50957704,"width":0.013297873,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Unnamed Group","depth":4,"bounds":{"left":0.0028257978,"top":0.5359138,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":4,"bounds":{"left":0.0028257978,"top":0.5594573,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":5,"bounds":{"left":0.015957447,"top":0.57102954,"width":0.091755316,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app","depth":4,"bounds":{"left":0.0028257978,"top":0.59217876,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app","depth":5,"bounds":{"left":0.015957447,"top":0.603751,"width":0.18932846,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Configure SSH access to multiple environment - Engineering - Confluence","depth":4,"bounds":{"left":0.0,"top":0.6249002,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Configure SSH access to multiple environment - Engineering - Confluence","depth":5,"bounds":{"left":0.013297873,"top":0.63647246,"width":0.12898937,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Useful commands - Engineering - Confluence","depth":4,"bounds":{"left":0.0,"top":0.6576217,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Useful commands - Engineering - Confluence","depth":5,"bounds":{"left":0.013297873,"top":0.6691939,"width":0.079288565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Unnamed Group","depth":4,"bounds":{"left":0.0028257978,"top":0.6955307,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"JY-20904 Fix UpdateActivityElasticSearchDocumentCommand find activity… by LakyLak · Pull Request #12078 · jiminny/app","depth":4,"bounds":{"left":0.0028257978,"top":0.71907425,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20904 Fix UpdateActivityElasticSearchDocumentCommand find activity… by LakyLak · Pull Request #12078 · jiminny/app","depth":5,"bounds":{"left":0.015957447,"top":0.73064643,"width":0.21575798,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20904] Fix UpdateActivityElasticSearchDocumentCommand - Jira","depth":4,"bounds":{"left":0.0028257978,"top":0.7517957,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20904] Fix UpdateActivityElasticSearchDocumentCommand - Jira","depth":5,"bounds":{"left":0.015957447,"top":0.7633679,"width":0.122340426,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.78451717,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.7960894,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.8188348,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to content","depth":6,"bounds":{"left":0.07962101,"top":0.0518755,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"bounds":{"left":0.07962101,"top":0.05347167,"width":0.0029920214,"height":0.21468475},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":10,"bounds":{"left":0.08494016,"top":0.06464485,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":9,"bounds":{"left":0.099567816,"top":0.06464485,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":12,"bounds":{"left":0.112865694,"top":0.06464485,"width":0.018949468,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":14,"bounds":{"left":0.11486037,"top":0.07063048,"width":0.014960106,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":12,"bounds":{"left":0.13680187,"top":0.06464485,"width":0.017785905,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":14,"bounds":{"left":0.13879654,"top":0.07063048,"width":0.008477394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"bounds":{"left":0.81698805,"top":0.06464485,"width":0.06565824,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","depth":12,"bounds":{"left":0.82928854,"top":0.07063048,"width":0.011801862,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":12,"bounds":{"left":0.8424202,"top":0.07222666,"width":0.002493351,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to search","depth":12,"bounds":{"left":0.84640956,"top":0.07063048,"width":0.021276595,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":10,"bounds":{"left":0.88464093,"top":0.06464485,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":9,"bounds":{"left":0.8949468,"top":0.06464485,"width":0.008643617,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":9,"bounds":{"left":0.9115692,"top":0.06464485,"width":0.01662234,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"All issues(g then i)","depth":9,"bounds":{"left":0.93085104,"top":0.06464485,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All pull requests","depth":9,"bounds":{"left":0.94414896,"top":0.06464485,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All repositories","depth":9,"bounds":{"left":0.9574468,"top":0.06464485,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":9,"bounds":{"left":0.97074467,"top":0.06464485,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":9,"bounds":{"left":0.9840425,"top":0.06464485,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":9,"bounds":{"left":0.079288565,"top":0.051077414,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":10,"bounds":{"left":0.079288565,"top":0.05387071,"width":0.0787899,"height":0.023144454},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":12,"bounds":{"left":0.08494016,"top":0.09936153,"width":0.025099734,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":14,"bounds":{"left":0.095744684,"top":0.10574621,"width":0.011469414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (29)","depth":12,"bounds":{"left":0.11269947,"top":0.09936153,"width":0.05501995,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":14,"bounds":{"left":0.12333777,"top":0.10574621,"width":0.02925532,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"bounds":{"left":0.15525267,"top":0.113727055,"width":0.0029920214,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"29","depth":14,"bounds":{"left":0.15824468,"top":0.113727055,"width":0.0056515955,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"bounds":{"left":0.16389628,"top":0.113727055,"width":0.0018284575,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Agents","depth":12,"bounds":{"left":0.17037898,"top":0.09936153,"width":0.029089095,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":14,"bounds":{"left":0.18151596,"top":0.10574621,"width":0.014960106,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":12,"bounds":{"left":0.20212767,"top":0.09936153,"width":0.03025266,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":14,"bounds":{"left":0.21326463,"top":0.10574621,"width":0.016123671,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":12,"bounds":{"left":0.23503989,"top":0.09936153,"width":0.023105053,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":14,"bounds":{"left":0.24601063,"top":0.10574621,"width":0.009142287,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality","depth":12,"bounds":{"left":0.26080453,"top":0.09936153,"width":0.058011968,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":14,"bounds":{"left":0.27244017,"top":0.10574621,"width":0.042719416,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":12,"bounds":{"left":0.32147607,"top":0.09936153,"width":0.03125,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":14,"bounds":{"left":0.33277926,"top":0.10574621,"width":0.016788565,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"bounds":{"left":0.35538563,"top":0.09936153,"width":0.032081116,"height":0.026336791},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"bounds":{"left":0.3665226,"top":0.10574621,"width":0.017785905,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":10,"bounds":{"left":0.09325133,"top":0.14365523,"width":0.0003324468,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":11,"bounds":{"left":0.09325133,"top":0.1452514,"width":0.039228722,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":10,"bounds":{"left":0.09325133,"top":0.1452514,"width":0.2159242,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":10,"bounds":{"left":0.30917552,"top":0.1452514,"width":0.04055851,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":11,"bounds":{"left":0.30917552,"top":0.1452514,"width":0.04055851,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":10,"bounds":{"left":0.34973404,"top":0.1452514,"width":0.08261303,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":10,"bounds":{"left":0.4323471,"top":0.1452514,"width":0.05219415,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":11,"bounds":{"left":0.4323471,"top":0.1452514,"width":0.05219415,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"bounds":{"left":0.48454124,"top":0.1452514,"width":0.0013297872,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":9,"bounds":{"left":0.98636967,"top":0.13886672,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"JY-20903 Update activity stage when opportunity is changed #12077 Edit title","depth":13,"bounds":{"left":0.090259306,"top":0.19193934,"width":0.3309508,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20903 Update activity stage when opportunity is changed","depth":14,"bounds":{"left":0.090259306,"top":0.19273743,"width":0.28108376,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"bounds":{"left":0.37400267,"top":0.19273743,"width":0.006482713,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12077","depth":15,"bounds":{"left":0.3804854,"top":0.19273743,"width":0.028756648,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit title","depth":14,"bounds":{"left":0.4105718,"top":0.19513169,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Preview","depth":13,"bounds":{"left":0.95827794,"top":0.19992019,"width":0.031083776,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Preview","depth":15,"bounds":{"left":0.96359706,"top":0.2047087,"width":0.01512633,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Checks pending","depth":13,"bounds":{"left":0.8715093,"top":0.19832402,"width":0.051861703,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks pending","depth":15,"bounds":{"left":0.88380986,"top":0.20430966,"width":0.03523936,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","depth":13,"bounds":{"left":0.9260306,"top":0.19832402,"width":0.02825798,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Code","depth":15,"bounds":{"left":0.9303524,"top":0.20430966,"width":0.011635638,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"bounds":{"left":0.1008976,"top":0.23623304,"width":0.011968086,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"LakyLak","depth":15,"bounds":{"left":0.11951463,"top":0.2330407,"width":0.01861702,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"LakyLak","depth":16,"bounds":{"left":0.11951463,"top":0.23463687,"width":0.01861702,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 2 commits into","depth":15,"bounds":{"left":0.13946144,"top":0.23463687,"width":0.06632314,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"bounds":{"left":0.20711437,"top":0.23264167,"width":0.018450798,"height":0.017557861},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"bounds":{"left":0.20910904,"top":0.235834,"width":0.014461436,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"bounds":{"left":0.22689494,"top":0.23463687,"width":0.009973404,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20903-update_activity-stage-on-opportunity-change","depth":16,"bounds":{"left":0.23819813,"top":0.23264167,"width":0.12865691,"height":0.017557861},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20903-update_activity-stage-on-opportunity-change","depth":17,"bounds":{"left":0.24019282,"top":0.235834,"width":0.124667555,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"bounds":{"left":0.36818483,"top":0.23024741,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 6 additions & 4 deletions","depth":14,"bounds":{"left":0.96193486,"top":0.28651237,"width":0.019946808,"height":0.11412609},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Conversation (4)","depth":16,"bounds":{"left":0.090259306,"top":0.26855546,"width":0.054853722,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Conversation","depth":17,"bounds":{"left":0.10255984,"top":0.27813247,"width":0.02825798,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"bounds":{"left":0.14079122,"top":0.27813247,"width":0.0029920214,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4","depth":18,"bounds":{"left":0.14378324,"top":0.27813247,"width":0.0029920214,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"bounds":{"left":0.14677526,"top":0.27813247,"width":0.0016622341,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Commits (2)","depth":16,"bounds":{"left":0.14511304,"top":0.26855546,"width":0.045545213,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Commits","depth":17,"bounds":{"left":0.15741356,"top":0.27813247,"width":0.019115692,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"bounds":{"left":0.18633644,"top":0.27813247,"width":0.0029920214,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":18,"bounds":{"left":0.18932846,"top":0.27813247,"width":0.0026595744,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"bounds":{"left":0.19198804,"top":0.27813247,"width":0.0018284575,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Checks (2)","depth":16,"bounds":{"left":0.19065824,"top":0.26855546,"width":0.042386968,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks","depth":17,"bounds":{"left":0.20295878,"top":0.27813247,"width":0.015957447,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"bounds":{"left":0.2287234,"top":0.27813247,"width":0.0029920214,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":18,"bounds":{"left":0.23171543,"top":0.27813247,"width":0.0026595744,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"bounds":{"left":0.234375,"top":0.27813247,"width":0.0018284575,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Files changed (1)","depth":16,"bounds":{"left":0.2330452,"top":0.26855546,"width":0.055684842,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Files changed","depth":17,"bounds":{"left":0.24534574,"top":0.27813247,"width":0.029753989,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"bounds":{"left":0.28440824,"top":0.27813247,"width":0.0029920214,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":18,"bounds":{"left":0.28740028,"top":0.27813247,"width":0.0019946808,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"bounds":{"left":0.28939494,"top":0.27813247,"width":0.0018284575,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull Request Toolbar","depth":14,"bounds":{"left":0.090259306,"top":0.3236233,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull Request Toolbar","depth":15,"bounds":{"left":0.090259306,"top":0.3264166,"width":0.030086435,"height":0.08060654},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse file tree","depth":14,"bounds":{"left":0.090259306,"top":0.31284916,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"All commits","depth":14,"bounds":{"left":0.1022274,"top":0.31284916,"width":0.040392287,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All commits","depth":16,"bounds":{"left":0.11186835,"top":0.3180367,"width":0.02244016,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0 of 1 file viewed","depth":15,"bounds":{"left":0.86602396,"top":0.32521948,"width":0.01512633,"height":0.08060654},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Submit review","depth":14,"bounds":{"left":0.90325797,"top":0.31284916,"width":0.03856383,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Submit","depth":16,"bounds":{"left":0.90625,"top":0.3180367,"width":0.014793883,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"review","depth":16,"bounds":{"left":0.9210439,"top":0.3180367,"width":0.012466756,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Open diff view settings","depth":14,"bounds":{"left":0.9444814,"top":0.31284916,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open overview panel","depth":14,"bounds":{"left":0.96210104,"top":0.31284916,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open comments panel","depth":14,"bounds":{"left":0.97273934,"top":0.31284916,"width":0.01662234,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"(","depth":16,"bounds":{"left":0.98105055,"top":0.3180367,"width":0.0026595744,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"bounds":{"left":0.9837101,"top":0.3180367,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":16,"bounds":{"left":0.9857048,"top":0.3180367,"width":0.0014960107,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Filter files…","depth":16,"bounds":{"left":0.1015625,"top":0.36193135,"width":0.06815159,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Filter options","depth":16,"bounds":{"left":0.17270611,"top":0.36113328,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"File tree","depth":15,"bounds":{"left":0.09059176,"top":0.39944133,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"File tree","depth":16,"bounds":{"left":0.09059176,"top":0.40223464,"width":0.014295213,"height":0.0518755},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Models","depth":19,"bounds":{"left":0.1065492,"top":0.40542698,"width":0.025099734,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Activity.php","depth":21,"bounds":{"left":0.10920878,"top":0.43136472,"width":0.025265958,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Activity.php","depth":22,"bounds":{"left":0.10920878,"top":0.43136472,"width":0.025265958,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse file","depth":14,"bounds":{"left":0.19730718,"top":0.36671987,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"app/Models/Activity.php","depth":15,"bounds":{"left":0.20794548,"top":0.36951315,"width":0.05518617,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"app/Models/Activity.php","depth":16,"bounds":{"left":0.20794548,"top":0.37110934,"width":0.05518617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app/Models/Activity.php","depth":18,"bounds":{"left":0.20794548,"top":0.37310454,"width":0.05518617,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy file name to clipboard","depth":15,"bounds":{"left":0.26579124,"top":0.36671987,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Expand all lines: app/Models/Activity.php","depth":15,"bounds":{"left":0.27509972,"top":0.36671987,"width":0.00930851,"height":0.022346368},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 6 additions & 4 deletions","depth":15,"bounds":{"left":0.9055851,"top":0.3790902,"width":0.019946808,"height":0.11412609},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Not Viewed","depth":14,"bounds":{"left":0.93583775,"top":0.36671987,"width":0.026595745,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Viewed","depth":16,"bounds":{"left":0.94547874,"top":0.3719074,"width":0.013962766,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Comment on this file","depth":14,"bounds":{"left":0.9650931,"top":0.36671987,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"More options","depth":14,"bounds":{"left":0.97706115,"top":0.36671987,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Original file line number","depth":17,"bounds":{"left":0.19464761,"top":0.396249,"width":0.017952127,"height":0.04708699},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line","depth":17,"bounds":{"left":0.21259974,"top":0.4046289,"width":0.018118352,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Diff line number","depth":17,"bounds":{"left":0.23071809,"top":0.396249,"width":0.01761968,"height":0.04708699},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Diff line change","depth":17,"bounds":{"left":0.24833776,"top":0.396249,"width":0.016954787,"height":0.04708699},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"@@ -2119,12 +2119,14 @@ public function updateActivityCrmData(array $records): void","depth":18,"bounds":{"left":0.21991356,"top":0.3982442,"width":0.19913563,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2119","depth":16,"bounds":{"left":0.19847074,"top":0.41739824,"width":0.009640957,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"bounds":{"left":0.25831118,"top":0.41739824,"width":0.0023271276,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"this","depth":18,"bounds":{"left":0.2606383,"top":0.41739824,"width":0.009640957,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"bounds":{"left":0.27027926,"top":0.41739824,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"account_id","depth":18,"bounds":{"left":0.27509972,"top":0.41739824,"width":0.023936171,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":18,"bounds":{"left":0.2990359,"top":0.41739824,"width":0.00731383,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"bounds":{"left":0.30634972,"top":0.41739824,"width":0.0023271276,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"account","depth":18,"bounds":{"left":0.30867687,"top":0.41739824,"width":0.016788565,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"bounds":{"left":0.3254654,"top":0.41739824,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"id","depth":18,"bounds":{"left":0.3302859,"top":0.41739824,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":";","depth":18,"bounds":{"left":0.33510637,"top":0.41739824,"width":0.0023271276,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2119","depth":16,"bounds":{"left":0.59574467,"top":0.41739824,"width":0.009474734,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"bounds":{"left":0.6554189,"top":0.41739824,"width":0.002493351,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"this","depth":18,"bounds":{"left":0.65791225,"top":0.41739824,"width":0.009640957,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"bounds":{"left":0.6675532,"top":0.41739824,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"account_id","depth":18,"bounds":{"left":0.6722075,"top":0.41739824,"width":0.024102394,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":18,"bounds":{"left":0.69630986,"top":0.41739824,"width":0.0071476065,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"bounds":{"left":0.7034575,"top":0.41739824,"width":0.002493351,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"account","depth":18,"bounds":{"left":0.7059508,"top":0.41739824,"width":0.016788565,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"bounds":{"left":0.72273934,"top":0.41739824,"width":0.004654255,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"id","depth":18,"bounds":{"left":0.7273936,"top":0.41739824,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":";","depth":18,"bounds":{"left":0.7322141,"top":0.41739824,"width":0.002493351,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2120","depth":16,"bounds":{"left":0.19847074,"top":0.4365523,"width":0.009640957,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":18,"bounds":{"left":0.21991356,"top":0.4365523,"width":0.03125,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2120","depth":16,"bounds":{"left":0.59574467,"top":0.4365523,"width":0.009474734,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":18,"bounds":{"left":0.6171875,"top":0.4365523,"width":0.031083776,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2121","depth":16,"bounds":{"left":0.19847074,"top":0.4557063,"width":0.009640957,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2121","depth":16,"bounds":{"left":0.59574467,"top":0.4557063,"width":0.009474734,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2122","depth":16,"bounds":{"left":0.19847074,"top":0.47486034,"width":0.009640957,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":18,"bounds":{"left":0.21459441,"top":0.47486034,"width":0.0023271276,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if","depth":18,"bounds":{"left":0.2486702,"top":0.47486034,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"bounds":{"left":0.2534907,"top":0.47486034,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"bounds":{"left":0.25831118,"top":0.47486034,"width":0.0023271276,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"this","depth":18,"bounds":{"left":0.2606383,"top":0.47486034,"width":0.009640957,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"bounds":{"left":0.27027926,"top":0.47486034,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stage_id","depth":18,"bounds":{"left":0.27509972,"top":0.47486034,"width":0.019115692,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"===","depth":18,"bounds":{"left":0.2942154,"top":0.47486034,"width":0.012134309,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"null","depth":18,"bounds":{"left":0.30634972,"top":0.47486034,"width":0.009474734,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"&&","depth":18,"bounds":{"left":0.31582448,"top":0.47486034,"width":0.009640957,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-3981148980175652978
|
1156398504435532096
|
visual_change
|
accessibility
|
NULL
|
Unnamed Group
Platform Sprint 4 Q2 - Platform Team Unnamed Group
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app
JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app
Close tab
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Usage | Windsurf
Usage | Windsurf
Unnamed Group
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app
JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app
Unnamed Group
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Unnamed Group
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app
JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Unnamed Group
JY-20904 Fix UpdateActivityElasticSearchDocumentCommand find activity… by LakyLak · Pull Request #12078 · jiminny/app
JY-20904 Fix UpdateActivityElasticSearchDocumentCommand find activity… by LakyLak · Pull Request #12078 · jiminny/app
[JY-20904] Fix UpdateActivityElasticSearchDocumentCommand - Jira
[JY-20904] Fix UpdateActivityElasticSearchDocumentCommand - Jira
Jiminny
Jiminny
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (29)
Pull requests
(
29
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality
Security and quality
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20903 Update activity stage when opportunity is changed #12077 Edit title
JY-20903 Update activity stage when opportunity is changed
#
12077
Edit title
Preview
Preview
Checks pending
Checks pending
Code
Code
Open
LakyLak
LakyLak
wants to merge 2 commits into
master
master
from
JY-20903-update_activity-stage-on-opportunity-change
JY-20903-update_activity-stage-on-opportunity-change
Copy head branch name to clipboard
Lines changed: 6 additions & 4 deletions
Conversation (4)
Conversation
(
4
)
Commits (2)
Commits
(
2
)
Checks (2)
Checks
(
2
)
Files changed (1)
Files changed
(
1
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
All commits
All commits
0 of 1 file viewed
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel
(
1
)
Filter files…
Filter options
File tree
File tree
app/Models
Activity.php
Activity.php
Collapse file
app/Models/Activity.php
app/Models/Activity.php
app/Models/Activity.php
Copy file name to clipboard
Expand all lines: app/Models/Activity.php
Lines changed: 6 additions & 4 deletions
Not Viewed
Viewed
Comment on this file
More options
Original file line number
Original file line
Diff line number
Diff line change
@@ -2119,12 +2119,14 @@ public function updateActivityCrmData(array $records): void
2119
$
this
->
account_id
=
$
account
->
id
;
2119
$
this
->
account_id
=
$
account
->
id
;
2120
}
2120
}
2121
2121
2122
-
if
(
$
this
->
stage_id
===
null
&&...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43609
|
1589
|
35
|
2026-05-14T13:02:27.277108+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763747277_m1.jpg...
|
Firefox
|
JY-20903 Update activity stage when opportunity is JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12077/changes
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Unnamed Group
Platform Sprint 4 Q2 - Platform Team Unnamed Group
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app
JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app
Close tab
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Usage | Windsurf
Usage | Windsurf
Unnamed Group
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app
JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app
Unnamed Group
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Unnamed Group
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app
JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Unnamed Group
JY-20904 Fix UpdateActivityElasticSearchDocumentCommand find activity… by LakyLak · Pull Request #12078 · jiminny/app
JY-20904 Fix UpdateActivityElasticSearchDocumentCommand find activity… by LakyLak · Pull Request #12078 · jiminny/app
[JY-20904] Fix UpdateActivityElasticSearchDocumentCommand - Jira
[JY-20904] Fix UpdateActivityElasticSearchDocumentCommand - Jira
Jiminny
Jiminny
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (29)
Pull requests
(
29
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality
Security and quality
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20903 Update activity stage when opportunity is changed #12077 Edit title
JY-20903 Update activity stage when opportunity is changed
#
12077
Edit title
Preview
Preview
Checks pending
Checks pending
Code
Code
Open
LakyLak
LakyLak
wants to merge 2 commits into
master
master
from
JY-20903-update_activity-stage-on-opportunity-change
JY-20903-update_activity-stage-on-opportunity-change
Copy head branch name to clipboard
Lines changed: 6 additions & 4 deletions
Conversation (4)
Conversation
(
4
)
Commits (2)
Commits
(
2
)
Checks (2)
Checks
(
2
)
Files changed (1)
Files changed
(
1
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
All commits
All commits
0 of 1 file viewed
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel
(
1
)
Filter files…
Filter options
File tree
File tree
app/Models
Activity.php
Activity.php
Collapse file
app/Models/Activity.php
app/Models/Activity.php
app/Models/Activity.php
Copy file name to clipboard
Expand all lines: app/Models/Activity.php
Lines changed: 6 additions & 4 deletions
Not Viewed
Viewed
Comment on this file
More options
Original file line number
Original file line
Diff line number
Diff line change
@@ -2119,12 +2119,14 @@ public function updateActivityCrmData(array $records): void
2119
$
this
->
account_id
=
$
account
->
id
;
2119
$
this
->
account_id
=
$
account
->
id
;
2120
}
2120
}
2121
2121
2122
-
if
(
$
this
->
stage_id
===
null
&&
$
stage
) {
2123
-
$
this
->
stage_id
=
$
stage
->
id
;
2124
-
}
2125
-
2126
if
(
$
opportunity
&&
$
this
->
opportunity_id
!==
$
opportunity
->
id
) {
2122
if
(
$
opportunity
&&
$
this
->
opportunity_id
!==
$
opportunity
->
id
) {
Add comment
More actions
2127
$
this
->
opportunity_id
=
$
opportunity
->
id
;
2123
$
this
->
opportunity_id
=
$
opportunity
->
id
;
2124
+
// Reset stage_id when opportunity changes to avoid stale stage from previous opportunity match
2125
+
$
this
->
stage_id
=
$
stage
?->id;
2126
+
}
2127
+...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Unnamed Group","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Usage | Windsurf","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Usage | Windsurf","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Unnamed Group","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"[SRD-6848] Sidekick SMS issue - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6848] Sidekick SMS issue - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20891] Sidekick SMS issue - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20891] Sidekick SMS issue - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Unnamed Group","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20903] Recorded call does not appear on the dashboard - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20903] Recorded call does not appear on the dashboard - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Unnamed Group","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Configure SSH access to multiple environment - Engineering - Confluence","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Configure SSH access to multiple environment - Engineering - Confluence","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Useful commands - Engineering - Confluence","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Useful commands - Engineering - Confluence","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Unnamed Group","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"JY-20904 Fix UpdateActivityElasticSearchDocumentCommand find activity… by LakyLak · Pull Request #12078 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20904 Fix UpdateActivityElasticSearchDocumentCommand find activity… by LakyLak · Pull Request #12078 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20904] Fix UpdateActivityElasticSearchDocumentCommand - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20904] Fix UpdateActivityElasticSearchDocumentCommand - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to content","depth":6,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to search","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":9,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":9,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"All issues(g then i)","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All pull requests","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All repositories","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":9,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (29)","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"29","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Agents","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":10,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"JY-20903 Update activity stage when opportunity is changed #12077 Edit title","depth":13,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20903 Update activity stage when opportunity is changed","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12077","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit title","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Preview","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Preview","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Checks pending","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks pending","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Code","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"LakyLak","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"LakyLak","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 2 commits into","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20903-update_activity-stage-on-opportunity-change","depth":16,"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20903-update_activity-stage-on-opportunity-change","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 6 additions & 4 deletions","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Conversation (4)","depth":16,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Conversation","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Commits (2)","depth":16,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Commits","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Checks (2)","depth":16,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Files changed (1)","depth":16,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Files changed","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull Request Toolbar","depth":14,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull Request Toolbar","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse file tree","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"All commits","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All commits","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0 of 1 file viewed","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Submit review","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Submit","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"review","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Open diff view settings","depth":14,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open overview panel","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open comments panel","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"(","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Filter files…","depth":16,"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Filter options","depth":16,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"File tree","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"File tree","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Models","depth":19,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Activity.php","depth":21,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Activity.php","depth":22,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse file","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"app/Models/Activity.php","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"app/Models/Activity.php","depth":16,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app/Models/Activity.php","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy file name to clipboard","depth":15,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Expand all lines: app/Models/Activity.php","depth":15,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 6 additions & 4 deletions","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Not Viewed","depth":14,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Viewed","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Comment on this file","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"More options","depth":14,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Original file line number","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Diff line number","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Diff line change","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"@@ -2119,12 +2119,14 @@ public function updateActivityCrmData(array $records): void","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2119","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"this","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"account_id","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"account","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"id","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":";","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2119","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"this","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"account_id","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"account","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"id","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":";","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2120","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2120","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2121","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2121","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2122","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"this","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stage_id","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"===","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"null","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"&&","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stage","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") {","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2123","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"this","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stage_id","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stage","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"id","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":";","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2124","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2125","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2126","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"opportunity","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"&&","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"this","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"opportunity_id","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"!==","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"opportunity","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"id","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") {","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2122","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"opportunity","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"&&","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"this","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"opportunity_id","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"!==","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"opportunity","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"id","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") {","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add comment","depth":17,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More actions","depth":17,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2127","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"this","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"opportunity_id","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"opportunity","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"id","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":";","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2123","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"this","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"opportunity_id","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"opportunity","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"id","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":";","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2124","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// Reset stage_id when opportunity changes to avoid stale stage from previous opportunity match","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2125","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"this","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stage_id","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stage","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"?->id;","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2126","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2127","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
7837553398281687675
|
1229010810679615840
|
visual_change
|
accessibility
|
NULL
|
Unnamed Group
Platform Sprint 4 Q2 - Platform Team Unnamed Group
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app
JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app
Close tab
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Usage | Windsurf
Usage | Windsurf
Unnamed Group
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app
JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app
Unnamed Group
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Unnamed Group
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app
JY-20903 Update activity stage when opportunity is changed by LakyLak · Pull Request #12077 · jiminny/app
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Unnamed Group
JY-20904 Fix UpdateActivityElasticSearchDocumentCommand find activity… by LakyLak · Pull Request #12078 · jiminny/app
JY-20904 Fix UpdateActivityElasticSearchDocumentCommand find activity… by LakyLak · Pull Request #12078 · jiminny/app
[JY-20904] Fix UpdateActivityElasticSearchDocumentCommand - Jira
[JY-20904] Fix UpdateActivityElasticSearchDocumentCommand - Jira
Jiminny
Jiminny
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (29)
Pull requests
(
29
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality
Security and quality
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20903 Update activity stage when opportunity is changed #12077 Edit title
JY-20903 Update activity stage when opportunity is changed
#
12077
Edit title
Preview
Preview
Checks pending
Checks pending
Code
Code
Open
LakyLak
LakyLak
wants to merge 2 commits into
master
master
from
JY-20903-update_activity-stage-on-opportunity-change
JY-20903-update_activity-stage-on-opportunity-change
Copy head branch name to clipboard
Lines changed: 6 additions & 4 deletions
Conversation (4)
Conversation
(
4
)
Commits (2)
Commits
(
2
)
Checks (2)
Checks
(
2
)
Files changed (1)
Files changed
(
1
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
All commits
All commits
0 of 1 file viewed
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel
(
1
)
Filter files…
Filter options
File tree
File tree
app/Models
Activity.php
Activity.php
Collapse file
app/Models/Activity.php
app/Models/Activity.php
app/Models/Activity.php
Copy file name to clipboard
Expand all lines: app/Models/Activity.php
Lines changed: 6 additions & 4 deletions
Not Viewed
Viewed
Comment on this file
More options
Original file line number
Original file line
Diff line number
Diff line change
@@ -2119,12 +2119,14 @@ public function updateActivityCrmData(array $records): void
2119
$
this
->
account_id
=
$
account
->
id
;
2119
$
this
->
account_id
=
$
account
->
id
;
2120
}
2120
}
2121
2121
2122
-
if
(
$
this
->
stage_id
===
null
&&
$
stage
) {
2123
-
$
this
->
stage_id
=
$
stage
->
id
;
2124
-
}
2125
-
2126
if
(
$
opportunity
&&
$
this
->
opportunity_id
!==
$
opportunity
->
id
) {
2122
if
(
$
opportunity
&&
$
this
->
opportunity_id
!==
$
opportunity
->
id
) {
Add comment
More actions
2127
$
this
->
opportunity_id
=
$
opportunity
->
id
;
2123
$
this
->
opportunity_id
=
$
opportunity
->
id
;
2124
+
// Reset stage_id when opportunity changes to avoid stale stage from previous opportunity match
2125
+
$
this
->
stage_id
=
$
stage
?->id;
2126
+
}
2127
+...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43611
|
1589
|
36
|
2026-05-14T13:02:37.947137+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763757947_m1.jpg...
|
Slack
|
Aneliya Angelova (DM) - Jiminny Inc - 3 new items Aneliya Angelova (DM) - Jiminny Inc - 3 new items - Slack...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelp→Describe what SlackFileEditViewGoHistoryWindowHelp→Describe what you are looking forAneliya AngelovaMessagesAdd canvas@ Files+lhl14100% <8• Thu 14 May 16:02:37HomeDMsActivityFilesLaterMoreJiminny ...scnicrat# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Direct messagesP. Aneliya Angelova€. Vasil Vasilev E. Galya Dimitrova&. Stefka Stoyanova: Todor StamatovMario GeorgievNikolay IvanovLo James Graham2 Stoyan TanevSteliyan GeorgievPetko KashinskiLukas Kovalik y...AppsToastJira Cloud6 0Monday, May 11th ~Today ~Aneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?при останалите CRMi трябва ръчно да се въведатLukas Kovalik 2:47 PMздрастиами не знам по принцип се вика при всичкитрябва да се за всички, някъде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725Jira CloudX Bug IV-20725 in Jira Cloud[HubSpot] Optimise CRM rematching on delete hubspot ac...StatusReady for QAPriority= MediumAssigneeAA Aneliya AngelovaAs of today at 4:00 PMOpen in Jirait SummariseLukas Kovalik 4:02 PMдазвьни направоMessage Aneliya AngelovaNew...
|
NULL
|
751616011596038026
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelp→Describe what SlackFileEditViewGoHistoryWindowHelp→Describe what you are looking forAneliya AngelovaMessagesAdd canvas@ Files+lhl14100% <8• Thu 14 May 16:02:37HomeDMsActivityFilesLaterMoreJiminny ...scnicrat# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Direct messagesP. Aneliya Angelova€. Vasil Vasilev E. Galya Dimitrova&. Stefka Stoyanova: Todor StamatovMario GeorgievNikolay IvanovLo James Graham2 Stoyan TanevSteliyan GeorgievPetko KashinskiLukas Kovalik y...AppsToastJira Cloud6 0Monday, May 11th ~Today ~Aneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?при останалите CRMi трябва ръчно да се въведатLukas Kovalik 2:47 PMздрастиами не знам по принцип се вика при всичкитрябва да се за всички, някъде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725Jira CloudX Bug IV-20725 in Jira Cloud[HubSpot] Optimise CRM rematching on delete hubspot ac...StatusReady for QAPriority= MediumAssigneeAA Aneliya AngelovaAs of today at 4:00 PMOpen in Jirait SummariseLukas Kovalik 4:02 PMдазвьни направоMessage Aneliya AngelovaNew...
|
43609
|
NULL
|
NULL
|
NULL
|
|
43612
|
1590
|
34
|
2026-05-14T13:02:37.950744+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763757950_m2.jpg...
|
Slack
|
Aneliya Angelova (DM) - Jiminny Inc - 3 new items Aneliya Angelova (DM) - Jiminny Inc - 3 new items - Slack...
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
rireroxVIewMistorbookmarksJY-20903 Update activity rireroxVIewMistorbookmarksJY-20903 Update activity sta XSRD-6849) Recorded call doesUsage | Windsurf4(SRD-6848] Sidekick SMS issue(JY-20891] Sidekick SMS issue -JY-20891 add support for seconcR (SRD-6849) Recorded call does :[JY-20903] Recorded call does r8 Jiminnv‹> Code?? Pull requests6. Agents• Actions0 Wiki• Security and qualityInsights ộ Settings(U On Adri 24 well start usina GitHub Copilot nteraction data for Al mode Itranina unless vou opt out. Review this update and manage vour preterences in vour gifi mo account setinasJY-20903 Update activity stage when opportunity is changed #12077 •I7 Open LakyLak wants to merge 2 commits into master from JY-20903-update_activity-stage-on-opportunity-change ®@ Conversation 4Commits2El Checks 2* Files changed 14 All commitsQ Filter files...• app/ModelsD Activity.phpapp/Models/Activity-php +C -2119,12 +2119,14 @@ public function updateActivityCrmData(array $records): voidSth1s->account 1d = Saccount—>1d* if (Sthis-›stage_id === null && $stage) (Sthis->stage_1d = Sstage->1d;if (Sopportunity && Sthis->opportunity_id != Sopportunity->id) €Sthis->opportunity_id = Sopportunity->id;1 (SRD-6853] Moxso - Potential de@ JY-20903 Update activity stage& Configure SSH access to multiple ‹* Useful commands - Engineering -JY-20904 Fix UpdateActivityElas(JY-20904) Fix UpdateActivityEla? Jiminnv+ New Tab212821292130if (sopportunity && sthis-›value !== sopportunity-›value) ([CREDIT_CARD] +]2123212421252226220 :[CREDIT_CARD]|• Type (/] to search100% C4 &• Thu 14 May 16:02:37+000• Checks pending• 0/1 viewedCode-( Preview ) •+6 -4 88820SubnitIeven ++6 -4 manz0 [ Viewed0 ...s setns-saccount, ld = soccount -218;if (Sopportunity && Sthis-›opportunity_id !== Sopportunity→>id) {sthis-sopportunity_id = Sopportunity->id;// Reset stage_id when opportunity changes to avoid stale stage from previous opportunity matchsthis->stage_id = $stage?->id;if (Sthis->stage id === null && Sstaae) <Isthis->stage_id = $stage->id;if (Sooportunity &{ Sthis->value !== Soooortunitv->value)<I...
|
NULL
|
-6174971048112902625
|
NULL
|
click
|
ocr
|
NULL
|
rireroxVIewMistorbookmarksJY-20903 Update activity rireroxVIewMistorbookmarksJY-20903 Update activity sta XSRD-6849) Recorded call doesUsage | Windsurf4(SRD-6848] Sidekick SMS issue(JY-20891] Sidekick SMS issue -JY-20891 add support for seconcR (SRD-6849) Recorded call does :[JY-20903] Recorded call does r8 Jiminnv‹> Code?? Pull requests6. Agents• Actions0 Wiki• Security and qualityInsights ộ Settings(U On Adri 24 well start usina GitHub Copilot nteraction data for Al mode Itranina unless vou opt out. Review this update and manage vour preterences in vour gifi mo account setinasJY-20903 Update activity stage when opportunity is changed #12077 •I7 Open LakyLak wants to merge 2 commits into master from JY-20903-update_activity-stage-on-opportunity-change ®@ Conversation 4Commits2El Checks 2* Files changed 14 All commitsQ Filter files...• app/ModelsD Activity.phpapp/Models/Activity-php +C -2119,12 +2119,14 @@ public function updateActivityCrmData(array $records): voidSth1s->account 1d = Saccount—>1d* if (Sthis-›stage_id === null && $stage) (Sthis->stage_1d = Sstage->1d;if (Sopportunity && Sthis->opportunity_id != Sopportunity->id) €Sthis->opportunity_id = Sopportunity->id;1 (SRD-6853] Moxso - Potential de@ JY-20903 Update activity stage& Configure SSH access to multiple ‹* Useful commands - Engineering -JY-20904 Fix UpdateActivityElas(JY-20904) Fix UpdateActivityEla? Jiminnv+ New Tab212821292130if (sopportunity && sthis-›value !== sopportunity-›value) ([CREDIT_CARD] +]2123212421252226220 :[CREDIT_CARD]|• Type (/] to search100% C4 &• Thu 14 May 16:02:37+000• Checks pending• 0/1 viewedCode-( Preview ) •+6 -4 88820SubnitIeven ++6 -4 manz0 [ Viewed0 ...s setns-saccount, ld = soccount -218;if (Sopportunity && Sthis-›opportunity_id !== Sopportunity→>id) {sthis-sopportunity_id = Sopportunity->id;// Reset stage_id when opportunity changes to avoid stale stage from previous opportunity matchsthis->stage_id = $stage?->id;if (Sthis->stage id === null && Sstaae) <Isthis->stage_id = $stage->id;if (Sooportunity &{ Sthis->value !== Soooortunitv->value)<I...
|
43610
|
NULL
|
NULL
|
NULL
|
|
43613
|
1589
|
37
|
2026-05-14T13:02:39.453790+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763759453_m1.jpg...
|
Slack
|
Lukas Kovalik (DM) - Jiminny Inc - 3 new items - S Lukas Kovalik (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Sep 26th, 2025 at 6:14:34 PM
6:14 PM
https://meet.google.com/txd-hxqc-pus
https://meet.google.com/txd-hxqc-pus
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Oct 6th, 2025 at 9:43:38 AM
9:43 AM
https://meet.google.com/iqc-eyhm-xgc
https://meet.google.com/iqc-eyhm-xgc
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Feb 14th at 5:48:06 PM
5:48 PM
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Feb 14th at 5:48:27 PM
5:48
curl -X POST
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
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
Lukas Kovalik
Mar 11th at 8:38:18 PM
8:38 PM
curl -X POST
http://[IP_ADDRESS]:8100/download
http://[IP_ADDRESS]:8100/download
\
-H “Content-Type: application/json” \
-d ‘{“url”: “
https://www.youtube.com/watch?v=VIDEO_ID
https://www.youtube.com/watch?v=VIDEO_ID
”, “format”: “audio”}’
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
Lukas Kovalik
Mar 12th at 2:51:33 PM
2:51 PM
fozjir-jeJcoc-sekhi0
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Mar 12th at 6:43:49 PM
6:43 PM
Create ticket autolog delay & Vasko about opportunity profile sync
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Remove from Later
More actions
Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775
Направих и 4 тикета за който не остана време
https://jiminny.atlassian.net/browse/JY-20772
https://jiminny.atlassian.net/browse/JY-20772
,
https://jiminny.atlassian.net/browse/JY-20773
https://jiminny.atlassian.net/browse/JY-20773
(добавих ПР който би трябвало да го фиксне),
https://jiminny.atlassian.net/browse/JY-20776
https://jiminny.atlassian.net/browse/JY-20776
и
https://jiminny.atlassian.net/browse/JY-20775
https://jiminny.atlassian.net/browse/JY-20775
Fix inconsistent favicon on PDF report tabs
Bug JY-20772 in Jira Cloud
Preview in Slack
Remove link preview
User Pilot not receiving events on report generated
Bug JY-20773 in Jira Cloud
Preview in Slack
Remove link preview
Automated report - sentry
Bug JY-20776 in Jira Cloud
Preview in Slack
Remove link preview
UserTransformer hasGeneratedAiReports refactor
Bug JY-20775 in Jira Cloud
Preview in Slack
Remove link preview
Scroll left
Scroll right
Shift + Return to add a new line
Shift + Return
to add a new line
20 results
Channel...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.011805556,"top":0.08111111,"width":0.025,"height":0.04},"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.00625,"top":0.14,"width":0.036111113,"height":0.075555556},"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.013888889,"top":0.19222222,"width":0.020833334,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.00625,"top":0.21555555,"width":0.036111113,"height":0.075555556},"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.015972223,"top":0.26777777,"width":0.016666668,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.00625,"top":0.2911111,"width":0.036111113,"height":0.075555556},"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.011111111,"top":0.34333333,"width":0.027083334,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.011111111,"top":0.34333333,"width":0.0055555557,"height":0.015555556}},{"char_start":1,"char_count":7,"bounds":{"left":0.015972223,"top":0.34333333,"width":0.022222223,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.00625,"top":0.36666667,"width":0.036111113,"height":0.075555556},"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.016666668,"top":0.4188889,"width":0.015972223,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.016666668,"top":0.4188889,"width":0.004166667,"height":0.015555556}},{"char_start":1,"char_count":4,"bounds":{"left":0.020833334,"top":0.4188889,"width":0.011805556,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.00625,"top":0.4422222,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.49444443,"width":0.018055556,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.00625,"top":0.5177778,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.57,"width":0.01875,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.039583333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.036805555,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.06111111,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.18472221,"top":0.12777779,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.050694443,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.09166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.093055554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.046527777,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.025694445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.022222223,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.072222225,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.057638887,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.054166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.034027778,"height":0.007777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.088194445,"top":0.14666666,"width":0.048611112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.072916664,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":15,"bounds":{"left":0.094444446,"top":0.17777778,"width":0.06666667,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.088194445,"top":0.20888889,"width":0.08055556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.088194445,"top":0.24,"width":0.035416666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.088194445,"top":0.2711111,"width":0.036805555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.05138889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":11,"bounds":{"left":0.093055554,"top":0.30222222,"width":0.045833334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.088194445,"top":0.33333334,"width":0.036111113,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.088194445,"top":0.36444443,"width":0.05138889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.094444446,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.004166667,"height":0.02}},{"char_start":1,"char_count":20,"bounds":{"left":0.09236111,"top":0.39555556,"width":0.09861111,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.088194445,"top":0.46888888,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.088194445,"top":0.5,"width":0.055555556,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.5,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.094444446,"top":0.5,"width":0.048611112,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.088194445,"top":0.5311111,"width":0.07361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.088194445,"top":0.56222224,"width":0.079166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"bounds":{"left":0.088194445,"top":0.5933333,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.6244444,"width":0.07152778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"bounds":{"left":0.088194445,"top":0.65555555,"width":0.06736111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.088194445,"top":0.68666667,"width":0.06666667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.088194445,"top":0.7177778,"width":0.060416665,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.7488889,"width":0.07986111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"bounds":{"left":0.088194445,"top":0.78,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.088194445,"top":0.8111111,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.15555556,"top":0.8111111,"width":0.016666668,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.088194445,"top":0.8844444,"width":0.025694445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.088194445,"top":0.91555554,"width":0.045833334,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.21319444,"top":0.12777779,"width":0.06458333,"height":0.04222222},"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.2326389,"top":0.14,"width":0.039583333,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.27986112,"top":0.12777779,"width":0.07152778,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"bounds":{"left":0.29930556,"top":0.14,"width":0.046527777,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.35347223,"top":0.12777779,"width":0.04375,"height":0.04222222},"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.37291667,"top":0.14,"width":0.01875,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.37291667,"top":0.14,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":4,"bounds":{"left":0.3784722,"top":0.14,"width":0.013194445,"height":0.017777778}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.4,"top":0.12777779,"width":0.022222223,"height":0.04222222},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":23,"bounds":{"left":0.5402778,"top":0.16111112,"width":0.11875,"height":0.0011111111},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"bounds":{"left":0.31111112,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Sep 26th, 2025 at 6:14:34 PM","depth":24,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:14 PM","depth":25,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://meet.google.com/txd-hxqc-pus","depth":25,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.17569445,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://meet.google.com/txd-hxqc-pus","depth":26,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.17569445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove preview","depth":26,"bounds":{"left":0.2326389,"top":0.16111112,"width":0.013888889,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"meet.google.com","depth":26,"bounds":{"left":0.27430555,"top":0.16111112,"width":0.08055556,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Meet","depth":26,"bounds":{"left":0.2576389,"top":0.16111112,"width":0.025,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Meet","depth":27,"bounds":{"left":0.2576389,"top":0.16111112,"width":0.025,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.","depth":26,"bounds":{"left":0.2576389,"top":0.16111112,"width":0.37361112,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":23,"bounds":{"left":0.54791665,"top":0.17666666,"width":0.103472225,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"bounds":{"left":0.31111112,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Oct 6th, 2025 at 9:43:38 AM","depth":24,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9:43 AM","depth":25,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://meet.google.com/iqc-eyhm-xgc","depth":25,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.17708333,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://meet.google.com/iqc-eyhm-xgc","depth":26,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.17708333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove preview","depth":26,"bounds":{"left":0.2326389,"top":0.16111112,"width":0.013888889,"height":0.033333335},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"meet.google.com","depth":26,"bounds":{"left":0.27430555,"top":0.16333333,"width":0.08055556,"height":0.02111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Meet","depth":26,"bounds":{"left":0.2576389,"top":0.18888889,"width":0.025,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Meet","depth":27,"bounds":{"left":0.2576389,"top":0.18888889,"width":0.025,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.","depth":26,"bounds":{"left":0.2576389,"top":0.21333334,"width":0.37361112,"height":0.044444446},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.2576389,"top":0.21333334,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":123,"bounds":{"left":0.2576389,"top":0.21333334,"width":0.37361112,"height":0.044444446}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":23,"bounds":{"left":0.53680557,"top":0.28444445,"width":0.125,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":24,"bounds":{"left":0.24652778,"top":0.32777777,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"bounds":{"left":0.31111112,"top":0.33,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Feb 14th at 5:48:06 PM","depth":24,"bounds":{"left":0.31666666,"top":0.33333334,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:48 PM","depth":25,"bounds":{"left":0.31666666,"top":0.33333334,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":25,"bounds":{"left":0.24652778,"top":0.35444444,"width":0.41319445,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":26,"bounds":{"left":0.24652778,"top":0.35444444,"width":0.41319445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Feb 14th at 5:48:27 PM","depth":25,"bounds":{"left":0.22430556,"top":0.3911111,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:48","depth":26,"bounds":{"left":0.22430556,"top":0.3911111,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curl -X POST","depth":25,"bounds":{"left":0.24652778,"top":0.38777778,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":25,"bounds":{"left":0.30833334,"top":0.38777778,"width":0.4125,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":26,"bounds":{"left":0.30833334,"top":0.38777778,"width":0.4125,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":23,"bounds":{"left":0.5361111,"top":0.43,"width":0.12638889,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":24,"bounds":{"left":0.24652778,"top":0.47333333,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"bounds":{"left":0.31111112,"top":0.47555557,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 11th at 8:38:18 PM","depth":24,"bounds":{"left":0.31666666,"top":0.4788889,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"8:38 PM","depth":25,"bounds":{"left":0.31666666,"top":0.4788889,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curl -X POST","depth":25,"bounds":{"left":0.24652778,"top":0.5,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"http://192.168.0.242:8100/download","depth":25,"bounds":{"left":0.30833334,"top":0.5,"width":0.17222223,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"http://192.168.0.242:8100/download","depth":26,"bounds":{"left":0.30833334,"top":0.5,"width":0.17222223,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"\\","depth":25,"bounds":{"left":0.48055556,"top":0.5,"width":0.007638889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"-H “Content-Type: application/json” \\","depth":25,"bounds":{"left":0.24652778,"top":0.52444446,"width":0.17569445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"-d ‘{“url”: “","depth":25,"bounds":{"left":0.24652778,"top":0.54888886,"width":0.052083332,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.24652778,"top":0.54888886,"width":0.0027777778,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.24930556,"top":0.54888886,"width":0.043055557,"height":0.02}}],"role_description":"text"},{"role":"AXLink","text":"https://www.youtube.com/watch?v=VIDEO_ID","depth":25,"bounds":{"left":0.2986111,"top":0.54888886,"width":0.21527778,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://www.youtube.com/watch?v=VIDEO_ID","depth":26,"bounds":{"left":0.2986111,"top":0.54888886,"width":0.21527778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"”, “format”: “audio”}’","depth":25,"bounds":{"left":0.51319444,"top":0.54888886,"width":0.08958333,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.51319444,"top":0.54888886,"width":0.0034722222,"height":0.02}},{"char_start":1,"char_count":21,"bounds":{"left":0.5159722,"top":0.54888886,"width":0.08680555,"height":0.02}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":23,"bounds":{"left":0.54097223,"top":0.5911111,"width":0.11666667,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":24,"bounds":{"left":0.24652778,"top":0.6344444,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"bounds":{"left":0.31111112,"top":0.63666666,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 12th at 2:51:33 PM","depth":24,"bounds":{"left":0.31666666,"top":0.64,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:51 PM","depth":25,"bounds":{"left":0.31666666,"top":0.64,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"fozjir-jeJcoc-sekhi0","depth":25,"bounds":{"left":0.24652778,"top":0.6611111,"width":0.088194445,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.24652778,"top":0.6611111,"width":0.0034722222,"height":0.02}},{"char_start":1,"char_count":19,"bounds":{"left":0.25,"top":0.6611111,"width":0.08472222,"height":0.02}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":24,"bounds":{"left":0.24652778,"top":0.69222224,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":24,"bounds":{"left":0.31111112,"top":0.6944444,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 12th at 6:43:49 PM","depth":24,"bounds":{"left":0.31666666,"top":0.69777775,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:43 PM","depth":25,"bounds":{"left":0.31666666,"top":0.69777775,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Create ticket autolog delay & Vasko about opportunity profile sync","depth":25,"bounds":{"left":0.24652778,"top":0.7188889,"width":0.30277777,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":26,"on_screen":false,"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":26,"on_screen":false,"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":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":26,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Remove from Later","depth":26,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":26,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775","depth":23,"bounds":{"left":0.21666667,"top":0.7644445,"width":0.7652778,"height":0.06666667},"on_screen":true,"value":"Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Направих и 4 тикета за който не остана време","depth":25,"bounds":{"left":0.225,"top":0.77555555,"width":0.22569445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20772","depth":25,"bounds":{"left":0.45069444,"top":0.77555555,"width":0.21111111,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20772","depth":26,"bounds":{"left":0.45069444,"top":0.77555555,"width":0.21111111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":25,"bounds":{"left":0.66180557,"top":0.77555555,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20773","depth":25,"bounds":{"left":0.6666667,"top":0.77555555,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20773","depth":26,"bounds":{"left":0.6666667,"top":0.77555555,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"(добавих ПР който би трябвало да го фиксне),","depth":25,"bounds":{"left":0.225,"top":0.77555555,"width":0.7486111,"height":0.044444446},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20776","depth":25,"bounds":{"left":0.35694444,"top":0.8,"width":0.21111111,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20776","depth":26,"bounds":{"left":0.35694444,"top":0.8,"width":0.21111111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и","depth":25,"bounds":{"left":0.56805557,"top":0.8,"width":0.011805556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20775","depth":25,"bounds":{"left":0.57916665,"top":0.8,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20775","depth":26,"bounds":{"left":0.57916665,"top":0.8,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Fix inconsistent favicon on PDF report tabs","depth":26,"bounds":{"left":0.26458332,"top":0.85888886,"width":0.11180556,"height":0.04},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.26458332,"top":0.85888886,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":42,"bounds":{"left":0.26458332,"top":0.85888886,"width":0.11180556,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20772 in Jira Cloud","depth":27,"bounds":{"left":0.26458332,"top":0.8811111,"width":0.108333334,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"bounds":{"left":0.26458332,"top":0.8811111,"width":0.06527778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"bounds":{"left":0.38194445,"top":0.8288889,"width":0.013888889,"height":0.022222223},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"User Pilot not receiving events on report generated","depth":26,"bounds":{"left":0.43958333,"top":0.85888886,"width":0.114583336,"height":0.054444443},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.43958333,"top":0.85888886,"width":0.007638889,"height":0.02}},{"char_start":1,"char_count":50,"bounds":{"left":0.43958333,"top":0.85888886,"width":0.110416666,"height":0.04}}],"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20773 in Jira Cloud","depth":27,"bounds":{"left":0.43958333,"top":0.8811111,"width":0.108333334,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"bounds":{"left":0.43958333,"top":0.8811111,"width":0.06527778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"bounds":{"left":0.55694443,"top":0.8288889,"width":0.013888889,"height":0.022222223},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Automated report - sentry","depth":26,"bounds":{"left":0.6145833,"top":0.85888886,"width":0.11111111,"height":0.04},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.6145833,"top":0.85888886,"width":0.0069444445,"height":0.02}},{"char_start":1,"char_count":24,"bounds":{"left":0.6145833,"top":0.85888886,"width":0.1125,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20776 in Jira Cloud","depth":27,"bounds":{"left":0.6145833,"top":0.8811111,"width":0.108333334,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"bounds":{"left":0.6145833,"top":0.8811111,"width":0.06527778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"bounds":{"left":0.73194444,"top":0.8288889,"width":0.013888889,"height":0.022222223},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"UserTransformer hasGeneratedAiReports refactor","depth":26,"bounds":{"left":0.7895833,"top":0.85888886,"width":0.11180556,"height":0.054444443},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.7895833,"top":0.85888886,"width":0.007638889,"height":0.02}},{"char_start":1,"char_count":45,"bounds":{"left":0.7895833,"top":0.85888886,"width":0.11388889,"height":0.04}}],"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20775 in Jira Cloud","depth":27,"bounds":{"left":0.7895833,"top":0.8811111,"width":0.108333334,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"bounds":{"left":0.7895833,"top":0.8811111,"width":0.06527778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"bounds":{"left":0.90694445,"top":0.8288889,"width":0.013888889,"height":0.022222223},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Scroll left","depth":22,"bounds":{"left":0.21041666,"top":0.8577778,"width":0.02013889,"height":0.032222223},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Scroll right","depth":22,"bounds":{"left":0.9701389,"top":0.8577778,"width":0.02013889,"height":0.032222223},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Shift + Return to add a new line","depth":20,"bounds":{"left":0.87569445,"top":0.9722222,"width":0.10138889,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Shift + Return","depth":21,"bounds":{"left":0.87569445,"top":0.97444445,"width":0.045138888,"height":0.013333334},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"to add a new line","depth":21,"bounds":{"left":0.92083335,"top":0.97444445,"width":0.05625,"height":0.013333334},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"20 results","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Channel","depth":11,"on_screen":false,"role_description":"text"}]...
|
7810669074852850187
|
-8995423948748978082
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Sep 26th, 2025 at 6:14:34 PM
6:14 PM
https://meet.google.com/txd-hxqc-pus
https://meet.google.com/txd-hxqc-pus
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Oct 6th, 2025 at 9:43:38 AM
9:43 AM
https://meet.google.com/iqc-eyhm-xgc
https://meet.google.com/iqc-eyhm-xgc
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Feb 14th at 5:48:06 PM
5:48 PM
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Feb 14th at 5:48:27 PM
5:48
curl -X POST
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
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
Lukas Kovalik
Mar 11th at 8:38:18 PM
8:38 PM
curl -X POST
http://[IP_ADDRESS]:8100/download
http://[IP_ADDRESS]:8100/download
\
-H “Content-Type: application/json” \
-d ‘{“url”: “
https://www.youtube.com/watch?v=VIDEO_ID
https://www.youtube.com/watch?v=VIDEO_ID
”, “format”: “audio”}’
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
Lukas Kovalik
Mar 12th at 2:51:33 PM
2:51 PM
fozjir-jeJcoc-sekhi0
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Mar 12th at 6:43:49 PM
6:43 PM
Create ticket autolog delay & Vasko about opportunity profile sync
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Remove from Later
More actions
Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775
Направих и 4 тикета за който не остана време
https://jiminny.atlassian.net/browse/JY-20772
https://jiminny.atlassian.net/browse/JY-20772
,
https://jiminny.atlassian.net/browse/JY-20773
https://jiminny.atlassian.net/browse/JY-20773
(добавих ПР който би трябвало да го фиксне),
https://jiminny.atlassian.net/browse/JY-20776
https://jiminny.atlassian.net/browse/JY-20776
и
https://jiminny.atlassian.net/browse/JY-20775
https://jiminny.atlassian.net/browse/JY-20775
Fix inconsistent favicon on PDF report tabs
Bug JY-20772 in Jira Cloud
Preview in Slack
Remove link preview
User Pilot not receiving events on report generated
Bug JY-20773 in Jira Cloud
Preview in Slack
Remove link preview
Automated report - sentry
Bug JY-20776 in Jira Cloud
Preview in Slack
Remove link preview
UserTransformer hasGeneratedAiReports refactor
Bug JY-20775 in Jira Cloud
Preview in Slack
Remove link preview
Scroll left
Scroll right
Shift + Return to add a new line
Shift + Return
to add a new line
20 results
Channel
HomeDMsActivityFilesLater..•MoreSlackFileEditViewGoHistoryEDJiminny ...scnicrat# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...• Direct messagesP. Aneliya Angelova€. Vasil Vasilev E®. Galya Dimitrova&. Stefka Stoyanova: Todor StamatovMario GeorgievNikolay IvanovLo James Graham2. Stoyan TanevSteliyan GeorgievPetko KashinskiLukas Kovalik youAppsToastJira CloudWindowHelpQDescribe what you are looking forLukas Kovalik• Messagest Add canvas© Files+meet.google.comMeetOctober 6th, 2025 ~Real-time meetings by Google. Using your browser, share your video, desktop, andpresentations with teammates and customers.Saturday, February 14th ~ladl19100% C8• Thu 14 May 16:02:39Lukas Kovalik 5:48 PMhttps://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notificationcurl -X POST https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20NotificationWednesday, March 11th ~Lukas Kovalik 8:38 PMcurl -X POST http://[IP_ADDRESS]:8100/download \-H "Content-Type: application/json" \-d ("url": "https://www.youtube.com/watch?v=VIDEO_ID", "format": "audio"}'Thursday, March 12th ~Lukas Kovalik 2:51 PMfozjir-jeJcoc-sekhioLukas Kovalik 6:43 PMCreate ticket autolog delay & Vasko about opportunity profile syncНаправих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР койтоби трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775|Fix inconsistent favico...Bug JY-20772 in Jira CloudUser Pilot not receivin...XE BuS Y-20773 in Jia CoudAutomated report - se...2E Bug JY-20776 in Jira Cloudy UserTransformer hasG...XE Bugry-20575 n ira Coc.+AaShift + Return to add a new line...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43614
|
1590
|
35
|
2026-05-14T13:02:39.936919+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763759936_m2.jpg...
|
Slack
|
Lukas Kovalik (DM) - Jiminny Inc - 3 new items - S Lukas Kovalik (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Sep 26th, 2025 at 6:14:34 PM
6:14 PM
https://meet.google.com/txd-hxqc-pus
https://meet.google.com/txd-hxqc-pus
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Oct 6th, 2025 at 9:43:38 AM
9:43 AM
https://meet.google.com/iqc-eyhm-xgc
https://meet.google.com/iqc-eyhm-xgc
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Feb 14th at 5:48:06 PM
5:48 PM
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Feb 14th at 5:48:27 PM
5:48
curl -X POST
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
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
Lukas Kovalik
Mar 11th at 8:38:18 PM
8:38 PM
curl -X POST
http://[IP_ADDRESS]:8100/download
http://[IP_ADDRESS]:8100/download
\
-H “Content-Type: application/json” \
-d ‘{“url”: “
https://www.youtube.com/watch?v=VIDEO_ID
https://www.youtube.com/watch?v=VIDEO_ID
”, “format”: “audio”}’
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
Lukas Kovalik
Mar 12th at 2:51:33 PM
2:51 PM
fozjir-jeJcoc-sekhi0
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Mar 12th at 6:43:49 PM
6:43 PM
Create ticket autolog delay & Vasko about opportunity profile sync
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Remove from Later
More actions
Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775
Направих и 4 тикета за който не остана време
https://jiminny.atlassian.net/browse/JY-20772
https://jiminny.atlassian.net/browse/JY-20772
,
https://jiminny.atlassian.net/browse/JY-20773
https://jiminny.atlassian.net/browse/JY-20773
(добавих ПР който би трябвало да го фиксне),
https://jiminny.atlassian.net/browse/JY-20776
https://jiminny.atlassian.net/browse/JY-20776
и
https://jiminny.atlassian.net/browse/JY-20775
https://jiminny.atlassian.net/browse/JY-20775
Fix inconsistent favicon on PDF report tabs
Bug JY-20772 in Jira Cloud
Preview in Slack
Remove link preview
User Pilot not receiving events on report generated
Bug JY-20773 in Jira Cloud
Preview in Slack
Remove link preview
Automated report - sentry
Bug JY-20776 in Jira Cloud
Preview in Slack
Remove link preview
UserTransformer hasGeneratedAiReports refactor
Bug JY-20775 in Jira Cloud
Preview in Slack
Remove link preview
Scroll left
Scroll right
Shift + Return to add a new line
Shift + Return
to add a new line
20 results
Channel...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.27593085,"top":1.0,"width":0.011968086,"height":-0.058260202},"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,"bounds":{"left":0.30718085,"top":1.0,"width":0.018949468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.01761968,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.02925532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.3587101,"top":1.0,"width":0.0026595744,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.024268618,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.043882977,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.04454787,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.022273935,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.012300532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.010638298,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.034574468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.027593086,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.025930852,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.016289894,"height":-0.09177971},"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":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","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,"bounds":{"left":0.3723404,"top":1.0,"width":0.030917553,"height":-0.09177971},"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":"Add canvas","depth":18,"bounds":{"left":0.40425533,"top":1.0,"width":0.034242023,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.43949467,"top":1.0,"width":0.020944148,"height":-0.09177971},"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":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.46176863,"top":1.0,"width":0.010638298,"height":-0.09177971},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Sep 26th, 2025 at 6:14:34 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:14 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://meet.google.com/txd-hxqc-pus","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://meet.google.com/txd-hxqc-pus","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove preview","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"meet.google.com","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Meet","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Meet","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Oct 6th, 2025 at 9:43:38 AM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9:43 AM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://meet.google.com/iqc-eyhm-xgc","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://meet.google.com/iqc-eyhm-xgc","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove preview","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"meet.google.com","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Meet","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Meet","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Feb 14th at 5:48:06 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:48 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Feb 14th at 5:48:27 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:48","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curl -X POST","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 11th at 8:38:18 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"8:38 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curl -X POST","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"http://192.168.0.242:8100/download","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"http://192.168.0.242:8100/download","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"\\","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"-H “Content-Type: application/json” \\","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"-d ‘{“url”: “","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://www.youtube.com/watch?v=VIDEO_ID","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://www.youtube.com/watch?v=VIDEO_ID","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"”, “format”: “audio”}’","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 12th at 2:51:33 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:51 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"fozjir-jeJcoc-sekhi0","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 12th at 6:43:49 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:43 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Create ticket autolog delay & Vasko about opportunity profile sync","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Remove from Later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775","depth":23,"on_screen":true,"value":"Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Направих и 4 тикета за който не остана време","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20772","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20772","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20773","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20773","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"(добавих ПР който би трябвало да го фиксне),","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20776","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20776","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20775","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20775","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Fix inconsistent favicon on PDF report tabs","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20772 in Jira Cloud","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"User Pilot not receiving events on report generated","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20773 in Jira Cloud","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Automated report - sentry","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20776 in Jira Cloud","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"UserTransformer hasGeneratedAiReports refactor","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20775 in Jira Cloud","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Scroll left","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Scroll right","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Shift + Return to add a new line","depth":20,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Shift + Return","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"to add a new line","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"20 results","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Channel","depth":11,"on_screen":false,"role_description":"text"}]...
|
7810669074852850187
|
-8995423948748978082
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Sep 26th, 2025 at 6:14:34 PM
6:14 PM
https://meet.google.com/txd-hxqc-pus
https://meet.google.com/txd-hxqc-pus
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Oct 6th, 2025 at 9:43:38 AM
9:43 AM
https://meet.google.com/iqc-eyhm-xgc
https://meet.google.com/iqc-eyhm-xgc
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Feb 14th at 5:48:06 PM
5:48 PM
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Feb 14th at 5:48:27 PM
5:48
curl -X POST
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
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
Lukas Kovalik
Mar 11th at 8:38:18 PM
8:38 PM
curl -X POST
http://[IP_ADDRESS]:8100/download
http://[IP_ADDRESS]:8100/download
\
-H “Content-Type: application/json” \
-d ‘{“url”: “
https://www.youtube.com/watch?v=VIDEO_ID
https://www.youtube.com/watch?v=VIDEO_ID
”, “format”: “audio”}’
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
Lukas Kovalik
Mar 12th at 2:51:33 PM
2:51 PM
fozjir-jeJcoc-sekhi0
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Mar 12th at 6:43:49 PM
6:43 PM
Create ticket autolog delay & Vasko about opportunity profile sync
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Remove from Later
More actions
Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775
Направих и 4 тикета за който не остана време
https://jiminny.atlassian.net/browse/JY-20772
https://jiminny.atlassian.net/browse/JY-20772
,
https://jiminny.atlassian.net/browse/JY-20773
https://jiminny.atlassian.net/browse/JY-20773
(добавих ПР който би трябвало да го фиксне),
https://jiminny.atlassian.net/browse/JY-20776
https://jiminny.atlassian.net/browse/JY-20776
и
https://jiminny.atlassian.net/browse/JY-20775
https://jiminny.atlassian.net/browse/JY-20775
Fix inconsistent favicon on PDF report tabs
Bug JY-20772 in Jira Cloud
Preview in Slack
Remove link preview
User Pilot not receiving events on report generated
Bug JY-20773 in Jira Cloud
Preview in Slack
Remove link preview
Automated report - sentry
Bug JY-20776 in Jira Cloud
Preview in Slack
Remove link preview
UserTransformer hasGeneratedAiReports refactor
Bug JY-20775 in Jira Cloud
Preview in Slack
Remove link preview
Scroll left
Scroll right
Shift + Return to add a new line
Shift + Return
to add a new line
20 results
Channel
JY-20903 Update activity sta XSRD-6849) Recorded call doesUsage | Windsurf4(SRD-68481 Sidekick SMS issue(JY-20891] Sidekick SMS issueJY-20891 add support for seconcR (SRD-6849) Recorded call does :[JY-20903] Recorded call does r8 Jiminni1 (SRD-6853] Moxso - Potential de@ JY-20903 Update activity stage& Configure SSH access to multiple ‹* Useful commands - Engineering -JY-20904 Fix UpdateActivityElas(JY-20904) Fix UpdateActivityEla? Jiminnv- New Tabjiminny / app 8<> Code?? Pull requests6. Agents• Actions|0 Wiki• Security and qualityInsights ộ Settings(U On Adri 24 well start usina GitHub Copilot nteraction data for Al mode Itranina unless vou opt out. Review this update and manage vour preterences in vour gifi mo account setinasJY-20903 Update activity stage when opportunity is changed #12077 •I7 Open LakyLak wants to merge 2 commits into master from JY-20903-update_activity-stage-on-opportunity-change ®@ Conversation 4Commits2El Checks 2* Files changed 14 All commitsQ Filter files...• app/ModelsD Activity.phpapp/Models/Activity-php 0 +C -2119,12 +2119,14 @@ public function updateActivityCrmData(array $records): voidSth1s->account 1d = Saccount—>1d* if (Sthis-›stage_id === null && $stage) (Sthis->stage_1d = Sstage->1d;if (Sopportunity d& Sthis->opportunity_id !== Sopportunity->id) €Sthis->opportunity_id = Sopportunity->id;212821292130if (Sopportunity d& Sthis->value !== Sopportunity-»value) ‹ + [PHONE]|• Type (/] to search |100% L2 6* Inu 14 May 10:02:39…+ • 0• Checks pending |• 0/1 viewedCode-( Preview ) •+6 -4 88820SubnitIeven ++6 -4 manz0 [ Viewed0 ...s setns-saccount, ld = soccount -218;if (Sopportunity && Sthis->opportunity_id != Sopportunity->id) €Sthis->opportunity_id = Sopportunity->id;// Reset stage_id when opportunity changes to avoid stale stage from previous opportunity matchsthis->stage_id = $stage?->id;if (Sthis->stage id === null && Sstaae) <Isthis->stage_id = $stage->id;if (Sooportunity &{ Sthis->value !== Soooortunitv->value)<I...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43615
|
1589
|
38
|
2026-05-14T13:02:40.862876+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763760862_m1.jpg...
|
Slack
|
Lukas Kovalik (DM) - Jiminny Inc - 3 new items - S Lukas Kovalik (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Sep 26th, 2025 at 6:14:34 PM
6:14 PM
https://meet.google.com/txd-hxqc-pus
https://meet.google.com/txd-hxqc-pus
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Oct 6th, 2025 at 9:43:38 AM
9:43 AM
https://meet.google.com/iqc-eyhm-xgc
https://meet.google.com/iqc-eyhm-xgc
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Feb 14th at 5:48:06 PM
5:48 PM
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Feb 14th at 5:48:27 PM
5:48
curl -X POST
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
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
Lukas Kovalik
Mar 11th at 8:38:18 PM
8:38 PM
curl -X POST
http://[IP_ADDRESS]:8100/download
http://[IP_ADDRESS]:8100/download
\
-H “Content-Type: application/json” \
-d ‘{“url”: “
https://www.youtube.com/watch?v=VIDEO_ID
https://www.youtube.com/watch?v=VIDEO_ID
”, “format”: “audio”}’
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
Lukas Kovalik
Mar 12th at 2:51:33 PM
2:51 PM
fozjir-jeJcoc-sekhi0
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.011805556,"top":0.08111111,"width":0.025,"height":0.04},"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.00625,"top":0.14,"width":0.036111113,"height":0.075555556},"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.013888889,"top":0.19222222,"width":0.020833334,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.00625,"top":0.21555555,"width":0.036111113,"height":0.075555556},"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.015972223,"top":0.26777777,"width":0.016666668,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.00625,"top":0.2911111,"width":0.036111113,"height":0.075555556},"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.011111111,"top":0.34333333,"width":0.027083334,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.011111111,"top":0.34333333,"width":0.0055555557,"height":0.015555556}},{"char_start":1,"char_count":7,"bounds":{"left":0.015972223,"top":0.34333333,"width":0.022222223,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.00625,"top":0.36666667,"width":0.036111113,"height":0.075555556},"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.016666668,"top":0.4188889,"width":0.015972223,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.016666668,"top":0.4188889,"width":0.004166667,"height":0.015555556}},{"char_start":1,"char_count":4,"bounds":{"left":0.020833334,"top":0.4188889,"width":0.011805556,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.00625,"top":0.4422222,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.49444443,"width":0.018055556,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.00625,"top":0.5177778,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.57,"width":0.01875,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.039583333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.036805555,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.06111111,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.18472221,"top":0.12777779,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.050694443,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.09166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.093055554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.046527777,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.025694445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.022222223,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.072222225,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.057638887,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.054166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.034027778,"height":0.007777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.088194445,"top":0.14666666,"width":0.048611112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.072916664,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":15,"bounds":{"left":0.094444446,"top":0.17777778,"width":0.06666667,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.088194445,"top":0.20888889,"width":0.08055556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.088194445,"top":0.24,"width":0.035416666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.088194445,"top":0.2711111,"width":0.036805555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.05138889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":11,"bounds":{"left":0.093055554,"top":0.30222222,"width":0.045833334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.088194445,"top":0.33333334,"width":0.036111113,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.088194445,"top":0.36444443,"width":0.05138889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.094444446,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.004166667,"height":0.02}},{"char_start":1,"char_count":20,"bounds":{"left":0.09236111,"top":0.39555556,"width":0.09861111,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.088194445,"top":0.46888888,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.088194445,"top":0.5,"width":0.055555556,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.5,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.094444446,"top":0.5,"width":0.048611112,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.088194445,"top":0.5311111,"width":0.07361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.088194445,"top":0.56222224,"width":0.079166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"bounds":{"left":0.088194445,"top":0.5933333,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.6244444,"width":0.07152778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"bounds":{"left":0.088194445,"top":0.65555555,"width":0.06736111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.088194445,"top":0.68666667,"width":0.06666667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.088194445,"top":0.7177778,"width":0.060416665,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.7488889,"width":0.07986111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"bounds":{"left":0.088194445,"top":0.78,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.088194445,"top":0.8111111,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.15555556,"top":0.8111111,"width":0.016666668,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.088194445,"top":0.8844444,"width":0.025694445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.088194445,"top":0.91555554,"width":0.045833334,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.21319444,"top":0.12777779,"width":0.06458333,"height":0.04222222},"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.2326389,"top":0.14,"width":0.039583333,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.27986112,"top":0.12777779,"width":0.07152778,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"bounds":{"left":0.29930556,"top":0.14,"width":0.046527777,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.35347223,"top":0.12777779,"width":0.04375,"height":0.04222222},"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.37291667,"top":0.14,"width":0.01875,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.37291667,"top":0.14,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":4,"bounds":{"left":0.3784722,"top":0.14,"width":0.013194445,"height":0.017777778}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.4,"top":0.12777779,"width":0.022222223,"height":0.04222222},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5402778,"top":0.16111112,"width":0.11875,"height":0.0011111111},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Sep 26th, 2025 at 6:14:34 PM","depth":23,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:14 PM","depth":24,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://meet.google.com/txd-hxqc-pus","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.17569445,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://meet.google.com/txd-hxqc-pus","depth":25,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.17569445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove preview","depth":25,"bounds":{"left":0.2326389,"top":0.16111112,"width":0.013888889,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"meet.google.com","depth":25,"bounds":{"left":0.27430555,"top":0.16111112,"width":0.08055556,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Meet","depth":25,"bounds":{"left":0.2576389,"top":0.16111112,"width":0.025,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Meet","depth":26,"bounds":{"left":0.2576389,"top":0.16111112,"width":0.025,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.","depth":25,"bounds":{"left":0.2576389,"top":0.16111112,"width":0.37361112,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.54791665,"top":0.17666666,"width":0.103472225,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Oct 6th, 2025 at 9:43:38 AM","depth":23,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9:43 AM","depth":24,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://meet.google.com/iqc-eyhm-xgc","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.17708333,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://meet.google.com/iqc-eyhm-xgc","depth":25,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.17708333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove preview","depth":25,"bounds":{"left":0.2326389,"top":0.16111112,"width":0.013888889,"height":0.033333335},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"meet.google.com","depth":25,"bounds":{"left":0.27430555,"top":0.16333333,"width":0.08055556,"height":0.02111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Meet","depth":25,"bounds":{"left":0.2576389,"top":0.18888889,"width":0.025,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Meet","depth":26,"bounds":{"left":0.2576389,"top":0.18888889,"width":0.025,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.","depth":25,"bounds":{"left":0.2576389,"top":0.21333334,"width":0.37361112,"height":0.044444446},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.2576389,"top":0.21333334,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":123,"bounds":{"left":0.2576389,"top":0.21333334,"width":0.37361112,"height":0.044444446}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.53680557,"top":0.28444445,"width":0.125,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.32777777,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.33,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Feb 14th at 5:48:06 PM","depth":23,"bounds":{"left":0.31666666,"top":0.33333334,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:48 PM","depth":24,"bounds":{"left":0.31666666,"top":0.33333334,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":24,"bounds":{"left":0.24652778,"top":0.35444444,"width":0.41319445,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":25,"bounds":{"left":0.24652778,"top":0.35444444,"width":0.41319445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Feb 14th at 5:48:27 PM","depth":24,"bounds":{"left":0.22430556,"top":0.3911111,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:48","depth":25,"bounds":{"left":0.22430556,"top":0.3911111,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curl -X POST","depth":24,"bounds":{"left":0.24652778,"top":0.38777778,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":24,"bounds":{"left":0.30833334,"top":0.38777778,"width":0.4125,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":25,"bounds":{"left":0.30833334,"top":0.38777778,"width":0.4125,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5361111,"top":0.43,"width":0.12638889,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.47333333,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.47555557,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 11th at 8:38:18 PM","depth":23,"bounds":{"left":0.31666666,"top":0.4788889,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"8:38 PM","depth":24,"bounds":{"left":0.31666666,"top":0.4788889,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curl -X POST","depth":24,"bounds":{"left":0.24652778,"top":0.5,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"http://192.168.0.242:8100/download","depth":24,"bounds":{"left":0.30833334,"top":0.5,"width":0.17222223,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"http://192.168.0.242:8100/download","depth":25,"bounds":{"left":0.30833334,"top":0.5,"width":0.17222223,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"\\","depth":24,"bounds":{"left":0.48055556,"top":0.5,"width":0.007638889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"-H “Content-Type: application/json” \\","depth":24,"bounds":{"left":0.24652778,"top":0.52444446,"width":0.17569445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"-d ‘{“url”: “","depth":24,"bounds":{"left":0.24652778,"top":0.54888886,"width":0.052083332,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.24652778,"top":0.54888886,"width":0.0027777778,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.24930556,"top":0.54888886,"width":0.043055557,"height":0.02}}],"role_description":"text"},{"role":"AXLink","text":"https://www.youtube.com/watch?v=VIDEO_ID","depth":24,"bounds":{"left":0.2986111,"top":0.54888886,"width":0.21527778,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://www.youtube.com/watch?v=VIDEO_ID","depth":25,"bounds":{"left":0.2986111,"top":0.54888886,"width":0.21527778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"”, “format”: “audio”}’","depth":24,"bounds":{"left":0.51319444,"top":0.54888886,"width":0.08958333,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.51319444,"top":0.54888886,"width":0.0034722222,"height":0.02}},{"char_start":1,"char_count":21,"bounds":{"left":0.5159722,"top":0.54888886,"width":0.08680555,"height":0.02}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.54097223,"top":0.5911111,"width":0.11666667,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.6344444,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.63666666,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 12th at 2:51:33 PM","depth":23,"bounds":{"left":0.31666666,"top":0.64,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:51 PM","depth":24,"bounds":{"left":0.31666666,"top":0.64,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"fozjir-jeJcoc-sekhi0","depth":24,"bounds":{"left":0.24652778,"top":0.6611111,"width":0.088194445,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.24652778,"top":0.6611111,"width":0.0034722222,"height":0.02}},{"char_start":1,"char_count":19,"bounds":{"left":0.25,"top":0.6611111,"width":0.08472222,"height":0.02}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-582511383658056198
|
-8421214996267624356
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Sep 26th, 2025 at 6:14:34 PM
6:14 PM
https://meet.google.com/txd-hxqc-pus
https://meet.google.com/txd-hxqc-pus
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Oct 6th, 2025 at 9:43:38 AM
9:43 AM
https://meet.google.com/iqc-eyhm-xgc
https://meet.google.com/iqc-eyhm-xgc
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Feb 14th at 5:48:06 PM
5:48 PM
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Feb 14th at 5:48:27 PM
5:48
curl -X POST
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
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
Lukas Kovalik
Mar 11th at 8:38:18 PM
8:38 PM
curl -X POST
http://[IP_ADDRESS]:8100/download
http://[IP_ADDRESS]:8100/download
\
-H “Content-Type: application/json” \
-d ‘{“url”: “
https://www.youtube.com/watch?v=VIDEO_ID
https://www.youtube.com/watch?v=VIDEO_ID
”, “format”: “audio”}’
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
Lukas Kovalik
Mar 12th at 2:51:33 PM
2:51 PM
fozjir-jeJcoc-sekhi0
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
HomeDMsActivityFilesLater..•MoreSlackFileEditViewGoHistoryEDJiminny ...scnicrat# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...• Direct messagesP. Aneliya Angelova€. Vasil Vasilev E. Galya Dimitrova&. Stefka Stoyanova: Todor StamatovMario GeorgievNikolay IvanovLo James Graham2. Stoyan TanevSteliyan GeorgievPetko KashinskiLukas Kovalik youAppsToastJira CloudWindowHelpQDescribe what you are looking forLukas Kovalik• Messagest Add canvas© Files+meet.google.comMeetOctober 6th, 2025 ~Real-time meetings by Google. Using your browser, share your video, desktop, andpresentations with teammates and customers.Saturday, February 14th ~Lukas Kovalik 5:48 PMhttps://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notificationcurl -X POST https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20NotificationWednesday, March 11th ~‹$0ladl19100% C8• Thu 14 May 16:02:40Lukas Kovalik 8:38 PMcurl -X POST http://[IP_ADDRESS]:8100/download \-H "Content-Type: application/json" \-d ("url": "https://www.youtube.com/watch?v=VIDEO_ID", "format": "audio"}'Thursday, March 12th ~Lukas Kovalik 2:51 PMfozjir-jeJcoc-sekhioLukas Kovalik 6:43 PMCreate ticket autolog delay & Vasko about opportunity profile syncНаправих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР койтоби трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775Fix inconsistent favico...Bug JY-20772 in Jira CloudUser Pilot not receivin...XE Bug/Y-20770t ica ou.Automated report - se...2E Bug JY-20776 in Jira Cloudy UserTransformer hasG...X Bug./Y-20775 in Jira Cloud+AaShift + Return to add a new line...
|
43613
|
NULL
|
NULL
|
NULL
|
|
43616
|
1590
|
36
|
2026-05-14T13:02:40.880200+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763760880_m2.jpg...
|
Slack
|
Lukas Kovalik (DM) - Jiminny Inc - 3 new items - S Lukas Kovalik (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Sep 26th, 2025 at 6:14:34 PM
6:14 PM
https://meet.google.com/txd-hxqc-pus
https://meet.google.com/txd-hxqc-pus
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Oct 6th, 2025 at 9:43:38 AM
9:43 AM
https://meet.google.com/iqc-eyhm-xgc
https://meet.google.com/iqc-eyhm-xgc
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Feb 14th at 5:48:06 PM
5:48 PM
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Feb 14th at 5:48:27 PM
5:48
curl -X POST
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
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
Lukas Kovalik
Mar 11th at 8:38:18 PM
8:38 PM
curl -X POST
http://[IP_ADDRESS]:8100/download
http://[IP_ADDRESS]:8100/download
\
-H “Content-Type: application/json” \
-d ‘{“url”: “
https://www.youtube.com/watch?v=VIDEO_ID
https://www.youtube.com/watch?v=VIDEO_ID
”, “format”: “audio”}’
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.27593085,"top":1.0,"width":0.011968086,"height":-0.058260202},"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,"bounds":{"left":0.30718085,"top":1.0,"width":0.018949468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.01761968,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.02925532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.3587101,"top":1.0,"width":0.0026595744,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.024268618,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.043882977,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.04454787,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.022273935,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.012300532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.010638298,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.034574468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.027593086,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.025930852,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.016289894,"height":-0.09177971},"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":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","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,"bounds":{"left":0.3723404,"top":1.0,"width":0.030917553,"height":-0.09177971},"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":"Add canvas","depth":18,"bounds":{"left":0.40425533,"top":1.0,"width":0.034242023,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.43949467,"top":1.0,"width":0.020944148,"height":-0.09177971},"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":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.46176863,"top":1.0,"width":0.010638298,"height":-0.09177971},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Sep 26th, 2025 at 6:14:34 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:14 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://meet.google.com/txd-hxqc-pus","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://meet.google.com/txd-hxqc-pus","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove preview","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"meet.google.com","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Meet","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Meet","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Oct 6th, 2025 at 9:43:38 AM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9:43 AM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://meet.google.com/iqc-eyhm-xgc","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://meet.google.com/iqc-eyhm-xgc","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove preview","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"meet.google.com","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Meet","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Meet","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Feb 14th at 5:48:06 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:48 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Feb 14th at 5:48:27 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:48","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curl -X POST","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 11th at 8:38:18 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"8:38 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curl -X POST","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"http://192.168.0.242:8100/download","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"http://192.168.0.242:8100/download","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"\\","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"-H “Content-Type: application/json” \\","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"-d ‘{“url”: “","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://www.youtube.com/watch?v=VIDEO_ID","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://www.youtube.com/watch?v=VIDEO_ID","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"”, “format”: “audio”}’","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-8863158466586824553
|
-8421214996267888548
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Sep 26th, 2025 at 6:14:34 PM
6:14 PM
https://meet.google.com/txd-hxqc-pus
https://meet.google.com/txd-hxqc-pus
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Oct 6th, 2025 at 9:43:38 AM
9:43 AM
https://meet.google.com/iqc-eyhm-xgc
https://meet.google.com/iqc-eyhm-xgc
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Feb 14th at 5:48:06 PM
5:48 PM
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Feb 14th at 5:48:27 PM
5:48
curl -X POST
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
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
Lukas Kovalik
Mar 11th at 8:38:18 PM
8:38 PM
curl -X POST
http://[IP_ADDRESS]:8100/download
http://[IP_ADDRESS]:8100/download
\
-H “Content-Type: application/json” \
-d ‘{“url”: “
https://www.youtube.com/watch?v=VIDEO_ID
https://www.youtube.com/watch?v=VIDEO_ID
”, “format”: “audio”}’
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
JY-20903 Update activity sta XSRD-6849) Recorded call doesUsage | Windsurf4(SRD-6848] Sidekick SMS issue(JY-20891] Sidekick SMS issueJY-20891 add support for seconcR (SRD-6849) Recorded call does :[JY-20903] Recorded call does r8 Jiminni1 (SRD-6853] Moxso - Potential de@ JY-20903 Update activity stage& Configure SSH access to multiple ‹* Useful commands - Engineering -JY-20904 Fix UpdateActivityElas(JY-20904) Fix UpdateActivityEla? Jiminnv- New Tabjiminny / app 8<> Code?? Pull requests6. Agents• Actions|0 Wiki• Security and qualityInsights ộ Settings(U On Adri 24 well start usina GitHub Copilot nteraction data for Al mode Itranina unless vou opt out. Review this update and manage vour preterences in vour gifi mo account setinasJY-20903 Update activity stage when opportunity is changed #12077 •I7 Open LakyLak wants to merge 2 commits into master from JY-20903-update_activity-stage-on-opportunity-change ®@ Conversation 4Commits2El Checks 2* Files changed 14 All commitsQ Filter files...• app/ModelsE Accivity.phpapp/Models/Activity-php 0 +C -2119,12 +2119,14 @@ public function updateActivityCrmData(array $records): voidSth1s->account 1d = Saccount—>1d* if (Sthis-›stage_id === null && $stage) (Sthis->stage_1d = Sstage->1d;if (Sopportunity d& Sthis-sopportunity_id !== Sopportunity->id) €Sthis->opportunity_id = Sopportunity->id;212821292130if (Sopportunity d& Sthis->value !== Sopportunity-»value) ‹ + [PHONE]|• Type (/] to search100% K/2 8 • Thu 14 May 16:02:40+•0 |1• Checks pending |• 0/1 viewedCode-( Preview ) •+6 -4 88820SubnitIeven ++6 -4 manz0 [ Viewed0 ...s setns-saccount, ld = soccount -218;if (Sopportunity && Sthis->opportunity_id != Sopportunity->id) €Sthis->opportunity_id = Sopportunity->id;// Reset stage_id when opportunity changes to avoid stale stage from previous opportunity matchsthis->stage_id = $stage?->id;if (Sthis->stage id === null && Sstaae) <Isthis->stage_id = $stage->id;if (Sooportunity &{ Sthis->value !== Soooortunitv->value)<I...
|
43614
|
NULL
|
NULL
|
NULL
|
|
43618
|
1590
|
37
|
2026-05-14T13:02:43.125240+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763763125_m2.jpg...
|
Slack
|
Lukas Kovalik (DM) - Jiminny Inc - 3 new items - S Lukas Kovalik (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Sep 26th, 2025 at 6:14:34 PM
6:14 PM
https://meet.google.com/txd-hxqc-pus
https://meet.google.com/txd-hxqc-pus
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Oct 6th, 2025 at 9:43:38 AM
9:43 AM
https://meet.google.com/iqc-eyhm-xgc
https://meet.google.com/iqc-eyhm-xgc
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Feb 14th at 5:48:06 PM
5:48 PM
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Feb 14th at 5:48:27 PM
5:48
curl -X POST
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
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
Lukas Kovalik
Mar 11th at 8:38:18 PM
8:38 PM
curl -X POST
http://[IP_ADDRESS]:8100/download
http://[IP_ADDRESS]:8100/download
\
-H “Content-Type: application/json” \
-d ‘{“url”: “
https://www.youtube.com/watch?v=VIDEO_ID
https://www.youtube.com/watch?v=VIDEO_ID
”, “format”: “audio”}’
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
Lukas Kovalik
Mar 12th at 2:51:33 PM
2:51 PM
fozjir-jeJcoc-sekhi0
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Mar 12th at 6:43:49 PM
6:43 PM
Create ticket autolog delay & Vasko about opportunity profile sync
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Remove from Later
More actions
Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775
Направих и 4 тикета за който не остана време
https://jiminny.atlassian.net/browse/JY-20772
https://jiminny.atlassian.net/browse/JY-20772
,
https://jiminny.atlassian.net/browse/JY-20773
https://jiminny.atlassian.net/browse/JY-20773
(добавих ПР който би трябвало да го фиксне),
https://jiminny.atlassian.net/browse/JY-20776
https://jiminny.atlassian.net/browse/JY-20776
и
https://jiminny.atlassian.net/browse/JY-20775
https://jiminny.atlassian.net/browse/JY-20775
Fix inconsistent favicon on PDF report tabs
Bug JY-20772 in Jira Cloud
Preview in Slack
Remove link preview
User Pilot not receiving events on report generated
Bug JY-20773 in Jira Cloud
Preview in Slack
Remove link preview
Automated report - sentry
Bug JY-20776 in Jira Cloud
Preview in Slack
Remove link preview
UserTransformer hasGeneratedAiReports refactor
Bug JY-20775 in Jira Cloud
Preview in Slack
Remove link preview
Scroll left
Scroll right
Shift + Return to add a new line
Shift + Return
to add a new line
20 results
Channel...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.27593085,"top":1.0,"width":0.011968086,"height":-0.058260202},"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,"bounds":{"left":0.30718085,"top":1.0,"width":0.018949468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.01761968,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.02925532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.3587101,"top":1.0,"width":0.0026595744,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.024268618,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.043882977,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.04454787,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.022273935,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.012300532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.010638298,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.034574468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.027593086,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.025930852,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.016289894,"height":-0.09177971},"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":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","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,"bounds":{"left":0.3723404,"top":1.0,"width":0.030917553,"height":-0.09177971},"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":"Add canvas","depth":18,"bounds":{"left":0.40425533,"top":1.0,"width":0.034242023,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.43949467,"top":1.0,"width":0.020944148,"height":-0.09177971},"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":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.46176863,"top":1.0,"width":0.010638298,"height":-0.09177971},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Sep 26th, 2025 at 6:14:34 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:14 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://meet.google.com/txd-hxqc-pus","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://meet.google.com/txd-hxqc-pus","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove preview","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"meet.google.com","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Meet","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Meet","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Oct 6th, 2025 at 9:43:38 AM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9:43 AM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://meet.google.com/iqc-eyhm-xgc","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://meet.google.com/iqc-eyhm-xgc","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove preview","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"meet.google.com","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Meet","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Meet","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Feb 14th at 5:48:06 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:48 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Feb 14th at 5:48:27 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:48","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curl -X POST","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 11th at 8:38:18 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"8:38 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curl -X POST","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"http://192.168.0.242:8100/download","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"http://192.168.0.242:8100/download","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"\\","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"-H “Content-Type: application/json” \\","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"-d ‘{“url”: “","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://www.youtube.com/watch?v=VIDEO_ID","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://www.youtube.com/watch?v=VIDEO_ID","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"”, “format”: “audio”}’","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 12th at 2:51:33 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:51 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"fozjir-jeJcoc-sekhi0","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 12th at 6:43:49 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:43 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Create ticket autolog delay & Vasko about opportunity profile sync","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Remove from Later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775","depth":23,"on_screen":true,"value":"Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Направих и 4 тикета за който не остана време","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20772","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20772","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20773","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20773","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"(добавих ПР който би трябвало да го фиксне),","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20776","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20776","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20775","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20775","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Fix inconsistent favicon on PDF report tabs","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20772 in Jira Cloud","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"User Pilot not receiving events on report generated","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20773 in Jira Cloud","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Automated report - sentry","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20776 in Jira Cloud","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"UserTransformer hasGeneratedAiReports refactor","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20775 in Jira Cloud","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Scroll left","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Scroll right","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Shift + Return to add a new line","depth":20,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Shift + Return","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"to add a new line","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"20 results","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Channel","depth":11,"on_screen":false,"role_description":"text"}]...
|
7810669074852850187
|
-8995423948748978082
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Sep 26th, 2025 at 6:14:34 PM
6:14 PM
https://meet.google.com/txd-hxqc-pus
https://meet.google.com/txd-hxqc-pus
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Oct 6th, 2025 at 9:43:38 AM
9:43 AM
https://meet.google.com/iqc-eyhm-xgc
https://meet.google.com/iqc-eyhm-xgc
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Feb 14th at 5:48:06 PM
5:48 PM
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Feb 14th at 5:48:27 PM
5:48
curl -X POST
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
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
Lukas Kovalik
Mar 11th at 8:38:18 PM
8:38 PM
curl -X POST
http://[IP_ADDRESS]:8100/download
http://[IP_ADDRESS]:8100/download
\
-H “Content-Type: application/json” \
-d ‘{“url”: “
https://www.youtube.com/watch?v=VIDEO_ID
https://www.youtube.com/watch?v=VIDEO_ID
”, “format”: “audio”}’
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
Lukas Kovalik
Mar 12th at 2:51:33 PM
2:51 PM
fozjir-jeJcoc-sekhi0
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Mar 12th at 6:43:49 PM
6:43 PM
Create ticket autolog delay & Vasko about opportunity profile sync
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Remove from Later
More actions
Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775
Направих и 4 тикета за който не остана време
https://jiminny.atlassian.net/browse/JY-20772
https://jiminny.atlassian.net/browse/JY-20772
,
https://jiminny.atlassian.net/browse/JY-20773
https://jiminny.atlassian.net/browse/JY-20773
(добавих ПР който би трябвало да го фиксне),
https://jiminny.atlassian.net/browse/JY-20776
https://jiminny.atlassian.net/browse/JY-20776
и
https://jiminny.atlassian.net/browse/JY-20775
https://jiminny.atlassian.net/browse/JY-20775
Fix inconsistent favicon on PDF report tabs
Bug JY-20772 in Jira Cloud
Preview in Slack
Remove link preview
User Pilot not receiving events on report generated
Bug JY-20773 in Jira Cloud
Preview in Slack
Remove link preview
Automated report - sentry
Bug JY-20776 in Jira Cloud
Preview in Slack
Remove link preview
UserTransformer hasGeneratedAiReports refactor
Bug JY-20775 in Jira Cloud
Preview in Slack
Remove link preview
Scroll left
Scroll right
Shift + Return to add a new line
Shift + Return
to add a new line
20 results
Channel
JY-20903 Update activity sta XSRD-6849) Recorded call doesUsage | Windsurf4(SRD-6848] Sidekick SMS issue(JY-20891] Sidekick SMS issueJY-20891 add support for seconcR (SRD-6849) Recorded call does :[JY-20903] Recorded call does r8 Jiminni1 (SRD-6853] Moxso - Potential de@ JY-20903 Update activity stage& Configure SSH access to multiple ‹* Useful commands - Engineering -JY-20904 Fix UpdateActivityElas(JY-20904) Fix UpdateActivityEla? Jiminnv- New Tabjiminny / app 8<> Code?? Pull requests6. Agents• Actions|0 Wiki• Security and qualityInsights ộ Settings(U On Adri 24 well start usina GitHub Copilot nteraction data for Al mode Itranina unless vou opt out. Review this update and manage vour preterences in vour gifi mo account setinasJY-20903 Update activity stage when opportunity is changed #12077 •I7 Open LakyLak wants to merge 2 commits into master from JY-20903-update_activity-stage-on-opportunity-change ®@ Conversation 4Commits2El Checks 2* Files changed 14 All commitsQ Filter files...• app/ModelsE Accivity.phpapp/Models/Activity-php 0 +C -2119,12 +2119,14 @@ public function updateActivityCrmData(array $records): voidSth1s->account 1d = Saccount—>1d* if (Sthis-›stage_id === null && $stage) (Sthis->stage_1d = Sstage->1d;if (Sopportunity d& Sthis-sopportunity_id !== Sopportunity->id) €Sthis->opportunity_id = Sopportunity->id;212821292130if (Sopportunity d& Sthis->value !== Sopportunity-»value) ‹ + [PHONE]|• Type (/] to search100% K/2 8 • Thu 14 May 16:02:42+•0 |1• Checks pending |• 0/1 viewedCode-( Preview ) •+6 -4 88820SubnitIeven ++6 -4 manz0 [ Viewed0 ...s setns-saccount, ld = soccount -218;if (Sopportunity && Sthis->opportunity_id != Sopportunity->id) €Sthis->opportunity_id = Sopportunity->id;// Reset stage_id when opportunity changes to avoid stale stage from previous opportunity matchsthis->stage_id = $stage?->id;if (Sthis->stage id === null && Sstaae) <Isthis->stage_id = $stage->id;if (Sooportunity &{ Sthis->value !== Soooortunitv->value)<I...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43617
|
1589
|
39
|
2026-05-14T13:02:43.145941+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763763145_m1.jpg...
|
Slack
|
Lukas Kovalik (DM) - Jiminny Inc - 3 new items - S Lukas Kovalik (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Sep 26th, 2025 at 6:14:34 PM
6:14 PM
https://meet.google.com/txd-hxqc-pus
https://meet.google.com/txd-hxqc-pus
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Oct 6th, 2025 at 9:43:38 AM
9:43 AM
https://meet.google.com/iqc-eyhm-xgc
https://meet.google.com/iqc-eyhm-xgc
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Feb 14th at 5:48:06 PM
5:48 PM
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Feb 14th at 5:48:27 PM
5:48
curl -X POST
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
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
Lukas Kovalik
Mar 11th at 8:38:18 PM
8:38 PM
curl -X POST
http://[IP_ADDRESS]:8100/download
http://[IP_ADDRESS]:8100/download
\
-H “Content-Type: application/json” \
-d ‘{“url”: “
https://www.youtube.com/watch?v=VIDEO_ID
https://www.youtube.com/watch?v=VIDEO_ID
”, “format”: “audio”}’
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
Lukas Kovalik
Mar 12th at 2:51:33 PM
2:51 PM
fozjir-jeJcoc-sekhi0
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Mar 12th at 6:43:49 PM
6:43 PM
Create ticket autolog delay & Vasko about opportunity profile sync
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Remove from Later
More actions
Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775
Направих и 4 тикета за който не остана време
https://jiminny.atlassian.net/browse/JY-20772
https://jiminny.atlassian.net/browse/JY-20772
,
https://jiminny.atlassian.net/browse/JY-20773
https://jiminny.atlassian.net/browse/JY-20773
(добавих ПР който би трябвало да го фиксне),
https://jiminny.atlassian.net/browse/JY-20776
https://jiminny.atlassian.net/browse/JY-20776
и
https://jiminny.atlassian.net/browse/JY-20775
https://jiminny.atlassian.net/browse/JY-20775
Fix inconsistent favicon on PDF report tabs
Bug JY-20772 in Jira Cloud
Preview in Slack
Remove link preview
User Pilot not receiving events on report generated
Bug JY-20773 in Jira Cloud
Preview in Slack
Remove link preview
Automated report - sentry
Bug JY-20776 in Jira Cloud
Preview in Slack
Remove link preview
UserTransformer hasGeneratedAiReports refactor
Bug JY-20775 in Jira Cloud
Preview in Slack
Remove link preview
Scroll left
Scroll right
Shift + Return to add a new line
Shift + Return
to add a new line
20 results
Channel...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.011805556,"top":0.08111111,"width":0.025,"height":0.04},"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.00625,"top":0.14,"width":0.036111113,"height":0.075555556},"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.013888889,"top":0.19222222,"width":0.020833334,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.00625,"top":0.21555555,"width":0.036111113,"height":0.075555556},"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.015972223,"top":0.26777777,"width":0.016666668,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.00625,"top":0.2911111,"width":0.036111113,"height":0.075555556},"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.011111111,"top":0.34333333,"width":0.027083334,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.011111111,"top":0.34333333,"width":0.0055555557,"height":0.015555556}},{"char_start":1,"char_count":7,"bounds":{"left":0.015972223,"top":0.34333333,"width":0.022222223,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.00625,"top":0.36666667,"width":0.036111113,"height":0.075555556},"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.016666668,"top":0.4188889,"width":0.015972223,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.016666668,"top":0.4188889,"width":0.004166667,"height":0.015555556}},{"char_start":1,"char_count":4,"bounds":{"left":0.020833334,"top":0.4188889,"width":0.011805556,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.00625,"top":0.4422222,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.49444443,"width":0.018055556,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.00625,"top":0.5177778,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.57,"width":0.01875,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.039583333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.036805555,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.06111111,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.18472221,"top":0.12777779,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.050694443,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.09166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.093055554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.046527777,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.025694445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.022222223,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.072222225,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.057638887,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.054166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.034027778,"height":0.007777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.088194445,"top":0.14666666,"width":0.048611112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.072916664,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":15,"bounds":{"left":0.094444446,"top":0.17777778,"width":0.06666667,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.088194445,"top":0.20888889,"width":0.08055556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.088194445,"top":0.24,"width":0.035416666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.088194445,"top":0.2711111,"width":0.036805555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.05138889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":11,"bounds":{"left":0.093055554,"top":0.30222222,"width":0.045833334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.088194445,"top":0.33333334,"width":0.036111113,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.088194445,"top":0.36444443,"width":0.05138889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.094444446,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.004166667,"height":0.02}},{"char_start":1,"char_count":20,"bounds":{"left":0.09236111,"top":0.39555556,"width":0.09861111,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.088194445,"top":0.46888888,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.088194445,"top":0.5,"width":0.055555556,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.5,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.094444446,"top":0.5,"width":0.048611112,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.088194445,"top":0.5311111,"width":0.07361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.088194445,"top":0.56222224,"width":0.079166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"bounds":{"left":0.088194445,"top":0.5933333,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.6244444,"width":0.07152778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"bounds":{"left":0.088194445,"top":0.65555555,"width":0.06736111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.088194445,"top":0.68666667,"width":0.06666667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.088194445,"top":0.7177778,"width":0.060416665,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.7488889,"width":0.07986111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"bounds":{"left":0.088194445,"top":0.78,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.088194445,"top":0.8111111,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.15555556,"top":0.8111111,"width":0.016666668,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.088194445,"top":0.8844444,"width":0.025694445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.088194445,"top":0.91555554,"width":0.045833334,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.21319444,"top":0.12777779,"width":0.06458333,"height":0.04222222},"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.2326389,"top":0.14,"width":0.039583333,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.27986112,"top":0.12777779,"width":0.07152778,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"bounds":{"left":0.29930556,"top":0.14,"width":0.046527777,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.35347223,"top":0.12777779,"width":0.04375,"height":0.04222222},"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.37291667,"top":0.14,"width":0.01875,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.37291667,"top":0.14,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":4,"bounds":{"left":0.3784722,"top":0.14,"width":0.013194445,"height":0.017777778}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.4,"top":0.12777779,"width":0.022222223,"height":0.04222222},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5402778,"top":0.16111112,"width":0.11875,"height":0.0011111111},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Sep 26th, 2025 at 6:14:34 PM","depth":23,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:14 PM","depth":24,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://meet.google.com/txd-hxqc-pus","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.17569445,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://meet.google.com/txd-hxqc-pus","depth":25,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.17569445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove preview","depth":25,"bounds":{"left":0.2326389,"top":0.16111112,"width":0.013888889,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"meet.google.com","depth":25,"bounds":{"left":0.27430555,"top":0.16111112,"width":0.08055556,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Meet","depth":25,"bounds":{"left":0.2576389,"top":0.16111112,"width":0.025,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Meet","depth":26,"bounds":{"left":0.2576389,"top":0.16111112,"width":0.025,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.","depth":25,"bounds":{"left":0.2576389,"top":0.16111112,"width":0.37361112,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.54791665,"top":0.17666666,"width":0.103472225,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Oct 6th, 2025 at 9:43:38 AM","depth":23,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9:43 AM","depth":24,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://meet.google.com/iqc-eyhm-xgc","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.17708333,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://meet.google.com/iqc-eyhm-xgc","depth":25,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.17708333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove preview","depth":25,"bounds":{"left":0.2326389,"top":0.16111112,"width":0.013888889,"height":0.033333335},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"meet.google.com","depth":25,"bounds":{"left":0.27430555,"top":0.16333333,"width":0.08055556,"height":0.02111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Meet","depth":25,"bounds":{"left":0.2576389,"top":0.18888889,"width":0.025,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Meet","depth":26,"bounds":{"left":0.2576389,"top":0.18888889,"width":0.025,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.","depth":25,"bounds":{"left":0.2576389,"top":0.21333334,"width":0.37361112,"height":0.044444446},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.2576389,"top":0.21333334,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":123,"bounds":{"left":0.2576389,"top":0.21333334,"width":0.37361112,"height":0.044444446}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.53680557,"top":0.28444445,"width":0.125,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.32777777,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.33,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Feb 14th at 5:48:06 PM","depth":23,"bounds":{"left":0.31666666,"top":0.33333334,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:48 PM","depth":24,"bounds":{"left":0.31666666,"top":0.33333334,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":24,"bounds":{"left":0.24652778,"top":0.35444444,"width":0.41319445,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":25,"bounds":{"left":0.24652778,"top":0.35444444,"width":0.41319445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Feb 14th at 5:48:27 PM","depth":24,"bounds":{"left":0.22430556,"top":0.3911111,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:48","depth":25,"bounds":{"left":0.22430556,"top":0.3911111,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curl -X POST","depth":24,"bounds":{"left":0.24652778,"top":0.38777778,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":24,"bounds":{"left":0.30833334,"top":0.38777778,"width":0.4125,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":25,"bounds":{"left":0.30833334,"top":0.38777778,"width":0.4125,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5361111,"top":0.43,"width":0.12638889,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.47333333,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.47555557,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 11th at 8:38:18 PM","depth":23,"bounds":{"left":0.31666666,"top":0.4788889,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"8:38 PM","depth":24,"bounds":{"left":0.31666666,"top":0.4788889,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curl -X POST","depth":24,"bounds":{"left":0.24652778,"top":0.5,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"http://192.168.0.242:8100/download","depth":24,"bounds":{"left":0.30833334,"top":0.5,"width":0.17222223,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"http://192.168.0.242:8100/download","depth":25,"bounds":{"left":0.30833334,"top":0.5,"width":0.17222223,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"\\","depth":24,"bounds":{"left":0.48055556,"top":0.5,"width":0.007638889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"-H “Content-Type: application/json” \\","depth":24,"bounds":{"left":0.24652778,"top":0.52444446,"width":0.17569445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"-d ‘{“url”: “","depth":24,"bounds":{"left":0.24652778,"top":0.54888886,"width":0.052083332,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.24652778,"top":0.54888886,"width":0.0027777778,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.24930556,"top":0.54888886,"width":0.043055557,"height":0.02}}],"role_description":"text"},{"role":"AXLink","text":"https://www.youtube.com/watch?v=VIDEO_ID","depth":24,"bounds":{"left":0.2986111,"top":0.54888886,"width":0.21527778,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://www.youtube.com/watch?v=VIDEO_ID","depth":25,"bounds":{"left":0.2986111,"top":0.54888886,"width":0.21527778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"”, “format”: “audio”}’","depth":24,"bounds":{"left":0.51319444,"top":0.54888886,"width":0.08958333,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.51319444,"top":0.54888886,"width":0.0034722222,"height":0.02}},{"char_start":1,"char_count":21,"bounds":{"left":0.5159722,"top":0.54888886,"width":0.08680555,"height":0.02}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.54097223,"top":0.5911111,"width":0.11666667,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.6344444,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.63666666,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 12th at 2:51:33 PM","depth":23,"bounds":{"left":0.31666666,"top":0.64,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:51 PM","depth":24,"bounds":{"left":0.31666666,"top":0.64,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"fozjir-jeJcoc-sekhi0","depth":24,"bounds":{"left":0.24652778,"top":0.6611111,"width":0.088194445,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.24652778,"top":0.6611111,"width":0.0034722222,"height":0.02}},{"char_start":1,"char_count":19,"bounds":{"left":0.25,"top":0.6611111,"width":0.08472222,"height":0.02}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.69222224,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.6944444,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 12th at 6:43:49 PM","depth":23,"bounds":{"left":0.31666666,"top":0.69777775,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:43 PM","depth":24,"bounds":{"left":0.31666666,"top":0.69777775,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Create ticket autolog delay & Vasko about opportunity profile sync","depth":24,"bounds":{"left":0.24652778,"top":0.7188889,"width":0.30277777,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Remove from Later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775","depth":23,"bounds":{"left":0.21666667,"top":0.7644445,"width":0.7652778,"height":0.06666667},"on_screen":true,"value":"Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Направих и 4 тикета за който не остана време","depth":25,"bounds":{"left":0.225,"top":0.77555555,"width":0.22569445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20772","depth":25,"bounds":{"left":0.45069444,"top":0.77555555,"width":0.21111111,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20772","depth":26,"bounds":{"left":0.45069444,"top":0.77555555,"width":0.21111111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":25,"bounds":{"left":0.66180557,"top":0.77555555,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20773","depth":25,"bounds":{"left":0.6666667,"top":0.77555555,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20773","depth":26,"bounds":{"left":0.6666667,"top":0.77555555,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"(добавих ПР който би трябвало да го фиксне),","depth":25,"bounds":{"left":0.225,"top":0.77555555,"width":0.7486111,"height":0.044444446},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20776","depth":25,"bounds":{"left":0.35694444,"top":0.8,"width":0.21111111,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20776","depth":26,"bounds":{"left":0.35694444,"top":0.8,"width":0.21111111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и","depth":25,"bounds":{"left":0.56805557,"top":0.8,"width":0.011805556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20775","depth":25,"bounds":{"left":0.57916665,"top":0.8,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20775","depth":26,"bounds":{"left":0.57916665,"top":0.8,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Fix inconsistent favicon on PDF report tabs","depth":26,"bounds":{"left":0.26458332,"top":0.85888886,"width":0.11180556,"height":0.04},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.26458332,"top":0.85888886,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":42,"bounds":{"left":0.26458332,"top":0.85888886,"width":0.11180556,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20772 in Jira Cloud","depth":27,"bounds":{"left":0.26458332,"top":0.8811111,"width":0.108333334,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"bounds":{"left":0.26458332,"top":0.8811111,"width":0.06527778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"bounds":{"left":0.38194445,"top":0.8288889,"width":0.013888889,"height":0.022222223},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"User Pilot not receiving events on report generated","depth":26,"bounds":{"left":0.43958333,"top":0.85888886,"width":0.114583336,"height":0.054444443},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.43958333,"top":0.85888886,"width":0.007638889,"height":0.02}},{"char_start":1,"char_count":50,"bounds":{"left":0.43958333,"top":0.85888886,"width":0.110416666,"height":0.04}}],"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20773 in Jira Cloud","depth":27,"bounds":{"left":0.43958333,"top":0.8811111,"width":0.108333334,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"bounds":{"left":0.43958333,"top":0.8811111,"width":0.06527778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"bounds":{"left":0.55694443,"top":0.8288889,"width":0.013888889,"height":0.022222223},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Automated report - sentry","depth":26,"bounds":{"left":0.6145833,"top":0.85888886,"width":0.11111111,"height":0.04},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.6145833,"top":0.85888886,"width":0.0069444445,"height":0.02}},{"char_start":1,"char_count":24,"bounds":{"left":0.6145833,"top":0.85888886,"width":0.1125,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20776 in Jira Cloud","depth":27,"bounds":{"left":0.6145833,"top":0.8811111,"width":0.108333334,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"bounds":{"left":0.6145833,"top":0.8811111,"width":0.06527778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"bounds":{"left":0.73194444,"top":0.8288889,"width":0.013888889,"height":0.022222223},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"UserTransformer hasGeneratedAiReports refactor","depth":26,"bounds":{"left":0.7895833,"top":0.85888886,"width":0.11180556,"height":0.054444443},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.7895833,"top":0.85888886,"width":0.007638889,"height":0.02}},{"char_start":1,"char_count":45,"bounds":{"left":0.7895833,"top":0.85888886,"width":0.11388889,"height":0.04}}],"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20775 in Jira Cloud","depth":27,"bounds":{"left":0.7895833,"top":0.8811111,"width":0.108333334,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"bounds":{"left":0.7895833,"top":0.8811111,"width":0.06527778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"bounds":{"left":0.90694445,"top":0.8288889,"width":0.013888889,"height":0.022222223},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Scroll left","depth":22,"bounds":{"left":0.21041666,"top":0.8577778,"width":0.02013889,"height":0.032222223},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Scroll right","depth":22,"bounds":{"left":0.9701389,"top":0.8577778,"width":0.02013889,"height":0.032222223},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Shift + Return to add a new line","depth":20,"bounds":{"left":0.87569445,"top":0.9722222,"width":0.10138889,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Shift + Return","depth":21,"bounds":{"left":0.87569445,"top":0.97444445,"width":0.045138888,"height":0.013333334},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"to add a new line","depth":21,"bounds":{"left":0.92083335,"top":0.97444445,"width":0.05625,"height":0.013333334},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"20 results","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Channel","depth":11,"on_screen":false,"role_description":"text"}]...
|
7810669074852850187
|
-8995423948748978082
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Sep 26th, 2025 at 6:14:34 PM
6:14 PM
https://meet.google.com/txd-hxqc-pus
https://meet.google.com/txd-hxqc-pus
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Oct 6th, 2025 at 9:43:38 AM
9:43 AM
https://meet.google.com/iqc-eyhm-xgc
https://meet.google.com/iqc-eyhm-xgc
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Feb 14th at 5:48:06 PM
5:48 PM
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Feb 14th at 5:48:27 PM
5:48
curl -X POST
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
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
Lukas Kovalik
Mar 11th at 8:38:18 PM
8:38 PM
curl -X POST
http://[IP_ADDRESS]:8100/download
http://[IP_ADDRESS]:8100/download
\
-H “Content-Type: application/json” \
-d ‘{“url”: “
https://www.youtube.com/watch?v=VIDEO_ID
https://www.youtube.com/watch?v=VIDEO_ID
”, “format”: “audio”}’
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
Lukas Kovalik
Mar 12th at 2:51:33 PM
2:51 PM
fozjir-jeJcoc-sekhi0
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Mar 12th at 6:43:49 PM
6:43 PM
Create ticket autolog delay & Vasko about opportunity profile sync
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Remove from Later
More actions
Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775
Направих и 4 тикета за който не остана време
https://jiminny.atlassian.net/browse/JY-20772
https://jiminny.atlassian.net/browse/JY-20772
,
https://jiminny.atlassian.net/browse/JY-20773
https://jiminny.atlassian.net/browse/JY-20773
(добавих ПР който би трябвало да го фиксне),
https://jiminny.atlassian.net/browse/JY-20776
https://jiminny.atlassian.net/browse/JY-20776
и
https://jiminny.atlassian.net/browse/JY-20775
https://jiminny.atlassian.net/browse/JY-20775
Fix inconsistent favicon on PDF report tabs
Bug JY-20772 in Jira Cloud
Preview in Slack
Remove link preview
User Pilot not receiving events on report generated
Bug JY-20773 in Jira Cloud
Preview in Slack
Remove link preview
Automated report - sentry
Bug JY-20776 in Jira Cloud
Preview in Slack
Remove link preview
UserTransformer hasGeneratedAiReports refactor
Bug JY-20775 in Jira Cloud
Preview in Slack
Remove link preview
Scroll left
Scroll right
Shift + Return to add a new line
Shift + Return
to add a new line
20 results
Channel
HomeDMsActivityFilesLater..•MoreSlackFileEditViewGoHistoryEDJiminny ...scnicrat# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...• Direct messagesP. Aneliya Angelova€. Vasil Vasilev E®. Galya Dimitrova&. Stefka Stoyanova: Todor StamatovMario GeorgievNikolay IvanovLo James Graham2 Stoyan TanevSteliyan GeorgievPetko KashinskiLukas Kovalik youAppsToastJira CloudWindowHelpQDescribe what you are looking forLukas Kovalik• Messagest Add canvas© Files+meet.google.comMeetOctober 6th, 2025 ~Real-time meetings by Google. Using your browser, share your video, desktop, andpresentations with teammates and customers.Saturday, February 14th ~Lukas Kovalik 5:48 PMhttps://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notificationcurl -X POST https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20NotificationWednesday, March 11th ~‹$0ladl19100% С48• Thu 14 May 16:02:43Lukas Kovalik 8:38 PMcurl -X POST http://[IP_ADDRESS]:8100/download-H "Content-Type: application/json" \-d ("url": "https://www.youtube.com/watch?v=VIDEO_ID", "format": "audio"}'Thursday, March 12th ~Lukas Kovalik 2:51 PMfozjir-jeJcoc-sekhioLukas Kovalik 6:43 PMCreate ticket autolog delay & Vasko about opportunity profile syncНаправих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР койтоби трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775ted report -serlranstormer hasi+АаShift + Return to add a new line...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43619
|
NULL
|
0
|
2026-05-14T13:02:48.525112+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763768525_m1.jpg...
|
Slack
|
Lukas Kovalik (DM) - Jiminny Inc - 3 new items - S Lukas Kovalik (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Sep 26th, 2025 at 6:14:34 PM
6:14 PM
https://meet.google.com/txd-hxqc-pus
https://meet.google.com/txd-hxqc-pus
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Oct 6th, 2025 at 9:43:38 AM
9:43 AM
https://meet.google.com/iqc-eyhm-xgc
https://meet.google.com/iqc-eyhm-xgc
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Feb 14th at 5:48:06 PM
5:48 PM
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Feb 14th at 5:48:27 PM
5:48
curl -X POST
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
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
Lukas Kovalik
Mar 11th at 8:38:18 PM
8:38 PM
curl -X POST
http://[IP_ADDRESS]:8100/download
http://[IP_ADDRESS]:8100/download
\
-H “Content-Type: application/json” \
-d ‘{“url”: “
https://www.youtube.com/watch?v=VIDEO_ID
https://www.youtube.com/watch?v=VIDEO_ID
”, “format”: “audio”}’
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
Lukas Kovalik
Mar 12th at 2:51:33 PM
2:51 PM
fozjir-jeJcoc-sekhi0
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Mar 12th at 6:43:49 PM
6:43 PM
Create ticket autolog delay & Vasko about opportunity profile sync
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Remove from Later
More actions
Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775
Направих и 4 тикета за който не остана време
https://jiminny.atlassian.net/browse/JY-20772
https://jiminny.atlassian.net/browse/JY-20772
,
https://jiminny.atlassian.net/browse/JY-20773
https://jiminny.atlassian.net/browse/JY-20773
(добавих ПР който би трябвало да го фиксне),
https://jiminny.atlassian.net/browse/JY-20776
https://jiminny.atlassian.net/browse/JY-20776
и
https://jiminny.atlassian.net/browse/JY-20775
https://jiminny.atlassian.net/browse/JY-20775
Fix inconsistent favicon on PDF report tabs
Bug JY-20772 in Jira Cloud
Preview in Slack
Remove link preview
User Pilot not receiving events on report generated
Bug JY-20773 in Jira Cloud
Preview in Slack
Remove link preview
Automated report - sentry
Bug JY-20776 in Jira Cloud
Preview in Slack
Remove link preview
UserTransformer hasGeneratedAiReports refactor
Bug JY-20775 in Jira Cloud
Preview in Slack
Remove link preview
Scroll left
Scroll right
Shift + Return to add a new line
Shift + Return
to add a new line
20 results
Channel
Aneliya Angelova...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.011805556,"top":0.08111111,"width":0.025,"height":0.04},"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.00625,"top":0.14,"width":0.036111113,"height":0.075555556},"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.013888889,"top":0.19222222,"width":0.020833334,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.00625,"top":0.21555555,"width":0.036111113,"height":0.075555556},"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.015972223,"top":0.26777777,"width":0.016666668,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.00625,"top":0.2911111,"width":0.036111113,"height":0.075555556},"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.011111111,"top":0.34333333,"width":0.027083334,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.011111111,"top":0.34333333,"width":0.0055555557,"height":0.015555556}},{"char_start":1,"char_count":7,"bounds":{"left":0.015972223,"top":0.34333333,"width":0.022222223,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.00625,"top":0.36666667,"width":0.036111113,"height":0.075555556},"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.016666668,"top":0.4188889,"width":0.015972223,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.016666668,"top":0.4188889,"width":0.004166667,"height":0.015555556}},{"char_start":1,"char_count":4,"bounds":{"left":0.020833334,"top":0.4188889,"width":0.011805556,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.00625,"top":0.4422222,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.49444443,"width":0.018055556,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.00625,"top":0.5177778,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.57,"width":0.01875,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.039583333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.036805555,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.06111111,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.18472221,"top":0.12777779,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.050694443,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.09166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.093055554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.046527777,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.025694445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.022222223,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.072222225,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.057638887,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.054166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.034027778,"height":0.007777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.088194445,"top":0.14666666,"width":0.048611112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.072916664,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":15,"bounds":{"left":0.094444446,"top":0.17777778,"width":0.06666667,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.088194445,"top":0.20888889,"width":0.08055556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.088194445,"top":0.24,"width":0.035416666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.088194445,"top":0.2711111,"width":0.036805555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.05138889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":11,"bounds":{"left":0.093055554,"top":0.30222222,"width":0.045833334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.088194445,"top":0.33333334,"width":0.036111113,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.088194445,"top":0.36444443,"width":0.05138889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.094444446,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.004166667,"height":0.02}},{"char_start":1,"char_count":20,"bounds":{"left":0.09236111,"top":0.39555556,"width":0.09861111,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":24,"bounds":{"left":0.088194445,"top":0.46888888,"width":0.07013889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.46888888,"width":0.0069444445,"height":0.02}},{"char_start":1,"char_count":15,"bounds":{"left":0.09513889,"top":0.46888888,"width":0.07152778,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.088194445,"top":0.5,"width":0.055555556,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.5,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.094444446,"top":0.5,"width":0.048611112,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.088194445,"top":0.5311111,"width":0.07361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.088194445,"top":0.56222224,"width":0.079166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"bounds":{"left":0.088194445,"top":0.5933333,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.6244444,"width":0.07152778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"bounds":{"left":0.088194445,"top":0.65555555,"width":0.06736111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.088194445,"top":0.68666667,"width":0.06666667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.088194445,"top":0.7177778,"width":0.060416665,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.7488889,"width":0.07986111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"bounds":{"left":0.088194445,"top":0.78,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.088194445,"top":0.8111111,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.15555556,"top":0.8111111,"width":0.016666668,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.088194445,"top":0.8844444,"width":0.025694445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.088194445,"top":0.91555554,"width":0.045833334,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.21319444,"top":0.12777779,"width":0.06458333,"height":0.04222222},"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.2326389,"top":0.14,"width":0.039583333,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.27986112,"top":0.12777779,"width":0.07152778,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"bounds":{"left":0.29930556,"top":0.14,"width":0.046527777,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.35347223,"top":0.12777779,"width":0.04375,"height":0.04222222},"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.37291667,"top":0.14,"width":0.01875,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.37291667,"top":0.14,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":4,"bounds":{"left":0.3784722,"top":0.14,"width":0.013194445,"height":0.017777778}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.4,"top":0.12777779,"width":0.022222223,"height":0.04222222},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5402778,"top":0.16111112,"width":0.11875,"height":0.0011111111},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Sep 26th, 2025 at 6:14:34 PM","depth":23,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:14 PM","depth":24,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://meet.google.com/txd-hxqc-pus","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.17569445,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://meet.google.com/txd-hxqc-pus","depth":25,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.17569445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove preview","depth":25,"bounds":{"left":0.2326389,"top":0.16111112,"width":0.013888889,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"meet.google.com","depth":25,"bounds":{"left":0.27430555,"top":0.16111112,"width":0.08055556,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Meet","depth":25,"bounds":{"left":0.2576389,"top":0.16111112,"width":0.025,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Meet","depth":26,"bounds":{"left":0.2576389,"top":0.16111112,"width":0.025,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.","depth":25,"bounds":{"left":0.2576389,"top":0.16111112,"width":0.37361112,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.54791665,"top":0.17666666,"width":0.103472225,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Oct 6th, 2025 at 9:43:38 AM","depth":23,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9:43 AM","depth":24,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.031944446,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://meet.google.com/iqc-eyhm-xgc","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.17708333,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://meet.google.com/iqc-eyhm-xgc","depth":25,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.17708333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove preview","depth":25,"bounds":{"left":0.2326389,"top":0.16111112,"width":0.013888889,"height":0.033333335},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"meet.google.com","depth":25,"bounds":{"left":0.27430555,"top":0.16333333,"width":0.08055556,"height":0.02111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Meet","depth":25,"bounds":{"left":0.2576389,"top":0.18888889,"width":0.025,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Meet","depth":26,"bounds":{"left":0.2576389,"top":0.18888889,"width":0.025,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.","depth":25,"bounds":{"left":0.2576389,"top":0.21333334,"width":0.37361112,"height":0.044444446},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.2576389,"top":0.21333334,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":123,"bounds":{"left":0.2576389,"top":0.21333334,"width":0.37361112,"height":0.044444446}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.53680557,"top":0.28444445,"width":0.125,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.32777777,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.33,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Feb 14th at 5:48:06 PM","depth":23,"bounds":{"left":0.31666666,"top":0.33333334,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:48 PM","depth":24,"bounds":{"left":0.31666666,"top":0.33333334,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":24,"bounds":{"left":0.24652778,"top":0.35444444,"width":0.41319445,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":25,"bounds":{"left":0.24652778,"top":0.35444444,"width":0.41319445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Feb 14th at 5:48:27 PM","depth":24,"bounds":{"left":0.22430556,"top":0.3911111,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:48","depth":25,"bounds":{"left":0.22430556,"top":0.3911111,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curl -X POST","depth":24,"bounds":{"left":0.24652778,"top":0.38777778,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":24,"bounds":{"left":0.30833334,"top":0.38777778,"width":0.4125,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":25,"bounds":{"left":0.30833334,"top":0.38777778,"width":0.4125,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5361111,"top":0.43,"width":0.12638889,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.47333333,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.47555557,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 11th at 8:38:18 PM","depth":23,"bounds":{"left":0.31666666,"top":0.4788889,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"8:38 PM","depth":24,"bounds":{"left":0.31666666,"top":0.4788889,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curl -X POST","depth":24,"bounds":{"left":0.24652778,"top":0.5,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"http://192.168.0.242:8100/download","depth":24,"bounds":{"left":0.30833334,"top":0.5,"width":0.17222223,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"http://192.168.0.242:8100/download","depth":25,"bounds":{"left":0.30833334,"top":0.5,"width":0.17222223,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"\\","depth":24,"bounds":{"left":0.48055556,"top":0.5,"width":0.007638889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"-H “Content-Type: application/json” \\","depth":24,"bounds":{"left":0.24652778,"top":0.52444446,"width":0.17569445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"-d ‘{“url”: “","depth":24,"bounds":{"left":0.24652778,"top":0.54888886,"width":0.052083332,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.24652778,"top":0.54888886,"width":0.0027777778,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.24930556,"top":0.54888886,"width":0.043055557,"height":0.02}}],"role_description":"text"},{"role":"AXLink","text":"https://www.youtube.com/watch?v=VIDEO_ID","depth":24,"bounds":{"left":0.2986111,"top":0.54888886,"width":0.21527778,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://www.youtube.com/watch?v=VIDEO_ID","depth":25,"bounds":{"left":0.2986111,"top":0.54888886,"width":0.21527778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"”, “format”: “audio”}’","depth":24,"bounds":{"left":0.51319444,"top":0.54888886,"width":0.08958333,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.51319444,"top":0.54888886,"width":0.0034722222,"height":0.02}},{"char_start":1,"char_count":21,"bounds":{"left":0.5159722,"top":0.54888886,"width":0.08680555,"height":0.02}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.54097223,"top":0.5911111,"width":0.11666667,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.6344444,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.63666666,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 12th at 2:51:33 PM","depth":23,"bounds":{"left":0.31666666,"top":0.64,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:51 PM","depth":24,"bounds":{"left":0.31666666,"top":0.64,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"fozjir-jeJcoc-sekhi0","depth":24,"bounds":{"left":0.24652778,"top":0.6611111,"width":0.088194445,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.24652778,"top":0.6611111,"width":0.0034722222,"height":0.02}},{"char_start":1,"char_count":19,"bounds":{"left":0.25,"top":0.6611111,"width":0.08472222,"height":0.02}}],"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.69222224,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.6944444,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 12th at 6:43:49 PM","depth":23,"bounds":{"left":0.31666666,"top":0.69777775,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:43 PM","depth":24,"bounds":{"left":0.31666666,"top":0.69777775,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Create ticket autolog delay & Vasko about opportunity profile sync","depth":24,"bounds":{"left":0.24652778,"top":0.7188889,"width":0.30277777,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Remove from Later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775","depth":23,"bounds":{"left":0.21666667,"top":0.7644445,"width":0.7652778,"height":0.06666667},"on_screen":true,"value":"Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Направих и 4 тикета за който не остана време","depth":25,"bounds":{"left":0.225,"top":0.77555555,"width":0.22569445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20772","depth":25,"bounds":{"left":0.45069444,"top":0.77555555,"width":0.21111111,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20772","depth":26,"bounds":{"left":0.45069444,"top":0.77555555,"width":0.21111111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":25,"bounds":{"left":0.66180557,"top":0.77555555,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20773","depth":25,"bounds":{"left":0.6666667,"top":0.77555555,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20773","depth":26,"bounds":{"left":0.6666667,"top":0.77555555,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"(добавих ПР който би трябвало да го фиксне),","depth":25,"bounds":{"left":0.225,"top":0.77555555,"width":0.7486111,"height":0.044444446},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20776","depth":25,"bounds":{"left":0.35694444,"top":0.8,"width":0.21111111,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20776","depth":26,"bounds":{"left":0.35694444,"top":0.8,"width":0.21111111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и","depth":25,"bounds":{"left":0.56805557,"top":0.8,"width":0.011805556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20775","depth":25,"bounds":{"left":0.57916665,"top":0.8,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20775","depth":26,"bounds":{"left":0.57916665,"top":0.8,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Fix inconsistent favicon on PDF report tabs","depth":26,"bounds":{"left":0.26458332,"top":0.85888886,"width":0.11180556,"height":0.04},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.26458332,"top":0.85888886,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":42,"bounds":{"left":0.26458332,"top":0.85888886,"width":0.11180556,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20772 in Jira Cloud","depth":27,"bounds":{"left":0.26458332,"top":0.8811111,"width":0.108333334,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"bounds":{"left":0.26458332,"top":0.8811111,"width":0.06527778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"bounds":{"left":0.38194445,"top":0.8288889,"width":0.013888889,"height":0.022222223},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"User Pilot not receiving events on report generated","depth":26,"bounds":{"left":0.43958333,"top":0.85888886,"width":0.114583336,"height":0.054444443},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.43958333,"top":0.85888886,"width":0.007638889,"height":0.02}},{"char_start":1,"char_count":50,"bounds":{"left":0.43958333,"top":0.85888886,"width":0.110416666,"height":0.04}}],"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20773 in Jira Cloud","depth":27,"bounds":{"left":0.43958333,"top":0.8811111,"width":0.108333334,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"bounds":{"left":0.43958333,"top":0.8811111,"width":0.06527778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"bounds":{"left":0.55694443,"top":0.8288889,"width":0.013888889,"height":0.022222223},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Automated report - sentry","depth":26,"bounds":{"left":0.6145833,"top":0.85888886,"width":0.11111111,"height":0.04},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.6145833,"top":0.85888886,"width":0.0069444445,"height":0.02}},{"char_start":1,"char_count":24,"bounds":{"left":0.6145833,"top":0.85888886,"width":0.1125,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20776 in Jira Cloud","depth":27,"bounds":{"left":0.6145833,"top":0.8811111,"width":0.108333334,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"bounds":{"left":0.6145833,"top":0.8811111,"width":0.06527778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"bounds":{"left":0.73194444,"top":0.8288889,"width":0.013888889,"height":0.022222223},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"UserTransformer hasGeneratedAiReports refactor","depth":26,"bounds":{"left":0.7895833,"top":0.85888886,"width":0.11180556,"height":0.054444443},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.7895833,"top":0.85888886,"width":0.007638889,"height":0.02}},{"char_start":1,"char_count":45,"bounds":{"left":0.7895833,"top":0.85888886,"width":0.11388889,"height":0.04}}],"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20775 in Jira Cloud","depth":27,"bounds":{"left":0.7895833,"top":0.8811111,"width":0.108333334,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"bounds":{"left":0.7895833,"top":0.8811111,"width":0.06527778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"bounds":{"left":0.90694445,"top":0.8288889,"width":0.013888889,"height":0.022222223},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Scroll left","depth":22,"bounds":{"left":0.21041666,"top":0.8577778,"width":0.02013889,"height":0.032222223},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Scroll right","depth":22,"bounds":{"left":0.9701389,"top":0.8577778,"width":0.02013889,"height":0.032222223},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Shift + Return to add a new line","depth":20,"bounds":{"left":0.87569445,"top":0.9722222,"width":0.10138889,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Shift + Return","depth":21,"bounds":{"left":0.87569445,"top":0.97444445,"width":0.045138888,"height":0.013333334},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"to add a new line","depth":21,"bounds":{"left":0.92083335,"top":0.97444445,"width":0.05625,"height":0.013333334},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"20 results","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Channel","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":13,"bounds":{"left":0.08958333,"top":0.42666668,"width":0.06944445,"height":0.017777778},"on_screen":true,"role_description":"text"}]...
|
2596268126970991154
|
-8995423948748978082
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Sep 26th, 2025 at 6:14:34 PM
6:14 PM
https://meet.google.com/txd-hxqc-pus
https://meet.google.com/txd-hxqc-pus
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Oct 6th, 2025 at 9:43:38 AM
9:43 AM
https://meet.google.com/iqc-eyhm-xgc
https://meet.google.com/iqc-eyhm-xgc
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Feb 14th at 5:48:06 PM
5:48 PM
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Feb 14th at 5:48:27 PM
5:48
curl -X POST
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
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
Lukas Kovalik
Mar 11th at 8:38:18 PM
8:38 PM
curl -X POST
http://[IP_ADDRESS]:8100/download
http://[IP_ADDRESS]:8100/download
\
-H “Content-Type: application/json” \
-d ‘{“url”: “
https://www.youtube.com/watch?v=VIDEO_ID
https://www.youtube.com/watch?v=VIDEO_ID
”, “format”: “audio”}’
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
Lukas Kovalik
Mar 12th at 2:51:33 PM
2:51 PM
fozjir-jeJcoc-sekhi0
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Mar 12th at 6:43:49 PM
6:43 PM
Create ticket autolog delay & Vasko about opportunity profile sync
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Remove from Later
More actions
Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775
Направих и 4 тикета за който не остана време
https://jiminny.atlassian.net/browse/JY-20772
https://jiminny.atlassian.net/browse/JY-20772
,
https://jiminny.atlassian.net/browse/JY-20773
https://jiminny.atlassian.net/browse/JY-20773
(добавих ПР който би трябвало да го фиксне),
https://jiminny.atlassian.net/browse/JY-20776
https://jiminny.atlassian.net/browse/JY-20776
и
https://jiminny.atlassian.net/browse/JY-20775
https://jiminny.atlassian.net/browse/JY-20775
Fix inconsistent favicon on PDF report tabs
Bug JY-20772 in Jira Cloud
Preview in Slack
Remove link preview
User Pilot not receiving events on report generated
Bug JY-20773 in Jira Cloud
Preview in Slack
Remove link preview
Automated report - sentry
Bug JY-20776 in Jira Cloud
Preview in Slack
Remove link preview
UserTransformer hasGeneratedAiReports refactor
Bug JY-20775 in Jira Cloud
Preview in Slack
Remove link preview
Scroll left
Scroll right
Shift + Return to add a new line
Shift + Return
to add a new line
20 results
Channel
Aneliya Angelova
HomeDMsActivityFilesLater..•MoreSlackFileEditViewGoHistoryEDJiminny ...scnicrat# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...• Direct messages8. Aneliya AngelovaGalya Dimitrova/asil Vasilev.-%. Galya Dimitro...&. Stefka Stoyanova: Todor StamatovMario GeorgievNikolay IvanovLo James Graham2 Stoyan TanevSteliyan GeorgievPetko KashinskiLukas Kovalik youAppsToastJira CloudWindowHelpQDescribe what you are looking forLukas Kovalik• Messagest Add canvas© Files+meet.google.comMeetOctober 6th, 2025 ~Real-time meetings by Google. Using your browser, share your video, desktop, andpresentations with teammates and customers.Saturday, February 14th~Lukas Kovalik 5:48 PMhttps://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notificationcurl -X POST https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20NotificationWednesday, March 11th ~‹$0ladl19100% C8• Thu 14 May 16:02:48Lukas Kovalik 8:38 PMcurl -X POST http://[IP_ADDRESS]:8100/download \-H "Content-Type: application/json" \-d '("url": "https://www.youtube.com/watch?v=VIDEO_ID", "format": "audio"}Thursday, March 12th ~Lukas Kovalik 2:51 PMfozjir-jeJcoc-sekhioLukas Kovalik 6:43 PMCreate ticket autolog delay & Vasko about opportunitunenflnanaBIUSO20E2https://jiminny.atlassian.net/browse/JY-20772 https://jiminny.atlassian.net/browse/JY-20773https://jiminny.atlassian.net/browse/JY-20776https://jiminny.atlassian.net/browse/JY-20775Fix inconsistent favico...Bug JY-20772 in Jira CloudUser Pilot not receivin...XE Bug YP-207 73 in Jia cViueAutomated report - se...Bug Y-20776 in Jira CloudUserTransformer hasG...XE BugJY-20775 in Jira Cioud+AaShift + Return to add a new line...
|
43617
|
NULL
|
NULL
|
NULL
|
|
43620
|
NULL
|
0
|
2026-05-14T13:02:48.554383+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763768554_m2.jpg...
|
Slack
|
Lukas Kovalik (DM) - Jiminny Inc - 3 new items - S Lukas Kovalik (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Sep 26th, 2025 at 6:14:34 PM
6:14 PM
https://meet.google.com/txd-hxqc-pus
https://meet.google.com/txd-hxqc-pus
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Oct 6th, 2025 at 9:43:38 AM
9:43 AM
https://meet.google.com/iqc-eyhm-xgc
https://meet.google.com/iqc-eyhm-xgc
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Feb 14th at 5:48:06 PM
5:48 PM
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Feb 14th at 5:48:27 PM
5:48
curl -X POST
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
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
Lukas Kovalik
Mar 11th at 8:38:18 PM
8:38 PM
curl -X POST
http://[IP_ADDRESS]:8100/download
http://[IP_ADDRESS]:8100/download
\
-H “Content-Type: application/json” \
-d ‘{“url”: “
https://www.youtube.com/watch?v=VIDEO_ID
https://www.youtube.com/watch?v=VIDEO_ID
”, “format”: “audio”}’
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
Lukas Kovalik
Mar 12th at 2:51:33 PM
2:51 PM
fozjir-jeJcoc-sekhi0
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Mar 12th at 6:43:49 PM
6:43 PM
Create ticket autolog delay & Vasko about opportunity profile sync
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Remove from Later
More actions
Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775
Направих и 4 тикета за който не остана време
https://jiminny.atlassian.net/browse/JY-20772
https://jiminny.atlassian.net/browse/JY-20772
,
https://jiminny.atlassian.net/browse/JY-20773
https://jiminny.atlassian.net/browse/JY-20773
(добавих ПР който би трябвало да го фиксне),
https://jiminny.atlassian.net/browse/JY-20776
https://jiminny.atlassian.net/browse/JY-20776
и
https://jiminny.atlassian.net/browse/JY-20775
https://jiminny.atlassian.net/browse/JY-20775
Fix inconsistent favicon on PDF report tabs
Bug JY-20772 in Jira Cloud
Preview in Slack
Remove link preview
User Pilot not receiving events on report generated
Bug JY-20773 in Jira Cloud
Preview in Slack
Remove link preview
Automated report - sentry
Bug JY-20776 in Jira Cloud
Preview in Slack
Remove link preview
UserTransformer hasGeneratedAiReports refactor
Bug JY-20775 in Jira Cloud
Preview in Slack
Remove link preview
Scroll left
Scroll right
Shift + Return to add a new line
Shift + Return
to add a new line
20 results
Channel
Aneliya Angelova...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.27593085,"top":1.0,"width":0.011968086,"height":-0.058260202},"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,"bounds":{"left":0.30718085,"top":1.0,"width":0.018949468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.01761968,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.02925532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.3587101,"top":1.0,"width":0.0026595744,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.30718085,"top":1.0,"width":0.024268618,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.043882977,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.04454787,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.022273935,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.012300532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.010638298,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.034574468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.027593086,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.025930852,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.3125,"top":1.0,"width":0.016289894,"height":-0.09177971},"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":"Aneliya Angelova","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","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,"bounds":{"left":0.3723404,"top":1.0,"width":0.030917553,"height":-0.09177971},"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":"Add canvas","depth":18,"bounds":{"left":0.40425533,"top":1.0,"width":0.034242023,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.43949467,"top":1.0,"width":0.020944148,"height":-0.09177971},"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":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.46176863,"top":1.0,"width":0.010638298,"height":-0.09177971},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Sep 26th, 2025 at 6:14:34 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:14 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://meet.google.com/txd-hxqc-pus","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://meet.google.com/txd-hxqc-pus","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove preview","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"meet.google.com","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Meet","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Meet","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Oct 6th, 2025 at 9:43:38 AM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9:43 AM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://meet.google.com/iqc-eyhm-xgc","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://meet.google.com/iqc-eyhm-xgc","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove preview","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"meet.google.com","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Meet","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Meet","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Feb 14th at 5:48:06 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:48 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Feb 14th at 5:48:27 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:48","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curl -X POST","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 11th at 8:38:18 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"8:38 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curl -X POST","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"http://192.168.0.242:8100/download","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"http://192.168.0.242:8100/download","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"\\","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"-H “Content-Type: application/json” \\","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"-d ‘{“url”: “","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://www.youtube.com/watch?v=VIDEO_ID","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://www.youtube.com/watch?v=VIDEO_ID","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"”, “format”: “audio”}’","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 12th at 2:51:33 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:51 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"fozjir-jeJcoc-sekhi0","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Mar 12th at 6:43:49 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6:43 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Create ticket autolog delay & Vasko about opportunity profile sync","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Remove from Later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775","depth":23,"on_screen":true,"value":"Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Направих и 4 тикета за който не остана време","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20772","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20772","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20773","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20773","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"(добавих ПР който би трябвало да го фиксне),","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20776","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20776","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20775","depth":25,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20775","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Fix inconsistent favicon on PDF report tabs","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20772 in Jira Cloud","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"User Pilot not receiving events on report generated","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20773 in Jira Cloud","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Automated report - sentry","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20776 in Jira Cloud","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"UserTransformer hasGeneratedAiReports refactor","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20775 in Jira Cloud","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove link preview","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Scroll left","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Scroll right","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Shift + Return to add a new line","depth":20,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Shift + Return","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"to add a new line","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"20 results","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Channel","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":13,"on_screen":true,"role_description":"text"}]...
|
2596268126970991154
|
-8995423948748978082
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Sep 26th, 2025 at 6:14:34 PM
6:14 PM
https://meet.google.com/txd-hxqc-pus
https://meet.google.com/txd-hxqc-pus
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Oct 6th, 2025 at 9:43:38 AM
9:43 AM
https://meet.google.com/iqc-eyhm-xgc
https://meet.google.com/iqc-eyhm-xgc
Remove preview
meet.google.com
Meet
Meet
Real-time meetings by Google. Using your browser, share your video, desktop, and presentations with teammates and customers.
Jump to date
Lukas Kovalik
Feb 14th at 5:48:06 PM
5:48 PM
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Feb 14th at 5:48:27 PM
5:48
curl -X POST
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
https://api.pushcut.io/EFZez29JBvFml7wPTjKyl/notifications/My%20First%20Notification
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
Lukas Kovalik
Mar 11th at 8:38:18 PM
8:38 PM
curl -X POST
http://[IP_ADDRESS]:8100/download
http://[IP_ADDRESS]:8100/download
\
-H “Content-Type: application/json” \
-d ‘{“url”: “
https://www.youtube.com/watch?v=VIDEO_ID
https://www.youtube.com/watch?v=VIDEO_ID
”, “format”: “audio”}’
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
Lukas Kovalik
Mar 12th at 2:51:33 PM
2:51 PM
fozjir-jeJcoc-sekhi0
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Mar 12th at 6:43:49 PM
6:43 PM
Create ticket autolog delay & Vasko about opportunity profile sync
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Remove from Later
More actions
Направих и 4 тикета за който не остана време https://jiminny.atlassian.net/browse/JY-20772, https://jiminny.atlassian.net/browse/JY-20773 (добавих ПР който би трябвало да го фиксне), https://jiminny.atlassian.net/browse/JY-20776 и https://jiminny.atlassian.net/browse/JY-20775
Направих и 4 тикета за който не остана време
https://jiminny.atlassian.net/browse/JY-20772
https://jiminny.atlassian.net/browse/JY-20772
,
https://jiminny.atlassian.net/browse/JY-20773
https://jiminny.atlassian.net/browse/JY-20773
(добавих ПР който би трябвало да го фиксне),
https://jiminny.atlassian.net/browse/JY-20776
https://jiminny.atlassian.net/browse/JY-20776
и
https://jiminny.atlassian.net/browse/JY-20775
https://jiminny.atlassian.net/browse/JY-20775
Fix inconsistent favicon on PDF report tabs
Bug JY-20772 in Jira Cloud
Preview in Slack
Remove link preview
User Pilot not receiving events on report generated
Bug JY-20773 in Jira Cloud
Preview in Slack
Remove link preview
Automated report - sentry
Bug JY-20776 in Jira Cloud
Preview in Slack
Remove link preview
UserTransformer hasGeneratedAiReports refactor
Bug JY-20775 in Jira Cloud
Preview in Slack
Remove link preview
Scroll left
Scroll right
Shift + Return to add a new line
Shift + Return
to add a new line
20 results
Channel
Aneliya Angelova
JY-20903 Update activity sta XSRD-6849) Recorded call doesUsage | Windsurf4(SRD-6848] Sidekick SMS issue(JY-20891] Sidekick SMS issueJY-20891 add support for seconcR (SRD-6849) Recorded call does :[JY-20903] Recorded call does r8 Jiminni1 (SRD-6853] Moxso - Potential de@ JY-20903 Update activity stage& Configure SSH access to multiple ‹* Useful commands - Engineering -JY-20904 Fix UpdateActivityElas(JY-20904) Fix UpdateActivityEla? Jiminnv- New Tabjiminny / app 8<> Code?? Pull requests6. Agents• Actions|0 Wiki• Security and qualityInsights ộ Settings(U On Adri 24 well start usina GitHub Copilot nteraction data for Al mode Itranina unless vou opt out. Review this update and manage vour preterences in vour gifi mo account setinasJY-20903 Update activity stage when opportunity is changed #12077 •I7 Open LakyLak wants to merge 2 commits into master from JY-20903-update_activity-stage-on-opportunity-change ®@ Conversation 4Commits2El Checks 2* Files changed 14 All commitsQ Filter files...• app/ModelsD Activity.phpapp/Models/Activity-php 0 +C -2119,12 +2119,14 @@ public function updateActivityCrmData(array $records): voidSth1s->account 1d = Saccount—>1d* if (Sthis-›stage_id === null && $stage) (Sthis->stage_1d = Sstage->1d;if (Sopportunity d& Sthis-sopportunity_id !== Sopportunity->id) €Sthis->opportunity_id = Sopportunity->id;212821292130if (Sopportunity d& Sthis->value !== Sopportunity-»value) ‹ + [PHONE]|• Type (/] to search100% K/2 8 • Thu 14 May 16:02:48+•0 |1• Checks pending |• 0/1 viewedCode-( Preview ) •+6 -4 88820SubnitIeven ++6 -4 manz0 [ Viewed0 ...s setns-saccount, ld = soccount -218;if (Sopportunity && Sthis->opportunity_id != Sopportunity->id) €Sthis->opportunity_id = Sopportunity->id;// Reset stage_id when opportunity changes to avoid stale stage from previous opportunity matchsthis->stage_id = $stage?->id;if (Sthis->stage id === null && Sstaae) <Isthis->stage_id = $stage->id;if (Sopportunity && $this->value !== Sopportunity->value) {...
|
43618
|
NULL
|
NULL
|
NULL
|
|
43621
|
1591
|
0
|
2026-05-14T13:02:49.645630+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763769645_m1.jpg...
|
Slack
|
Aneliya Angelova (DM) - Jiminny Inc - 3 new items Aneliya Angelova (DM) - Jiminny Inc - 3 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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
Jump to date
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:51:36 PM
2:51
трябва да се за всички, някъде не се ли попълва
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:52:10 PM
2:52
при зохо май беше hardcoded но май и там си връщаха две категории
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Aneliya Angelova
Today at 4:00:37 PM
4:00 PM
Лукаш имаш ли време да се чуем за тестването на
https://jiminny.atlassian.net/browse/JY-20725
https://jiminny.atlassian.net/browse/JY-20725
Jira Cloud
Jira Cloud
Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise
[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts
Bug JY-20725 in Jira Cloud
Preview in Slack
Status
Ready for QA
Priority
Medium
Assignee
Aneliya Angelova
As of today at 4:00 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug JY-20725
View conversations
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
Lukas Kovalik
Today at 4:02:04 PM
4:02 PM
да
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:02:21 PM
4:02
звъни направо
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
20 results
Channel...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.011805556,"top":0.08111111,"width":0.025,"height":0.04},"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.00625,"top":0.14,"width":0.036111113,"height":0.075555556},"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.013888889,"top":0.19222222,"width":0.020833334,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.00625,"top":0.21555555,"width":0.036111113,"height":0.075555556},"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.015972223,"top":0.26777777,"width":0.016666668,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.00625,"top":0.2911111,"width":0.036111113,"height":0.075555556},"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.011111111,"top":0.34333333,"width":0.027083334,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.011111111,"top":0.34333333,"width":0.0055555557,"height":0.015555556}},{"char_start":1,"char_count":7,"bounds":{"left":0.015972223,"top":0.34333333,"width":0.022222223,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.00625,"top":0.36666667,"width":0.036111113,"height":0.075555556},"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.016666668,"top":0.4188889,"width":0.015972223,"height":0.015555556},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.016666668,"top":0.4188889,"width":0.004166667,"height":0.015555556}},{"char_start":1,"char_count":4,"bounds":{"left":0.020833334,"top":0.4188889,"width":0.011805556,"height":0.015555556}}],"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.00625,"top":0.4422222,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.49444443,"width":0.018055556,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.00625,"top":0.5177778,"width":0.036111113,"height":0.075555556},"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.015277778,"top":0.57,"width":0.01875,"height":0.015555556},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.039583333,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.036805555,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.06111111,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.18472221,"top":0.12777779,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.077083334,"top":0.12777779,"width":0.050694443,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.09166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.093055554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.046527777,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.025694445,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.038194444,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.022222223,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.072222225,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.057638887,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.054166667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.088194445,"top":0.12777779,"width":0.034027778,"height":0.007777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.088194445,"top":0.14666666,"width":0.048611112,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.072916664,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.17777778,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":15,"bounds":{"left":0.094444446,"top":0.17777778,"width":0.06666667,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.088194445,"top":0.20888889,"width":0.08055556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.088194445,"top":0.24,"width":0.035416666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.088194445,"top":0.2711111,"width":0.036805555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.05138889,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.30222222,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":11,"bounds":{"left":0.093055554,"top":0.30222222,"width":0.045833334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.088194445,"top":0.33333334,"width":0.036111113,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.088194445,"top":0.36444443,"width":0.05138889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.094444446,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.39555556,"width":0.004166667,"height":0.02}},{"char_start":1,"char_count":20,"bounds":{"left":0.09236111,"top":0.39555556,"width":0.09861111,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.088194445,"top":0.46888888,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.088194445,"top":0.5,"width":0.055555556,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.088194445,"top":0.5,"width":0.00625,"height":0.02}},{"char_start":1,"char_count":12,"bounds":{"left":0.094444446,"top":0.5,"width":0.048611112,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.088194445,"top":0.5311111,"width":0.07361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.088194445,"top":0.56222224,"width":0.079166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"bounds":{"left":0.088194445,"top":0.5933333,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.6244444,"width":0.07152778,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"bounds":{"left":0.088194445,"top":0.65555555,"width":0.06736111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"bounds":{"left":0.088194445,"top":0.68666667,"width":0.06666667,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"bounds":{"left":0.088194445,"top":0.7177778,"width":0.060416665,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"bounds":{"left":0.088194445,"top":0.7488889,"width":0.07986111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"bounds":{"left":0.088194445,"top":0.78,"width":0.072222225,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.088194445,"top":0.8111111,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"bounds":{"left":0.15555556,"top":0.8111111,"width":0.013194445,"height":0.02},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.15555556,"top":0.8111111,"width":0.0048611113,"height":0.02}},{"char_start":1,"char_count":2,"bounds":{"left":0.16041666,"top":0.8111111,"width":0.011805556,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.088194445,"top":0.8844444,"width":0.025694445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.088194445,"top":0.91555554,"width":0.045833334,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.21319444,"top":0.12777779,"width":0.06458333,"height":0.04222222},"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.2326389,"top":0.14,"width":0.039583333,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.27986112,"top":0.12777779,"width":0.07152778,"height":0.04222222},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"bounds":{"left":0.29930556,"top":0.14,"width":0.046527777,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.35347223,"top":0.12777779,"width":0.04375,"height":0.04222222},"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.37291667,"top":0.14,"width":0.01875,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.37291667,"top":0.14,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":4,"bounds":{"left":0.3784722,"top":0.14,"width":0.013194445,"height":0.017777778}}],"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.4,"top":0.12777779,"width":0.022222223,"height":0.04222222},"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":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5465278,"top":0.16111112,"width":0.10555556,"height":0.0011111111},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:16:54 PM","depth":23,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:16 PM","depth":24,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами ще го деплойна но ако нещо гръмне","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.19791667,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.08125,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:04 PM","depth":23,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17 PM","depth":24,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"аа разбрахте","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.061805554,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:17:07 PM","depth":24,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:17","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:14 PM","depth":24,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Галя каза че не се използва фичъра","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.16875,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 28th at 5:21:22 PM","depth":24,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"5:21","depth":25,"bounds":{"left":0.22430556,"top":0.16111112,"width":0.016666668,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"и няма проблем да гръмне","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.12916666,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5472222,"top":0.16111112,"width":0.104166664,"height":0.028888889},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.08125,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:24:41 PM","depth":23,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:24 PM","depth":24,"bounds":{"left":0.33333334,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш за Hubspot за синковете вече се използва тази команда нали?","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.3326389,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"crm:sync-hubspot-objects","depth":25,"bounds":{"left":0.24930556,"top":0.16111112,"width":0.12013889,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.06458333,"height":0.0011111111},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.16111112,"width":0.0055555557,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"May 11th at 1:32:50 PM","depth":23,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:32 PM","depth":24,"bounds":{"left":0.31666666,"top":0.16111112,"width":0.03125,"height":0.0011111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"да крон я пуска през 5 мин","depth":24,"bounds":{"left":0.24652778,"top":0.16111112,"width":0.12986112,"height":0.012222222},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"bounds":{"left":0.5729167,"top":0.19555555,"width":0.05277778,"height":0.031111112},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.23888889,"width":0.08125,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.24111111,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:30:26 PM","depth":23,"bounds":{"left":0.33333334,"top":0.24444444,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30 PM","depth":24,"bounds":{"left":0.33333334,"top":0.24444444,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?","depth":24,"bounds":{"left":0.24652778,"top":0.26555556,"width":0.5069444,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:30:45 PM","depth":24,"bounds":{"left":0.22430556,"top":0.30222222,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:30","depth":25,"bounds":{"left":0.22430556,"top":0.30222222,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"при останалите CRMi трябва ръчно да се въведат","depth":24,"bounds":{"left":0.24652778,"top":0.2988889,"width":0.24166666,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.33,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.33222222,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 2:47:56 PM","depth":23,"bounds":{"left":0.31666666,"top":0.33555555,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:47 PM","depth":24,"bounds":{"left":0.31666666,"top":0.33555555,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти","depth":24,"bounds":{"left":0.24652778,"top":0.35666665,"width":0.03888889,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:48:14 PM","depth":24,"bounds":{"left":0.22430556,"top":0.39333335,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:48","depth":25,"bounds":{"left":0.22430556,"top":0.39333335,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ами не знам по принцип се вика при всички","depth":24,"bounds":{"left":0.24652778,"top":0.39,"width":0.21111111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:51:36 PM","depth":24,"bounds":{"left":0.22430556,"top":0.42666668,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:51","depth":25,"bounds":{"left":0.22430556,"top":0.42666668,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"трябва да се за всички, някъде не се ли попълва","depth":24,"bounds":{"left":0.24652778,"top":0.42333335,"width":0.2326389,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 2:52:10 PM","depth":24,"bounds":{"left":0.22430556,"top":0.46,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2:52","depth":25,"bounds":{"left":0.22430556,"top":0.46,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"при зохо май беше hardcoded но май и там си връщаха две категории","depth":24,"bounds":{"left":0.24652778,"top":0.45666668,"width":0.3361111,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.24652778,"top":0.48777777,"width":0.08125,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.32777777,"top":0.49,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:00:37 PM","depth":23,"bounds":{"left":0.33333334,"top":0.49333334,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:00 PM","depth":24,"bounds":{"left":0.33333334,"top":0.49333334,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш имаш ли време да се чуем за тестването на","depth":24,"bounds":{"left":0.24652778,"top":0.5144445,"width":0.24722221,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://jiminny.atlassian.net/browse/JY-20725","depth":24,"bounds":{"left":0.49305555,"top":0.5144445,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://jiminny.atlassian.net/browse/JY-20725","depth":25,"bounds":{"left":0.49305555,"top":0.5144445,"width":0.21180555,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.24652778,"top":0.5466667,"width":0.039583333,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.24652778,"top":0.5466667,"width":0.004166667,"height":0.017777778}},{"char_start":1,"char_count":9,"bounds":{"left":0.25069445,"top":0.5466667,"width":0.035416666,"height":0.017777778}}],"role_description":"text"},{"role":"AXButton","text":"Jira Cloud","depth":23,"bounds":{"left":0.2888889,"top":0.5466667,"width":0.011111111,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise","depth":25,"bounds":{"left":0.24652778,"top":0.57,"width":0.33333334,"height":0.19111112},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts","depth":26,"bounds":{"left":0.2888889,"top":0.5888889,"width":0.28055555,"height":0.04},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.2888889,"top":0.5888889,"width":0.0034722222,"height":0.02}},{"char_start":1,"char_count":68,"bounds":{"left":0.2888889,"top":0.5888889,"width":0.27708334,"height":0.02}}],"role_description":"text"},{"role":"AXStaticText","text":"Bug JY-20725 in Jira Cloud","depth":27,"bounds":{"left":0.2888889,"top":0.6111111,"width":0.108333334,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Preview in Slack","depth":27,"bounds":{"left":0.2888889,"top":0.6111111,"width":0.06527778,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Status","depth":26,"bounds":{"left":0.2888889,"top":0.6433333,"width":0.025,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ready for QA","depth":26,"bounds":{"left":0.29166666,"top":0.67,"width":0.061805554,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Priority","depth":26,"bounds":{"left":0.37222221,"top":0.6433333,"width":0.029861111,"height":0.017777778},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.37222221,"top":0.6433333,"width":0.0055555557,"height":0.017777778}},{"char_start":1,"char_count":7,"bounds":{"left":0.37777779,"top":0.6433333,"width":0.024305556,"height":0.017777778}}],"role_description":"text"},{"role":"AXStaticText","text":"Medium","depth":26,"bounds":{"left":0.3888889,"top":0.67,"width":0.038194444,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Assignee","depth":26,"bounds":{"left":0.44652778,"top":0.6433333,"width":0.035416666,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":26,"bounds":{"left":0.46319443,"top":0.67,"width":0.07847222,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"As of today at 4:00 PM","depth":27,"bounds":{"left":0.25555557,"top":0.7266667,"width":0.09166667,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Refresh","depth":27,"bounds":{"left":0.34930557,"top":0.7311111,"width":0.030555556,"height":0.008888889},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open in Jira","depth":27,"bounds":{"left":0.43333334,"top":0.72,"width":0.06458333,"height":0.031111112},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"✨ Summarise","depth":27,"bounds":{"left":0.5,"top":0.72,"width":0.07361111,"height":0.031111112},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Open in browser","depth":26,"bounds":{"left":0.44791666,"top":0.5888889,"width":0.047222223,"height":0.035555556},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Open","depth":27,"bounds":{"left":0.46736112,"top":0.5977778,"width":0.022222223,"height":0.017777778},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Share Bug JY-20725","depth":26,"bounds":{"left":0.5013889,"top":0.5888889,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View conversations","depth":26,"bounds":{"left":0.5236111,"top":0.5888889,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More actions","depth":26,"bounds":{"left":0.54583335,"top":0.5888889,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"bounds":{"left":0.8041667,"top":0.47,"width":0.022222223,"height":0.035555556},"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":25,"bounds":{"left":0.8263889,"top":0.47,"width":0.022222223,"height":0.035555556},"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":25,"bounds":{"left":0.8486111,"top":0.47,"width":0.022222223,"height":0.035555556},"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":25,"bounds":{"left":0.87083334,"top":0.47,"width":0.022222223,"height":0.035555556},"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":25,"bounds":{"left":0.89305556,"top":0.47,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"bounds":{"left":0.9152778,"top":0.47,"width":0.022222223,"height":0.035555556},"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":25,"bounds":{"left":0.9375,"top":0.47,"width":0.022222223,"height":0.035555556},"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":25,"bounds":{"left":0.9597222,"top":0.47,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"bounds":{"left":0.24652778,"top":0.77444446,"width":0.06458333,"height":0.024444444},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.31111112,"top":0.77666664,"width":0.0055555557,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 4:02:04 PM","depth":23,"bounds":{"left":0.31666666,"top":0.78,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:02 PM","depth":24,"bounds":{"left":0.31666666,"top":0.78,"width":0.03125,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"да","depth":24,"bounds":{"left":0.24652778,"top":0.8011111,"width":0.011805556,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 4:02:21 PM","depth":24,"bounds":{"left":0.22430556,"top":0.8377778,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4:02","depth":25,"bounds":{"left":0.22430556,"top":0.8377778,"width":0.016666668,"height":0.016666668},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"звъни направо","depth":24,"bounds":{"left":0.24652778,"top":0.83444446,"width":0.06944445,"height":0.02},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":false,"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":25,"on_screen":false,"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":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"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.21666667,"top":0.88,"width":0.7652778,"height":0.04222222},"on_screen":true,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"20 results","depth":11,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Channel","depth":11,"on_screen":false,"role_description":"text"}]...
|
-8280000885004039981
|
-1712681130233902764
|
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
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
Vasil Vasilev
Galya Dimitrova
Stefka Stoyanova
Todor Stamatov
Mario Georgiev
Nikolay Ivanov
James Graham
Stoyan Tanev
Steliyan Georgiev
Petko Kashinski
Lukas Kovalik
you
Toast
Jira Cloud
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Apr 28th at 5:16:54 PM
5:16 PM
ами ще го деплойна но ако нещо гръмне
Aneliya Angelova
Apr 28th at 5:17:04 PM
5:17 PM
аа разбрахте
Apr 28th at 5:17:07 PM
5:17
Apr 28th at 5:21:14 PM
5:21
Галя каза че не се използва фичъра
Apr 28th at 5:21:22 PM
5:21
и няма проблем да гръмне
Jump to date
Aneliya Angelova
May 11th at 1:24:41 PM
1:24 PM
Лукаш за Hubspot за синковете вече се използва тази команда нали?
crm:sync-hubspot-objects
Lukas Kovalik
May 11th at 1:32:50 PM
1:32 PM
да крон я пуска през 5 мин
Jump to date
Aneliya Angelova
Today at 2:30:26 PM
2:30 PM
Лукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:30:45 PM
2:30
при останалите CRMi трябва ръчно да се въведат
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 2:47:56 PM
2:47 PM
здрасти
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:48:14 PM
2:48
ами не знам по принцип се вика при всички
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:51:36 PM
2:51
трябва да се за всички, някъде не се ли попълва
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 2:52:10 PM
2:52
при зохо май беше hardcoded но май и там си връщаха две категории
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Aneliya Angelova
Today at 4:00:37 PM
4:00 PM
Лукаш имаш ли време да се чуем за тестването на
https://jiminny.atlassian.net/browse/JY-20725
https://jiminny.atlassian.net/browse/JY-20725
Jira Cloud
Jira Cloud
Jira Cloud Bug JY-20725 [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts Bug JY-20725 in Jira Cloud Preview in Slack Status Ready for QA Priority Medium Medium Assignee Aneliya Angelova Aneliya Angelova As of today at 4:00 PM Refresh Open in Jira ✨ Summarise
[HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts
Bug JY-20725 in Jira Cloud
Preview in Slack
Status
Ready for QA
Priority
Medium
Assignee
Aneliya Angelova
As of today at 4:00 PM
Refresh
Open in Jira
✨ Summarise
Open in browser
Open
Share Bug JY-20725
View conversations
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
Lukas Kovalik
Today at 4:02:04 PM
4:02 PM
да
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 4:02:21 PM
4:02
звъни направо
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
20 results
Channel
HomeDMsActivityFilesLater..•MoreSlackFileEditViewEDJiminny ...scnicre.# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of _jimi...Direct messages8. Aneliya Angelova€. Vasil Vasil.... Galya Dimitrova&. Stefka Stoyanova: Todor StamatovMario GeorgievNikolay IvanovLo James Graham8 Stoyan TanevSteliyan GeorgievPetko KashinskiLukas Kovalik y...AppsToastJira CloudGoHistoryWindowHelpQDescribe what you are looking forAneliya AngelovaMessagest Add canvas@ Files+hhl100% C8• Thu 14 May 16:02:49Monday, May 11th ~Today ~Aneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?при останалите CRMi трябва ръчно да се въведатLukas Kovalik 2:47 PMздрастиами не знам по принцип се вика при всичкитрябва да се за всички, някъде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725Jira CloudX Bug IV-20725 in Jira Cloud[HubSpot] Optimise CRM rematching on delete hubspot ac...StatusReady for QAPriority= MediumAssigneeAA Aneliya AngelovaAs of today at 4:00 PMOpen in Jirait SummariseLukas Kovalik 4:02 PMдазвьни направоMessage Aneliya Angelova99+Shift + Return to add a new line...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43623
|
1592
|
0
|
2026-05-14T13:02:54.433021+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763774433_m2.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pushed 1 commit to origin/JY-20903-update_activity Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change
text/html
text/html
text/html
View pull request
1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Activities;
use Illuminate\Support\Facades\Validator;
use Jiminny\Console\Commands\Command;
use Jiminny\Jobs\Crm\MatchActivityCrmData;
use Jiminny\Models\Activity;
use Jiminny\Models\Team;
use Symfony\Component\Console\Command\Command as CommandAlias;
class ActivitiesMatchCrmCommand extends Command
{
protected $signature = 'activity:match-crm
{--teamId=}
{--from=}
{--to=}
{--activityId=}
{--matchFromOtherCrm}
{--remoteSearch}
{--sync}
';
public function handle(): int
{
$teamId = $this->option('teamId');
$from = $this->option('from');
$to = $this->option('to');
$matchFromOtherCrm = $this->option('matchFromOtherCrm');
$remoteSearch = $this->option('remoteSearch');
$activityId = $this->option('activityId');
$validator = Validator::make(
[
'teamId' => $teamId,
'from' => $from,
'to' => $to,
'matchFromOtherCrm' => $matchFromOtherCrm,
'activityId' => $activityId,
'remoteSearch' => $remoteSearch,
],
[
'teamId' => ['required_without:activityId', 'numeric', 'nullable'],
'from' => ['required_without:activityId', 'date', 'nullable'],
'to' => ['required_without:activityId', 'date', 'nullable'],
'matchFromOtherCrm' => ['required', 'boolean'],
'remoteSearch' => ['required', 'boolean'],
'activityId' => ['numeric', 'nullable'],
]
);
if ($validator->fails()) {
$this->error('Validation failed:');
$this->output->block($validator->errors()->all());
return CommandAlias::FAILURE;
}
if ($activityId) {
$activity = Activity::find((int) $activityId);
if ($activity === null) {
$this->error('Cannot find activity.');
return CommandAlias::FAILURE;
}
$team = $activity->getTeam();
$this->info($activity->getTitle() . ' found.');
$activityIds = [$activity->getId()];
} else {
$team = Team::find($teamId);
if ($team === null) {
$this->error('Cannot find team.');
return CommandAlias::FAILURE;
}
$this->info($team->getName() . ' | matching activities from ' . $from . ' to ' . $to);
$activities = Activity::select('activities.id')
->join('users', 'activities.user_id', '=', 'users.id')
->where('users.team_id', '=', $team->getId())
->whereBetween('activities.created_at', [$from, $to]);
if ($matchFromOtherCrm) {
$activities->where('activities.crm_configuration_id', '!=', $team->getCrmConfigurationId());
}
$activityIds = $activities->pluck('id');
$this->info('Found activities: ' . $activityIds->count());
}
if (! $this->confirm('Do you want to continue?')) {
die();
}
foreach ($activityIds as $activityId) {
$this->dispatch(
new MatchActivityCrmData(
activityId: (int) $activityId,
fromConfiguration: $matchFromOtherCrm ? $team->getCrmConfiguration() : null,
remoteSearch: $remoteSearch,
)
);
}
return CommandAlias::SUCCESS;
}
}...
|
[{"role":"AXTextField","text [{"role":"AXTextField","text":"Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change","depth":3,"bounds":{"left":0.8753325,"top":0.82521945,"width":0.11037234,"height":0.040702313},"on_screen":true,"value":"Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.82521945,"width":0.10305851,"height":0.040702313},"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"View pull request","depth":2,"bounds":{"left":0.8753325,"top":0.87150836,"width":0.03523936,"height":0.013567438},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1 file committed","depth":2,"bounds":{"left":0.8753325,"top":0.91300875,"width":0.100398935,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20903 revert changes in command","depth":3,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.11037234,"height":0.013567438},"on_screen":true,"value":"JY-20903 revert changes in command","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.0787899,"height":0.013567438},"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"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":"#12077 on JY-20903-update_activity-stage-on…hange, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12566489,"height":0.025538707},"on_screen":true,"help_text":"Pull request #12077 exists for current branch JY-20903-update__activity-stage-on…hange","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":"4","depth":4,"bounds":{"left":0.38397607,"top":0.12529927,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.39361703,"top":0.123703115,"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.40093085,"top":0.123703115,"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\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Jobs\\Crm\\MatchActivityCrmData;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Team;\nuse Symfony\\Component\\Console\\Command\\Command as CommandAlias;\n\nclass ActivitiesMatchCrmCommand extends Command\n{\n protected $signature = 'activity:match-crm\n {--teamId=}\n {--from=}\n {--to=}\n {--activityId=}\n {--matchFromOtherCrm}\n {--remoteSearch}\n {--sync}\n ';\n\n public function handle(): int\n {\n $teamId = $this->option('teamId');\n $from = $this->option('from');\n $to = $this->option('to');\n $matchFromOtherCrm = $this->option('matchFromOtherCrm');\n $remoteSearch = $this->option('remoteSearch');\n $activityId = $this->option('activityId');\n\n $validator = Validator::make(\n [\n 'teamId' => $teamId,\n 'from' => $from,\n 'to' => $to,\n 'matchFromOtherCrm' => $matchFromOtherCrm,\n 'activityId' => $activityId,\n 'remoteSearch' => $remoteSearch,\n ],\n [\n 'teamId' => ['required_without:activityId', 'numeric', 'nullable'],\n 'from' => ['required_without:activityId', 'date', 'nullable'],\n 'to' => ['required_without:activityId', 'date', 'nullable'],\n 'matchFromOtherCrm' => ['required', 'boolean'],\n 'remoteSearch' => ['required', 'boolean'],\n 'activityId' => ['numeric', 'nullable'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return CommandAlias::FAILURE;\n }\n\n if ($activityId) {\n $activity = Activity::find((int) $activityId);\n if ($activity === null) {\n $this->error('Cannot find activity.');\n\n return CommandAlias::FAILURE;\n }\n $team = $activity->getTeam();\n $this->info($activity->getTitle() . ' found.');\n\n $activityIds = [$activity->getId()];\n } else {\n $team = Team::find($teamId);\n if ($team === null) {\n $this->error('Cannot find team.');\n\n return CommandAlias::FAILURE;\n }\n\n $this->info($team->getName() . ' | matching activities from ' . $from . ' to ' . $to);\n\n $activities = Activity::select('activities.id')\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->where('users.team_id', '=', $team->getId())\n ->whereBetween('activities.created_at', [$from, $to]);\n if ($matchFromOtherCrm) {\n $activities->where('activities.crm_configuration_id', '!=', $team->getCrmConfigurationId());\n }\n\n $activityIds = $activities->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n }\n\n if (! $this->confirm('Do you want to continue?')) {\n die();\n }\n\n foreach ($activityIds as $activityId) {\n $this->dispatch(\n new MatchActivityCrmData(\n activityId: (int) $activityId,\n fromConfiguration: $matchFromOtherCrm ? $team->getCrmConfiguration() : null,\n remoteSearch: $remoteSearch,\n )\n );\n }\n\n return CommandAlias::SUCCESS;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Jobs\\Crm\\MatchActivityCrmData;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Team;\nuse Symfony\\Component\\Console\\Command\\Command as CommandAlias;\n\nclass ActivitiesMatchCrmCommand extends Command\n{\n protected $signature = 'activity:match-crm\n {--teamId=}\n {--from=}\n {--to=}\n {--activityId=}\n {--matchFromOtherCrm}\n {--remoteSearch}\n {--sync}\n ';\n\n public function handle(): int\n {\n $teamId = $this->option('teamId');\n $from = $this->option('from');\n $to = $this->option('to');\n $matchFromOtherCrm = $this->option('matchFromOtherCrm');\n $remoteSearch = $this->option('remoteSearch');\n $activityId = $this->option('activityId');\n\n $validator = Validator::make(\n [\n 'teamId' => $teamId,\n 'from' => $from,\n 'to' => $to,\n 'matchFromOtherCrm' => $matchFromOtherCrm,\n 'activityId' => $activityId,\n 'remoteSearch' => $remoteSearch,\n ],\n [\n 'teamId' => ['required_without:activityId', 'numeric', 'nullable'],\n 'from' => ['required_without:activityId', 'date', 'nullable'],\n 'to' => ['required_without:activityId', 'date', 'nullable'],\n 'matchFromOtherCrm' => ['required', 'boolean'],\n 'remoteSearch' => ['required', 'boolean'],\n 'activityId' => ['numeric', 'nullable'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return CommandAlias::FAILURE;\n }\n\n if ($activityId) {\n $activity = Activity::find((int) $activityId);\n if ($activity === null) {\n $this->error('Cannot find activity.');\n\n return CommandAlias::FAILURE;\n }\n $team = $activity->getTeam();\n $this->info($activity->getTitle() . ' found.');\n\n $activityIds = [$activity->getId()];\n } else {\n $team = Team::find($teamId);\n if ($team === null) {\n $this->error('Cannot find team.');\n\n return CommandAlias::FAILURE;\n }\n\n $this->info($team->getName() . ' | matching activities from ' . $from . ' to ' . $to);\n\n $activities = Activity::select('activities.id')\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->where('users.team_id', '=', $team->getId())\n ->whereBetween('activities.created_at', [$from, $to]);\n if ($matchFromOtherCrm) {\n $activities->where('activities.crm_configuration_id', '!=', $team->getCrmConfigurationId());\n }\n\n $activityIds = $activities->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n }\n\n if (! $this->confirm('Do you want to continue?')) {\n die();\n }\n\n foreach ($activityIds as $activityId) {\n $this->dispatch(\n new MatchActivityCrmData(\n activityId: (int) $activityId,\n fromConfiguration: $matchFromOtherCrm ? $team->getCrmConfiguration() : null,\n remoteSearch: $remoteSearch,\n )\n );\n }\n\n return CommandAlias::SUCCESS;\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4862553758757229573
|
-8740216929708701628
|
visual_change
|
accessibility
|
NULL
|
Pushed 1 commit to origin/JY-20903-update_activity Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change
text/html
text/html
text/html
View pull request
1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Activities;
use Illuminate\Support\Facades\Validator;
use Jiminny\Console\Commands\Command;
use Jiminny\Jobs\Crm\MatchActivityCrmData;
use Jiminny\Models\Activity;
use Jiminny\Models\Team;
use Symfony\Component\Console\Command\Command as CommandAlias;
class ActivitiesMatchCrmCommand extends Command
{
protected $signature = 'activity:match-crm
{--teamId=}
{--from=}
{--to=}
{--activityId=}
{--matchFromOtherCrm}
{--remoteSearch}
{--sync}
';
public function handle(): int
{
$teamId = $this->option('teamId');
$from = $this->option('from');
$to = $this->option('to');
$matchFromOtherCrm = $this->option('matchFromOtherCrm');
$remoteSearch = $this->option('remoteSearch');
$activityId = $this->option('activityId');
$validator = Validator::make(
[
'teamId' => $teamId,
'from' => $from,
'to' => $to,
'matchFromOtherCrm' => $matchFromOtherCrm,
'activityId' => $activityId,
'remoteSearch' => $remoteSearch,
],
[
'teamId' => ['required_without:activityId', 'numeric', 'nullable'],
'from' => ['required_without:activityId', 'date', 'nullable'],
'to' => ['required_without:activityId', 'date', 'nullable'],
'matchFromOtherCrm' => ['required', 'boolean'],
'remoteSearch' => ['required', 'boolean'],
'activityId' => ['numeric', 'nullable'],
]
);
if ($validator->fails()) {
$this->error('Validation failed:');
$this->output->block($validator->errors()->all());
return CommandAlias::FAILURE;
}
if ($activityId) {
$activity = Activity::find((int) $activityId);
if ($activity === null) {
$this->error('Cannot find activity.');
return CommandAlias::FAILURE;
}
$team = $activity->getTeam();
$this->info($activity->getTitle() . ' found.');
$activityIds = [$activity->getId()];
} else {
$team = Team::find($teamId);
if ($team === null) {
$this->error('Cannot find team.');
return CommandAlias::FAILURE;
}
$this->info($team->getName() . ' | matching activities from ' . $from . ' to ' . $to);
$activities = Activity::select('activities.id')
->join('users', 'activities.user_id', '=', 'users.id')
->where('users.team_id', '=', $team->getId())
->whereBetween('activities.created_at', [$from, $to]);
if ($matchFromOtherCrm) {
$activities->where('activities.crm_configuration_id', '!=', $team->getCrmConfigurationId());
}
$activityIds = $activities->pluck('id');
$this->info('Found activities: ' . $activityIds->count());
}
if (! $this->confirm('Do you want to continue?')) {
die();
}
foreach ($activityIds as $activityId) {
$this->dispatch(
new MatchActivityCrmData(
activityId: (int) $activityId,
fromConfiguration: $matchFromOtherCrm ? $team->getCrmConfiguration() : null,
remoteSearch: $remoteSearch,
)
);
}
return CommandAlias::SUCCESS;
}
}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43622
|
1591
|
1
|
2026-05-14T13:02:54.550346+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763774550_m1.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Pushed 1 commit to origin/JY-20903-update_activity Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change
text/html
text/html
text/html
View pull request
1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
4
Previous Highlighted Error
Next Highlighted Error...
|
[{"role":"AXTextField","text [{"role":"AXTextField","text":"Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change","depth":3,"on_screen":true,"value":"Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"View pull request","depth":2,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1 file committed","depth":2,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20903 revert changes in command","depth":3,"on_screen":true,"value":"JY-20903 revert changes in command","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"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":"#12077 on JY-20903-update_activity-stage-on…hange, menu","depth":5,"on_screen":true,"help_text":"Pull request #12077 exists for current branch JY-20903-update__activity-stage-on…hange","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":"4","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}]...
|
2164930852212324331
|
-7082874502008207034
|
app_switch
|
accessibility
|
NULL
|
Pushed 1 commit to origin/JY-20903-update_activity Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change
text/html
text/html
text/html
View pull request
1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
4
Previous Highlighted Error
Next Highlighted Error...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43624
|
1591
|
2
|
2026-05-14T13:02:56.482089+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763776482_m1.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Pushed 1 commit to origin/JY-20903-update_activity Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change
text/html
text/html
text/html
View pull request
1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Activities;
use Illuminate\Support\Facades\Validator;
use Jiminny\Console\Commands\Command;
use Jiminny\Jobs\Crm\MatchActivityCrmData;
use Jiminny\Models\Activity;
use Jiminny\Models\Team;
use Symfony\Component\Console\Command\Command as CommandAlias;
class ActivitiesMatchCrmCommand extends Command
{
protected $signature = 'activity:match-crm
{--teamId=}
{--from=}
{--to=}
{--activityId=}
{--matchFromOtherCrm}
{--remoteSearch}
{--sync}
';
public function handle(): int
{
$teamId = $this->option('teamId');
$from = $this->option('from');
$to = $this->option('to');
$matchFromOtherCrm = $this->option('matchFromOtherCrm');
$remoteSearch = $this->option('remoteSearch');
$activityId = $this->option('activityId');
$validator = Validator::make(
[
'teamId' => $teamId,
'from' => $from,
'to' => $to,
'matchFromOtherCrm' => $matchFromOtherCrm,
'activityId' => $activityId,
'remoteSearch' => $remoteSearch,
],
[
'teamId' => ['required_without:activityId', 'numeric', 'nullable'],
'from' => ['required_without:activityId', 'date', 'nullable'],
'to' => ['required_without:activityId', 'date', 'nullable'],
'matchFromOtherCrm' => ['required', 'boolean'],
'remoteSearch' => ['required', 'boolean'],
'activityId' => ['numeric', 'nullable'],
]
);
if ($validator->fails()) {
$this->error('Validation failed:');
$this->output->block($validator->errors()->all());
return CommandAlias::FAILURE;
}
if ($activityId) {
$activity = Activity::find((int) $activityId);
if ($activity === null) {
$this->error('Cannot find activity.');
return CommandAlias::FAILURE;
}
$team = $activity->getTeam();
$this->info($activity->getTitle() . ' found.');
$activityIds = [$activity->getId()];
} else {
$team = Team::find($teamId);
if ($team === null) {
$this->error('Cannot find team.');
return CommandAlias::FAILURE;
}
$this->info($team->getName() . ' | matching activities from ' . $from . ' to ' . $to);
$activities = Activity::select('activities.id')
->join('users', 'activities.user_id', '=', 'users.id')
->where('users.team_id', '=', $team->getId())
->whereBetween('activities.created_at', [$from, $to]);
if ($matchFromOtherCrm) {
$activities->where('activities.crm_configuration_id', '!=', $team->getCrmConfigurationId());
}
$activityIds = $activities->pluck('id');
$this->info('Found activities: ' . $activityIds->count());
}
if (! $this->confirm('Do you want to continue?')) {
die();
}
foreach ($activityIds as $activityId) {
$this->dispatch(
new MatchActivityCrmData(
activityId: (int) $activityId,
fromConfiguration: $matchFromOtherCrm ? $team->getCrmConfiguration() : null,
remoteSearch: $remoteSearch,
)
);
}
return CommandAlias::SUCCESS;
}
}
Sync Changes
Hide This Notification...
|
[{"role":"AXTextField","text [{"role":"AXTextField","text":"Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change","depth":3,"on_screen":true,"value":"Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"View pull request","depth":2,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1 file committed","depth":2,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20903 revert changes in command","depth":3,"on_screen":true,"value":"JY-20903 revert changes in command","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"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":"#12077 on JY-20903-update_activity-stage-on…hange, menu","depth":5,"on_screen":true,"help_text":"Pull request #12077 exists for current branch JY-20903-update__activity-stage-on…hange","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":"4","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\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Jobs\\Crm\\MatchActivityCrmData;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Team;\nuse Symfony\\Component\\Console\\Command\\Command as CommandAlias;\n\nclass ActivitiesMatchCrmCommand extends Command\n{\n protected $signature = 'activity:match-crm\n {--teamId=}\n {--from=}\n {--to=}\n {--activityId=}\n {--matchFromOtherCrm}\n {--remoteSearch}\n {--sync}\n ';\n\n public function handle(): int\n {\n $teamId = $this->option('teamId');\n $from = $this->option('from');\n $to = $this->option('to');\n $matchFromOtherCrm = $this->option('matchFromOtherCrm');\n $remoteSearch = $this->option('remoteSearch');\n $activityId = $this->option('activityId');\n\n $validator = Validator::make(\n [\n 'teamId' => $teamId,\n 'from' => $from,\n 'to' => $to,\n 'matchFromOtherCrm' => $matchFromOtherCrm,\n 'activityId' => $activityId,\n 'remoteSearch' => $remoteSearch,\n ],\n [\n 'teamId' => ['required_without:activityId', 'numeric', 'nullable'],\n 'from' => ['required_without:activityId', 'date', 'nullable'],\n 'to' => ['required_without:activityId', 'date', 'nullable'],\n 'matchFromOtherCrm' => ['required', 'boolean'],\n 'remoteSearch' => ['required', 'boolean'],\n 'activityId' => ['numeric', 'nullable'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return CommandAlias::FAILURE;\n }\n\n if ($activityId) {\n $activity = Activity::find((int) $activityId);\n if ($activity === null) {\n $this->error('Cannot find activity.');\n\n return CommandAlias::FAILURE;\n }\n $team = $activity->getTeam();\n $this->info($activity->getTitle() . ' found.');\n\n $activityIds = [$activity->getId()];\n } else {\n $team = Team::find($teamId);\n if ($team === null) {\n $this->error('Cannot find team.');\n\n return CommandAlias::FAILURE;\n }\n\n $this->info($team->getName() . ' | matching activities from ' . $from . ' to ' . $to);\n\n $activities = Activity::select('activities.id')\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->where('users.team_id', '=', $team->getId())\n ->whereBetween('activities.created_at', [$from, $to]);\n if ($matchFromOtherCrm) {\n $activities->where('activities.crm_configuration_id', '!=', $team->getCrmConfigurationId());\n }\n\n $activityIds = $activities->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n }\n\n if (! $this->confirm('Do you want to continue?')) {\n die();\n }\n\n foreach ($activityIds as $activityId) {\n $this->dispatch(\n new MatchActivityCrmData(\n activityId: (int) $activityId,\n fromConfiguration: $matchFromOtherCrm ? $team->getCrmConfiguration() : null,\n remoteSearch: $remoteSearch,\n )\n );\n }\n\n return CommandAlias::SUCCESS;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Jobs\\Crm\\MatchActivityCrmData;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Team;\nuse Symfony\\Component\\Console\\Command\\Command as CommandAlias;\n\nclass ActivitiesMatchCrmCommand extends Command\n{\n protected $signature = 'activity:match-crm\n {--teamId=}\n {--from=}\n {--to=}\n {--activityId=}\n {--matchFromOtherCrm}\n {--remoteSearch}\n {--sync}\n ';\n\n public function handle(): int\n {\n $teamId = $this->option('teamId');\n $from = $this->option('from');\n $to = $this->option('to');\n $matchFromOtherCrm = $this->option('matchFromOtherCrm');\n $remoteSearch = $this->option('remoteSearch');\n $activityId = $this->option('activityId');\n\n $validator = Validator::make(\n [\n 'teamId' => $teamId,\n 'from' => $from,\n 'to' => $to,\n 'matchFromOtherCrm' => $matchFromOtherCrm,\n 'activityId' => $activityId,\n 'remoteSearch' => $remoteSearch,\n ],\n [\n 'teamId' => ['required_without:activityId', 'numeric', 'nullable'],\n 'from' => ['required_without:activityId', 'date', 'nullable'],\n 'to' => ['required_without:activityId', 'date', 'nullable'],\n 'matchFromOtherCrm' => ['required', 'boolean'],\n 'remoteSearch' => ['required', 'boolean'],\n 'activityId' => ['numeric', 'nullable'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return CommandAlias::FAILURE;\n }\n\n if ($activityId) {\n $activity = Activity::find((int) $activityId);\n if ($activity === null) {\n $this->error('Cannot find activity.');\n\n return CommandAlias::FAILURE;\n }\n $team = $activity->getTeam();\n $this->info($activity->getTitle() . ' found.');\n\n $activityIds = [$activity->getId()];\n } else {\n $team = Team::find($teamId);\n if ($team === null) {\n $this->error('Cannot find team.');\n\n return CommandAlias::FAILURE;\n }\n\n $this->info($team->getName() . ' | matching activities from ' . $from . ' to ' . $to);\n\n $activities = Activity::select('activities.id')\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->where('users.team_id', '=', $team->getId())\n ->whereBetween('activities.created_at', [$from, $to]);\n if ($matchFromOtherCrm) {\n $activities->where('activities.crm_configuration_id', '!=', $team->getCrmConfigurationId());\n }\n\n $activityIds = $activities->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n }\n\n if (! $this->confirm('Do you want to continue?')) {\n die();\n }\n\n foreach ($activityIds as $activityId) {\n $this->dispatch(\n new MatchActivityCrmData(\n activityId: (int) $activityId,\n fromConfiguration: $matchFromOtherCrm ? $team->getCrmConfiguration() : null,\n remoteSearch: $remoteSearch,\n )\n );\n }\n\n return CommandAlias::SUCCESS;\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}]...
|
7683757606334404006
|
-8740212531662190524
|
visual_change
|
accessibility
|
NULL
|
Pushed 1 commit to origin/JY-20903-update_activity Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change
text/html
text/html
text/html
View pull request
1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Activities;
use Illuminate\Support\Facades\Validator;
use Jiminny\Console\Commands\Command;
use Jiminny\Jobs\Crm\MatchActivityCrmData;
use Jiminny\Models\Activity;
use Jiminny\Models\Team;
use Symfony\Component\Console\Command\Command as CommandAlias;
class ActivitiesMatchCrmCommand extends Command
{
protected $signature = 'activity:match-crm
{--teamId=}
{--from=}
{--to=}
{--activityId=}
{--matchFromOtherCrm}
{--remoteSearch}
{--sync}
';
public function handle(): int
{
$teamId = $this->option('teamId');
$from = $this->option('from');
$to = $this->option('to');
$matchFromOtherCrm = $this->option('matchFromOtherCrm');
$remoteSearch = $this->option('remoteSearch');
$activityId = $this->option('activityId');
$validator = Validator::make(
[
'teamId' => $teamId,
'from' => $from,
'to' => $to,
'matchFromOtherCrm' => $matchFromOtherCrm,
'activityId' => $activityId,
'remoteSearch' => $remoteSearch,
],
[
'teamId' => ['required_without:activityId', 'numeric', 'nullable'],
'from' => ['required_without:activityId', 'date', 'nullable'],
'to' => ['required_without:activityId', 'date', 'nullable'],
'matchFromOtherCrm' => ['required', 'boolean'],
'remoteSearch' => ['required', 'boolean'],
'activityId' => ['numeric', 'nullable'],
]
);
if ($validator->fails()) {
$this->error('Validation failed:');
$this->output->block($validator->errors()->all());
return CommandAlias::FAILURE;
}
if ($activityId) {
$activity = Activity::find((int) $activityId);
if ($activity === null) {
$this->error('Cannot find activity.');
return CommandAlias::FAILURE;
}
$team = $activity->getTeam();
$this->info($activity->getTitle() . ' found.');
$activityIds = [$activity->getId()];
} else {
$team = Team::find($teamId);
if ($team === null) {
$this->error('Cannot find team.');
return CommandAlias::FAILURE;
}
$this->info($team->getName() . ' | matching activities from ' . $from . ' to ' . $to);
$activities = Activity::select('activities.id')
->join('users', 'activities.user_id', '=', 'users.id')
->where('users.team_id', '=', $team->getId())
->whereBetween('activities.created_at', [$from, $to]);
if ($matchFromOtherCrm) {
$activities->where('activities.crm_configuration_id', '!=', $team->getCrmConfigurationId());
}
$activityIds = $activities->pluck('id');
$this->info('Found activities: ' . $activityIds->count());
}
if (! $this->confirm('Do you want to continue?')) {
die();
}
foreach ($activityIds as $activityId) {
$this->dispatch(
new MatchActivityCrmData(
activityId: (int) $activityId,
fromConfiguration: $matchFromOtherCrm ? $team->getCrmConfiguration() : null,
remoteSearch: $remoteSearch,
)
);
}
return CommandAlias::SUCCESS;
}
}
Sync Changes
Hide This Notification...
|
43622
|
NULL
|
NULL
|
NULL
|
|
43625
|
1592
|
1
|
2026-05-14T13:02:56.487138+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763776487_m2.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pushed 1 commit to origin/JY-20903-update_activity Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change
text/html
text/html
text/html
View pull request
1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings...
|
[{"role":"AXTextField","text [{"role":"AXTextField","text":"Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change","depth":3,"bounds":{"left":0.8753325,"top":0.82521945,"width":0.11037234,"height":0.040702313},"on_screen":true,"value":"Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.82521945,"width":0.10305851,"height":0.040702313},"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"View pull request","depth":2,"bounds":{"left":0.8753325,"top":0.87150836,"width":0.03523936,"height":0.013567438},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1 file committed","depth":2,"bounds":{"left":0.8753325,"top":0.91300875,"width":0.100398935,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20903 revert changes in command","depth":3,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.11037234,"height":0.013567438},"on_screen":true,"value":"JY-20903 revert changes in command","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.0787899,"height":0.013567438},"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"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":"#12077 on JY-20903-update_activity-stage-on…hange, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12566489,"height":0.025538707},"on_screen":true,"help_text":"Pull request #12077 exists for current branch JY-20903-update__activity-stage-on…hange","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}]...
|
993626034484311521
|
-7096332524898286122
|
click
|
accessibility
|
NULL
|
Pushed 1 commit to origin/JY-20903-update_activity Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change
text/html
text/html
text/html
View pull request
1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43626
|
1591
|
3
|
2026-05-14T13:02:59.717520+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763779717_m1.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Pushed 1 commit to origin/JY-20903-update_activity Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change
text/html
text/html
text/html
View pull request
1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Activities;
use Illuminate\Support\Facades\Validator;
use Jiminny\Console\Commands\Command;
use Jiminny\Jobs\Crm\MatchActivityCrmData;
use Jiminny\Models\Activity;
use Jiminny\Models\Team;
use Symfony\Component\Console\Command\Command as CommandAlias;
class ActivitiesMatchCrmCommand extends Command
{
protected $signature = 'activity:match-crm
{--teamId=}
{--from=}
{--to=}
{--activityId=}
{--matchFromOtherCrm}
{--remoteSearch}
{--sync}
';
public function handle(): int
{
$teamId = $this->option('teamId');
$from = $this->option('from');
$to = $this->option('to');
$matchFromOtherCrm = $this->option('matchFromOtherCrm');
$remoteSearch = $this->option('remoteSearch');
$activityId = $this->option('activityId');
$validator = Validator::make(
[
'teamId' => $teamId,
'from' => $from,
'to' => $to,
'matchFromOtherCrm' => $matchFromOtherCrm,
'activityId' => $activityId,
'remoteSearch' => $remoteSearch,
],
[
'teamId' => ['required_without:activityId', 'numeric', 'nullable'],
'from' => ['required_without:activityId', 'date', 'nullable'],
'to' => ['required_without:activityId', 'date', 'nullable'],
'matchFromOtherCrm' => ['required', 'boolean'],
'remoteSearch' => ['required', 'boolean'],
'activityId' => ['numeric', 'nullable'],
]
);
if ($validator->fails()) {
$this->error('Validation failed:');
$this->output->block($validator->errors()->all());
return CommandAlias::FAILURE;
}
if ($activityId) {
$activity = Activity::find((int) $activityId);
if ($activity === null) {
$this->error('Cannot find activity.');
return CommandAlias::FAILURE;
}
$team = $activity->getTeam();
$this->info($activity->getTitle() . ' found.');
$activityIds = [$activity->getId()];
} else {
$team = Team::find($teamId);
if ($team === null) {
$this->error('Cannot find team.');
return CommandAlias::FAILURE;
}
$this->info($team->getName() . ' | matching activities from ' . $from . ' to ' . $to);
$activities = Activity::select('activities.id')
->join('users', 'activities.user_id', '=', 'users.id')
->where('users.team_id', '=', $team->getId())
->whereBetween('activities.created_at', [$from, $to]);
if ($matchFromOtherCrm) {
$activities->where('activities.crm_configuration_id', '!=', $team->getCrmConfigurationId());
}
$activityIds = $activities->pluck('id');
$this->info('Found activities: ' . $activityIds->count());
}
if (! $this->confirm('Do you want to continue?')) {
die();
}
foreach ($activityIds as $activityId) {
$this->dispatch(
new MatchActivityCrmData(
activityId: (int) $activityId,
fromConfiguration: $matchFromOtherCrm ? $team->getCrmConfiguration() : null,
remoteSearch: $remoteSearch,
)
);
}
return CommandAlias::SUCCESS;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Activities;
use Illuminate\Support\Facades\Validator;
use Jiminny\Console\Commands\Command;
use Jiminny\Contracts\Services\Crm\ServiceInterface;
use Jiminny\Models\Activity;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\EmailHelper;
use Throwable;
class FixActivitiesOpportunity extends Command
{
protected $signature = 'activity:fix-opportunity {--from=} {--to=}';
public function handle(EmailHelper $emailHelper): int
{
$from = $this->option('from');
$to = $this->option('to');
$validator = Validator::make(
['from' => $from, 'to' => $to],
[
'from' => ['required', 'date'],
'to' => ['required', 'date'],
]
);
if ($validator->fails()) {
$this->error('Validation failed:');
$this->output->block($validator->errors()->all());
return Command::FAILURE;
}
$this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);
$activityIds = Activity::select('activities.id')
->whereBetween('activities.created_at', [$from, $to])
->join('users', 'activities.user_id', '=', 'users.id')
->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')
->whereColumn('opportunities.team_id', '<>', 'users.team_id')
->pluck('id');
$this->info('Found activities: ' . $activityIds->count());
foreach ($activityIds as $activityId) {
$activity = Activity::where('id', $activityId)
->with(['user', 'participants'])
->first();
$crmService = $this->getCrmService($activity->getTeam());
if ($crmService === null) {
$this->resetActivityOpportunity($activity);
continue;
}
$this->processParticipants($crmService, $emailHelper, $activity);
}
return Command::SUCCESS;
}
private function getCrmService(Team $team): ?ServiceInterface
{
$config = $team->getCrmConfiguration();
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $team->getOwner(),
'providerSlug' => $config->getProviderName(),
]);
try {
return $crmResolver->prepareCrmService();
} catch (Throwable $e) {
$this->error('Could not prepare CRM service: ' . $e->getMessage());
return null;
}
}
private function processParticipants(
ServiceInterface $crmService,
EmailHelper $emailHelper,
Activity $activity
): void {
$team = $activity->getTeam();
$user = $activity->getUser();
$participants = $activity->getParticipants();
foreach ($participants as $participant) {
if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {
continue;
}
$emailAddress = $participant->getEmailAddress();
if ($emailHelper->isCompanyEmail($team, $emailAddress)) {
continue;
}
try {
$opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());
} catch (Throwable $e) {
$this->error('Could not find opportunity: ' . $e->getMessage());
$opportunity = null;
}
if ($opportunity === null) {
$this->resetActivityOpportunity($activity);
continue;
}
$activity->update(['opportunity_id' => $opportunity->getId()]);
$this->info('Opportunity updated for activity: ' . $activity->getId());
}
}
private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity
{
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
$match = $decorator->matchExactlyByEmail($emailAddress, $userId);
if (empty($match)) {
$match = $decorator->matchByDomain($emailAddress, $userId);
}
if (empty($match)) {
return null;
}
[, , $opportunity, ,] = $match;
return $opportunity;
}
private function resetActivityOpportunity(Activity $activity): void
{
$this->info('Reset opportunity for activity: ' . $activity->getId());
$activity->update(['opportunity_id' => null]);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXTextField","text [{"role":"AXTextField","text":"Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change","depth":3,"on_screen":true,"value":"Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"View pull request","depth":2,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1 file committed","depth":2,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20903 revert changes in command","depth":3,"on_screen":true,"value":"JY-20903 revert changes in command","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"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":"#12077 on JY-20903-update_activity-stage-on…hange, menu","depth":5,"on_screen":true,"help_text":"Pull request #12077 exists for current branch JY-20903-update__activity-stage-on…hange","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":"4","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\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Jobs\\Crm\\MatchActivityCrmData;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Team;\nuse Symfony\\Component\\Console\\Command\\Command as CommandAlias;\n\nclass ActivitiesMatchCrmCommand extends Command\n{\n protected $signature = 'activity:match-crm\n {--teamId=}\n {--from=}\n {--to=}\n {--activityId=}\n {--matchFromOtherCrm}\n {--remoteSearch}\n {--sync}\n ';\n\n public function handle(): int\n {\n $teamId = $this->option('teamId');\n $from = $this->option('from');\n $to = $this->option('to');\n $matchFromOtherCrm = $this->option('matchFromOtherCrm');\n $remoteSearch = $this->option('remoteSearch');\n $activityId = $this->option('activityId');\n\n $validator = Validator::make(\n [\n 'teamId' => $teamId,\n 'from' => $from,\n 'to' => $to,\n 'matchFromOtherCrm' => $matchFromOtherCrm,\n 'activityId' => $activityId,\n 'remoteSearch' => $remoteSearch,\n ],\n [\n 'teamId' => ['required_without:activityId', 'numeric', 'nullable'],\n 'from' => ['required_without:activityId', 'date', 'nullable'],\n 'to' => ['required_without:activityId', 'date', 'nullable'],\n 'matchFromOtherCrm' => ['required', 'boolean'],\n 'remoteSearch' => ['required', 'boolean'],\n 'activityId' => ['numeric', 'nullable'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return CommandAlias::FAILURE;\n }\n\n if ($activityId) {\n $activity = Activity::find((int) $activityId);\n if ($activity === null) {\n $this->error('Cannot find activity.');\n\n return CommandAlias::FAILURE;\n }\n $team = $activity->getTeam();\n $this->info($activity->getTitle() . ' found.');\n\n $activityIds = [$activity->getId()];\n } else {\n $team = Team::find($teamId);\n if ($team === null) {\n $this->error('Cannot find team.');\n\n return CommandAlias::FAILURE;\n }\n\n $this->info($team->getName() . ' | matching activities from ' . $from . ' to ' . $to);\n\n $activities = Activity::select('activities.id')\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->where('users.team_id', '=', $team->getId())\n ->whereBetween('activities.created_at', [$from, $to]);\n if ($matchFromOtherCrm) {\n $activities->where('activities.crm_configuration_id', '!=', $team->getCrmConfigurationId());\n }\n\n $activityIds = $activities->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n }\n\n if (! $this->confirm('Do you want to continue?')) {\n die();\n }\n\n foreach ($activityIds as $activityId) {\n $this->dispatch(\n new MatchActivityCrmData(\n activityId: (int) $activityId,\n fromConfiguration: $matchFromOtherCrm ? $team->getCrmConfiguration() : null,\n remoteSearch: $remoteSearch,\n )\n );\n }\n\n return CommandAlias::SUCCESS;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Jobs\\Crm\\MatchActivityCrmData;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Team;\nuse Symfony\\Component\\Console\\Command\\Command as CommandAlias;\n\nclass ActivitiesMatchCrmCommand extends Command\n{\n protected $signature = 'activity:match-crm\n {--teamId=}\n {--from=}\n {--to=}\n {--activityId=}\n {--matchFromOtherCrm}\n {--remoteSearch}\n {--sync}\n ';\n\n public function handle(): int\n {\n $teamId = $this->option('teamId');\n $from = $this->option('from');\n $to = $this->option('to');\n $matchFromOtherCrm = $this->option('matchFromOtherCrm');\n $remoteSearch = $this->option('remoteSearch');\n $activityId = $this->option('activityId');\n\n $validator = Validator::make(\n [\n 'teamId' => $teamId,\n 'from' => $from,\n 'to' => $to,\n 'matchFromOtherCrm' => $matchFromOtherCrm,\n 'activityId' => $activityId,\n 'remoteSearch' => $remoteSearch,\n ],\n [\n 'teamId' => ['required_without:activityId', 'numeric', 'nullable'],\n 'from' => ['required_without:activityId', 'date', 'nullable'],\n 'to' => ['required_without:activityId', 'date', 'nullable'],\n 'matchFromOtherCrm' => ['required', 'boolean'],\n 'remoteSearch' => ['required', 'boolean'],\n 'activityId' => ['numeric', 'nullable'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return CommandAlias::FAILURE;\n }\n\n if ($activityId) {\n $activity = Activity::find((int) $activityId);\n if ($activity === null) {\n $this->error('Cannot find activity.');\n\n return CommandAlias::FAILURE;\n }\n $team = $activity->getTeam();\n $this->info($activity->getTitle() . ' found.');\n\n $activityIds = [$activity->getId()];\n } else {\n $team = Team::find($teamId);\n if ($team === null) {\n $this->error('Cannot find team.');\n\n return CommandAlias::FAILURE;\n }\n\n $this->info($team->getName() . ' | matching activities from ' . $from . ' to ' . $to);\n\n $activities = Activity::select('activities.id')\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->where('users.team_id', '=', $team->getId())\n ->whereBetween('activities.created_at', [$from, $to]);\n if ($matchFromOtherCrm) {\n $activities->where('activities.crm_configuration_id', '!=', $team->getCrmConfigurationId());\n }\n\n $activityIds = $activities->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n }\n\n if (! $this->confirm('Do you want to continue?')) {\n die();\n }\n\n foreach ($activityIds as $activityId) {\n $this->dispatch(\n new MatchActivityCrmData(\n activityId: (int) $activityId,\n fromConfiguration: $matchFromOtherCrm ? $team->getCrmConfiguration() : null,\n remoteSearch: $remoteSearch,\n )\n );\n }\n\n return CommandAlias::SUCCESS;\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":"AXStaticText","text":"2","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\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\EmailHelper;\nuse Throwable;\n\nclass FixActivitiesOpportunity extends Command\n{\n protected $signature = 'activity:fix-opportunity {--from=} {--to=}';\n\n public function handle(EmailHelper $emailHelper): int\n {\n $from = $this->option('from');\n $to = $this->option('to');\n\n $validator = Validator::make(\n ['from' => $from, 'to' => $to],\n [\n 'from' => ['required', 'date'],\n 'to' => ['required', 'date'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return Command::FAILURE;\n }\n\n $this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);\n\n $activityIds = Activity::select('activities.id')\n ->whereBetween('activities.created_at', [$from, $to])\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')\n ->whereColumn('opportunities.team_id', '<>', 'users.team_id')\n ->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n\n foreach ($activityIds as $activityId) {\n $activity = Activity::where('id', $activityId)\n ->with(['user', 'participants'])\n ->first();\n\n $crmService = $this->getCrmService($activity->getTeam());\n if ($crmService === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $this->processParticipants($crmService, $emailHelper, $activity);\n }\n\n return Command::SUCCESS;\n }\n\n private function getCrmService(Team $team): ?ServiceInterface\n {\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n try {\n return $crmResolver->prepareCrmService();\n } catch (Throwable $e) {\n $this->error('Could not prepare CRM service: ' . $e->getMessage());\n\n return null;\n }\n }\n\n private function processParticipants(\n ServiceInterface $crmService,\n EmailHelper $emailHelper,\n Activity $activity\n ): void {\n $team = $activity->getTeam();\n $user = $activity->getUser();\n $participants = $activity->getParticipants();\n\n foreach ($participants as $participant) {\n if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {\n continue;\n }\n\n $emailAddress = $participant->getEmailAddress();\n if ($emailHelper->isCompanyEmail($team, $emailAddress)) {\n continue;\n }\n\n try {\n $opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());\n } catch (Throwable $e) {\n $this->error('Could not find opportunity: ' . $e->getMessage());\n\n $opportunity = null;\n }\n\n if ($opportunity === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $activity->update(['opportunity_id' => $opportunity->getId()]);\n\n $this->info('Opportunity updated for activity: ' . $activity->getId());\n }\n }\n\n private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity\n {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n $match = $decorator->matchExactlyByEmail($emailAddress, $userId);\n\n if (empty($match)) {\n $match = $decorator->matchByDomain($emailAddress, $userId);\n }\n\n if (empty($match)) {\n return null;\n }\n\n [, , $opportunity, ,] = $match;\n\n return $opportunity;\n }\n\n private function resetActivityOpportunity(Activity $activity): void\n {\n $this->info('Reset opportunity for activity: ' . $activity->getId());\n $activity->update(['opportunity_id' => null]);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\EmailHelper;\nuse Throwable;\n\nclass FixActivitiesOpportunity extends Command\n{\n protected $signature = 'activity:fix-opportunity {--from=} {--to=}';\n\n public function handle(EmailHelper $emailHelper): int\n {\n $from = $this->option('from');\n $to = $this->option('to');\n\n $validator = Validator::make(\n ['from' => $from, 'to' => $to],\n [\n 'from' => ['required', 'date'],\n 'to' => ['required', 'date'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return Command::FAILURE;\n }\n\n $this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);\n\n $activityIds = Activity::select('activities.id')\n ->whereBetween('activities.created_at', [$from, $to])\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')\n ->whereColumn('opportunities.team_id', '<>', 'users.team_id')\n ->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n\n foreach ($activityIds as $activityId) {\n $activity = Activity::where('id', $activityId)\n ->with(['user', 'participants'])\n ->first();\n\n $crmService = $this->getCrmService($activity->getTeam());\n if ($crmService === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $this->processParticipants($crmService, $emailHelper, $activity);\n }\n\n return Command::SUCCESS;\n }\n\n private function getCrmService(Team $team): ?ServiceInterface\n {\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n try {\n return $crmResolver->prepareCrmService();\n } catch (Throwable $e) {\n $this->error('Could not prepare CRM service: ' . $e->getMessage());\n\n return null;\n }\n }\n\n private function processParticipants(\n ServiceInterface $crmService,\n EmailHelper $emailHelper,\n Activity $activity\n ): void {\n $team = $activity->getTeam();\n $user = $activity->getUser();\n $participants = $activity->getParticipants();\n\n foreach ($participants as $participant) {\n if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {\n continue;\n }\n\n $emailAddress = $participant->getEmailAddress();\n if ($emailHelper->isCompanyEmail($team, $emailAddress)) {\n continue;\n }\n\n try {\n $opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());\n } catch (Throwable $e) {\n $this->error('Could not find opportunity: ' . $e->getMessage());\n\n $opportunity = null;\n }\n\n if ($opportunity === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $activity->update(['opportunity_id' => $opportunity->getId()]);\n\n $this->info('Opportunity updated for activity: ' . $activity->getId());\n }\n }\n\n private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity\n {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n $match = $decorator->matchExactlyByEmail($emailAddress, $userId);\n\n if (empty($match)) {\n $match = $decorator->matchByDomain($emailAddress, $userId);\n }\n\n if (empty($match)) {\n return null;\n }\n\n [, , $opportunity, ,] = $match;\n\n return $opportunity;\n }\n\n private function resetActivityOpportunity(Activity $activity): void\n {\n $this->info('Reset opportunity for activity: ' . $activity->getId());\n $activity->update(['opportunity_id' => null]);\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}]...
|
-2062729057537069259
|
-8744680853507163644
|
click
|
accessibility
|
NULL
|
Pushed 1 commit to origin/JY-20903-update_activity Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change
text/html
text/html
text/html
View pull request
1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Activities;
use Illuminate\Support\Facades\Validator;
use Jiminny\Console\Commands\Command;
use Jiminny\Jobs\Crm\MatchActivityCrmData;
use Jiminny\Models\Activity;
use Jiminny\Models\Team;
use Symfony\Component\Console\Command\Command as CommandAlias;
class ActivitiesMatchCrmCommand extends Command
{
protected $signature = 'activity:match-crm
{--teamId=}
{--from=}
{--to=}
{--activityId=}
{--matchFromOtherCrm}
{--remoteSearch}
{--sync}
';
public function handle(): int
{
$teamId = $this->option('teamId');
$from = $this->option('from');
$to = $this->option('to');
$matchFromOtherCrm = $this->option('matchFromOtherCrm');
$remoteSearch = $this->option('remoteSearch');
$activityId = $this->option('activityId');
$validator = Validator::make(
[
'teamId' => $teamId,
'from' => $from,
'to' => $to,
'matchFromOtherCrm' => $matchFromOtherCrm,
'activityId' => $activityId,
'remoteSearch' => $remoteSearch,
],
[
'teamId' => ['required_without:activityId', 'numeric', 'nullable'],
'from' => ['required_without:activityId', 'date', 'nullable'],
'to' => ['required_without:activityId', 'date', 'nullable'],
'matchFromOtherCrm' => ['required', 'boolean'],
'remoteSearch' => ['required', 'boolean'],
'activityId' => ['numeric', 'nullable'],
]
);
if ($validator->fails()) {
$this->error('Validation failed:');
$this->output->block($validator->errors()->all());
return CommandAlias::FAILURE;
}
if ($activityId) {
$activity = Activity::find((int) $activityId);
if ($activity === null) {
$this->error('Cannot find activity.');
return CommandAlias::FAILURE;
}
$team = $activity->getTeam();
$this->info($activity->getTitle() . ' found.');
$activityIds = [$activity->getId()];
} else {
$team = Team::find($teamId);
if ($team === null) {
$this->error('Cannot find team.');
return CommandAlias::FAILURE;
}
$this->info($team->getName() . ' | matching activities from ' . $from . ' to ' . $to);
$activities = Activity::select('activities.id')
->join('users', 'activities.user_id', '=', 'users.id')
->where('users.team_id', '=', $team->getId())
->whereBetween('activities.created_at', [$from, $to]);
if ($matchFromOtherCrm) {
$activities->where('activities.crm_configuration_id', '!=', $team->getCrmConfigurationId());
}
$activityIds = $activities->pluck('id');
$this->info('Found activities: ' . $activityIds->count());
}
if (! $this->confirm('Do you want to continue?')) {
die();
}
foreach ($activityIds as $activityId) {
$this->dispatch(
new MatchActivityCrmData(
activityId: (int) $activityId,
fromConfiguration: $matchFromOtherCrm ? $team->getCrmConfiguration() : null,
remoteSearch: $remoteSearch,
)
);
}
return CommandAlias::SUCCESS;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Activities;
use Illuminate\Support\Facades\Validator;
use Jiminny\Console\Commands\Command;
use Jiminny\Contracts\Services\Crm\ServiceInterface;
use Jiminny\Models\Activity;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\EmailHelper;
use Throwable;
class FixActivitiesOpportunity extends Command
{
protected $signature = 'activity:fix-opportunity {--from=} {--to=}';
public function handle(EmailHelper $emailHelper): int
{
$from = $this->option('from');
$to = $this->option('to');
$validator = Validator::make(
['from' => $from, 'to' => $to],
[
'from' => ['required', 'date'],
'to' => ['required', 'date'],
]
);
if ($validator->fails()) {
$this->error('Validation failed:');
$this->output->block($validator->errors()->all());
return Command::FAILURE;
}
$this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);
$activityIds = Activity::select('activities.id')
->whereBetween('activities.created_at', [$from, $to])
->join('users', 'activities.user_id', '=', 'users.id')
->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')
->whereColumn('opportunities.team_id', '<>', 'users.team_id')
->pluck('id');
$this->info('Found activities: ' . $activityIds->count());
foreach ($activityIds as $activityId) {
$activity = Activity::where('id', $activityId)
->with(['user', 'participants'])
->first();
$crmService = $this->getCrmService($activity->getTeam());
if ($crmService === null) {
$this->resetActivityOpportunity($activity);
continue;
}
$this->processParticipants($crmService, $emailHelper, $activity);
}
return Command::SUCCESS;
}
private function getCrmService(Team $team): ?ServiceInterface
{
$config = $team->getCrmConfiguration();
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $team->getOwner(),
'providerSlug' => $config->getProviderName(),
]);
try {
return $crmResolver->prepareCrmService();
} catch (Throwable $e) {
$this->error('Could not prepare CRM service: ' . $e->getMessage());
return null;
}
}
private function processParticipants(
ServiceInterface $crmService,
EmailHelper $emailHelper,
Activity $activity
): void {
$team = $activity->getTeam();
$user = $activity->getUser();
$participants = $activity->getParticipants();
foreach ($participants as $participant) {
if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {
continue;
}
$emailAddress = $participant->getEmailAddress();
if ($emailHelper->isCompanyEmail($team, $emailAddress)) {
continue;
}
try {
$opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());
} catch (Throwable $e) {
$this->error('Could not find opportunity: ' . $e->getMessage());
$opportunity = null;
}
if ($opportunity === null) {
$this->resetActivityOpportunity($activity);
continue;
}
$activity->update(['opportunity_id' => $opportunity->getId()]);
$this->info('Opportunity updated for activity: ' . $activity->getId());
}
}
private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity
{
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
$match = $decorator->matchExactlyByEmail($emailAddress, $userId);
if (empty($match)) {
$match = $decorator->matchByDomain($emailAddress, $userId);
}
if (empty($match)) {
return null;
}
[, , $opportunity, ,] = $match;
return $opportunity;
}
private function resetActivityOpportunity(Activity $activity): void
{
$this->info('Reset opportunity for activity: ' . $activity->getId());
$activity->update(['opportunity_id' => null]);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43627
|
1592
|
2
|
2026-05-14T13:02:59.763013+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763779763_m2.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pushed 1 commit to origin/JY-20903-update_activity Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change
text/html
text/html
text/html
View pull request
1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Activities;
use Illuminate\Support\Facades\Validator;
use Jiminny\Console\Commands\Command;
use Jiminny\Jobs\Crm\MatchActivityCrmData;
use Jiminny\Models\Activity;
use Jiminny\Models\Team;
use Symfony\Component\Console\Command\Command as CommandAlias;
class ActivitiesMatchCrmCommand extends Command
{
protected $signature = 'activity:match-crm
{--teamId=}
{--from=}
{--to=}
{--activityId=}
{--matchFromOtherCrm}
{--remoteSearch}
{--sync}
';
public function handle(): int
{
$teamId = $this->option('teamId');
$from = $this->option('from');
$to = $this->option('to');
$matchFromOtherCrm = $this->option('matchFromOtherCrm');
$remoteSearch = $this->option('remoteSearch');
$activityId = $this->option('activityId');
$validator = Validator::make(
[
'teamId' => $teamId,
'from' => $from,
'to' => $to,
'matchFromOtherCrm' => $matchFromOtherCrm,
'activityId' => $activityId,
'remoteSearch' => $remoteSearch,
],
[
'teamId' => ['required_without:activityId', 'numeric', 'nullable'],
'from' => ['required_without:activityId', 'date', 'nullable'],
'to' => ['required_without:activityId', 'date', 'nullable'],
'matchFromOtherCrm' => ['required', 'boolean'],
'remoteSearch' => ['required', 'boolean'],
'activityId' => ['numeric', 'nullable'],
]
);
if ($validator->fails()) {
$this->error('Validation failed:');
$this->output->block($validator->errors()->all());
return CommandAlias::FAILURE;
}
if ($activityId) {
$activity = Activity::find((int) $activityId);
if ($activity === null) {
$this->error('Cannot find activity.');
return CommandAlias::FAILURE;
}
$team = $activity->getTeam();
$this->info($activity->getTitle() . ' found.');
$activityIds = [$activity->getId()];
} else {
$team = Team::find($teamId);
if ($team === null) {
$this->error('Cannot find team.');
return CommandAlias::FAILURE;
}
$this->info($team->getName() . ' | matching activities from ' . $from . ' to ' . $to);
$activities = Activity::select('activities.id')
->join('users', 'activities.user_id', '=', 'users.id')
->where('users.team_id', '=', $team->getId())
->whereBetween('activities.created_at', [$from, $to]);
if ($matchFromOtherCrm) {
$activities->where('activities.crm_configuration_id', '!=', $team->getCrmConfigurationId());
}
$activityIds = $activities->pluck('id');
$this->info('Found activities: ' . $activityIds->count());
}
if (! $this->confirm('Do you want to continue?')) {
die();
}
foreach ($activityIds as $activityId) {
$this->dispatch(
new MatchActivityCrmData(
activityId: (int) $activityId,
fromConfiguration: $matchFromOtherCrm ? $team->getCrmConfiguration() : null,
remoteSearch: $remoteSearch,
)
);
}
return CommandAlias::SUCCESS;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Activities;
use Illuminate\Support\Facades\Validator;
use Jiminny\Console\Commands\Command;
use Jiminny\Contracts\Services\Crm\ServiceInterface;
use Jiminny\Models\Activity;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\EmailHelper;
use Throwable;
class FixActivitiesOpportunity extends Command
{
protected $signature = 'activity:fix-opportunity {--from=} {--to=}';
public function handle(EmailHelper $emailHelper): int
{
$from = $this->option('from');
$to = $this->option('to');
$validator = Validator::make(
['from' => $from, 'to' => $to],
[
'from' => ['required', 'date'],
'to' => ['required', 'date'],
]
);
if ($validator->fails()) {
$this->error('Validation failed:');
$this->output->block($validator->errors()->all());
return Command::FAILURE;
}
$this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);
$activityIds = Activity::select('activities.id')
->whereBetween('activities.created_at', [$from, $to])
->join('users', 'activities.user_id', '=', 'users.id')
->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')
->whereColumn('opportunities.team_id', '<>', 'users.team_id')
->pluck('id');
$this->info('Found activities: ' . $activityIds->count());
foreach ($activityIds as $activityId) {
$activity = Activity::where('id', $activityId)
->with(['user', 'participants'])
->first();
$crmService = $this->getCrmService($activity->getTeam());
if ($crmService === null) {
$this->resetActivityOpportunity($activity);
continue;
}
$this->processParticipants($crmService, $emailHelper, $activity);
}
return Command::SUCCESS;
}
private function getCrmService(Team $team): ?ServiceInterface
{
$config = $team->getCrmConfiguration();
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $team->getOwner(),
'providerSlug' => $config->getProviderName(),
]);
try {
return $crmResolver->prepareCrmService();
} catch (Throwable $e) {
$this->error('Could not prepare CRM service: ' . $e->getMessage());
return null;
}
}
private function processParticipants(
ServiceInterface $crmService,
EmailHelper $emailHelper,
Activity $activity
): void {
$team = $activity->getTeam();
$user = $activity->getUser();
$participants = $activity->getParticipants();
foreach ($participants as $participant) {
if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {
continue;
}
$emailAddress = $participant->getEmailAddress();
if ($emailHelper->isCompanyEmail($team, $emailAddress)) {
continue;
}
try {
$opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());
} catch (Throwable $e) {
$this->error('Could not find opportunity: ' . $e->getMessage());
$opportunity = null;
}
if ($opportunity === null) {
$this->resetActivityOpportunity($activity);
continue;
}
$activity->update(['opportunity_id' => $opportunity->getId()]);
$this->info('Opportunity updated for activity: ' . $activity->getId());
}
}
private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity
{
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
$match = $decorator->matchExactlyByEmail($emailAddress, $userId);
if (empty($match)) {
$match = $decorator->matchByDomain($emailAddress, $userId);
}
if (empty($match)) {
return null;
}
[, , $opportunity, ,] = $match;
return $opportunity;
}
private function resetActivityOpportunity(Activity $activity): void
{
$this->info('Reset opportunity for activity: ' . $activity->getId());
$activity->update(['opportunity_id' => null]);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXTextField","text [{"role":"AXTextField","text":"Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change","depth":3,"bounds":{"left":0.8753325,"top":0.82521945,"width":0.11037234,"height":0.040702313},"on_screen":true,"value":"Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.82521945,"width":0.10305851,"height":0.040702313},"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"View pull request","depth":2,"bounds":{"left":0.8753325,"top":0.87150836,"width":0.03523936,"height":0.013567438},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1 file committed","depth":2,"bounds":{"left":0.8753325,"top":0.91300875,"width":0.100398935,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20903 revert changes in command","depth":3,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.11037234,"height":0.013567438},"on_screen":true,"value":"JY-20903 revert changes in command","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.0787899,"height":0.013567438},"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"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":"#12077 on JY-20903-update_activity-stage-on…hange, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12566489,"height":0.025538707},"on_screen":true,"help_text":"Pull request #12077 exists for current branch JY-20903-update__activity-stage-on…hange","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":"4","depth":4,"bounds":{"left":0.38397607,"top":0.12529927,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.39361703,"top":0.123703115,"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.40093085,"top":0.123703115,"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\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Jobs\\Crm\\MatchActivityCrmData;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Team;\nuse Symfony\\Component\\Console\\Command\\Command as CommandAlias;\n\nclass ActivitiesMatchCrmCommand extends Command\n{\n protected $signature = 'activity:match-crm\n {--teamId=}\n {--from=}\n {--to=}\n {--activityId=}\n {--matchFromOtherCrm}\n {--remoteSearch}\n {--sync}\n ';\n\n public function handle(): int\n {\n $teamId = $this->option('teamId');\n $from = $this->option('from');\n $to = $this->option('to');\n $matchFromOtherCrm = $this->option('matchFromOtherCrm');\n $remoteSearch = $this->option('remoteSearch');\n $activityId = $this->option('activityId');\n\n $validator = Validator::make(\n [\n 'teamId' => $teamId,\n 'from' => $from,\n 'to' => $to,\n 'matchFromOtherCrm' => $matchFromOtherCrm,\n 'activityId' => $activityId,\n 'remoteSearch' => $remoteSearch,\n ],\n [\n 'teamId' => ['required_without:activityId', 'numeric', 'nullable'],\n 'from' => ['required_without:activityId', 'date', 'nullable'],\n 'to' => ['required_without:activityId', 'date', 'nullable'],\n 'matchFromOtherCrm' => ['required', 'boolean'],\n 'remoteSearch' => ['required', 'boolean'],\n 'activityId' => ['numeric', 'nullable'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return CommandAlias::FAILURE;\n }\n\n if ($activityId) {\n $activity = Activity::find((int) $activityId);\n if ($activity === null) {\n $this->error('Cannot find activity.');\n\n return CommandAlias::FAILURE;\n }\n $team = $activity->getTeam();\n $this->info($activity->getTitle() . ' found.');\n\n $activityIds = [$activity->getId()];\n } else {\n $team = Team::find($teamId);\n if ($team === null) {\n $this->error('Cannot find team.');\n\n return CommandAlias::FAILURE;\n }\n\n $this->info($team->getName() . ' | matching activities from ' . $from . ' to ' . $to);\n\n $activities = Activity::select('activities.id')\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->where('users.team_id', '=', $team->getId())\n ->whereBetween('activities.created_at', [$from, $to]);\n if ($matchFromOtherCrm) {\n $activities->where('activities.crm_configuration_id', '!=', $team->getCrmConfigurationId());\n }\n\n $activityIds = $activities->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n }\n\n if (! $this->confirm('Do you want to continue?')) {\n die();\n }\n\n foreach ($activityIds as $activityId) {\n $this->dispatch(\n new MatchActivityCrmData(\n activityId: (int) $activityId,\n fromConfiguration: $matchFromOtherCrm ? $team->getCrmConfiguration() : null,\n remoteSearch: $remoteSearch,\n )\n );\n }\n\n return CommandAlias::SUCCESS;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Jobs\\Crm\\MatchActivityCrmData;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Team;\nuse Symfony\\Component\\Console\\Command\\Command as CommandAlias;\n\nclass ActivitiesMatchCrmCommand extends Command\n{\n protected $signature = 'activity:match-crm\n {--teamId=}\n {--from=}\n {--to=}\n {--activityId=}\n {--matchFromOtherCrm}\n {--remoteSearch}\n {--sync}\n ';\n\n public function handle(): int\n {\n $teamId = $this->option('teamId');\n $from = $this->option('from');\n $to = $this->option('to');\n $matchFromOtherCrm = $this->option('matchFromOtherCrm');\n $remoteSearch = $this->option('remoteSearch');\n $activityId = $this->option('activityId');\n\n $validator = Validator::make(\n [\n 'teamId' => $teamId,\n 'from' => $from,\n 'to' => $to,\n 'matchFromOtherCrm' => $matchFromOtherCrm,\n 'activityId' => $activityId,\n 'remoteSearch' => $remoteSearch,\n ],\n [\n 'teamId' => ['required_without:activityId', 'numeric', 'nullable'],\n 'from' => ['required_without:activityId', 'date', 'nullable'],\n 'to' => ['required_without:activityId', 'date', 'nullable'],\n 'matchFromOtherCrm' => ['required', 'boolean'],\n 'remoteSearch' => ['required', 'boolean'],\n 'activityId' => ['numeric', 'nullable'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return CommandAlias::FAILURE;\n }\n\n if ($activityId) {\n $activity = Activity::find((int) $activityId);\n if ($activity === null) {\n $this->error('Cannot find activity.');\n\n return CommandAlias::FAILURE;\n }\n $team = $activity->getTeam();\n $this->info($activity->getTitle() . ' found.');\n\n $activityIds = [$activity->getId()];\n } else {\n $team = Team::find($teamId);\n if ($team === null) {\n $this->error('Cannot find team.');\n\n return CommandAlias::FAILURE;\n }\n\n $this->info($team->getName() . ' | matching activities from ' . $from . ' to ' . $to);\n\n $activities = Activity::select('activities.id')\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->where('users.team_id', '=', $team->getId())\n ->whereBetween('activities.created_at', [$from, $to]);\n if ($matchFromOtherCrm) {\n $activities->where('activities.crm_configuration_id', '!=', $team->getCrmConfigurationId());\n }\n\n $activityIds = $activities->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n }\n\n if (! $this->confirm('Do you want to continue?')) {\n die();\n }\n\n foreach ($activityIds as $activityId) {\n $this->dispatch(\n new MatchActivityCrmData(\n activityId: (int) $activityId,\n fromConfiguration: $matchFromOtherCrm ? $team->getCrmConfiguration() : null,\n remoteSearch: $remoteSearch,\n )\n );\n }\n\n return CommandAlias::SUCCESS;\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":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.7140958,"top":0.12529927,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7237367,"top":0.123703115,"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.73105055,"top":0.123703115,"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\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\EmailHelper;\nuse Throwable;\n\nclass FixActivitiesOpportunity extends Command\n{\n protected $signature = 'activity:fix-opportunity {--from=} {--to=}';\n\n public function handle(EmailHelper $emailHelper): int\n {\n $from = $this->option('from');\n $to = $this->option('to');\n\n $validator = Validator::make(\n ['from' => $from, 'to' => $to],\n [\n 'from' => ['required', 'date'],\n 'to' => ['required', 'date'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return Command::FAILURE;\n }\n\n $this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);\n\n $activityIds = Activity::select('activities.id')\n ->whereBetween('activities.created_at', [$from, $to])\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')\n ->whereColumn('opportunities.team_id', '<>', 'users.team_id')\n ->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n\n foreach ($activityIds as $activityId) {\n $activity = Activity::where('id', $activityId)\n ->with(['user', 'participants'])\n ->first();\n\n $crmService = $this->getCrmService($activity->getTeam());\n if ($crmService === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $this->processParticipants($crmService, $emailHelper, $activity);\n }\n\n return Command::SUCCESS;\n }\n\n private function getCrmService(Team $team): ?ServiceInterface\n {\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n try {\n return $crmResolver->prepareCrmService();\n } catch (Throwable $e) {\n $this->error('Could not prepare CRM service: ' . $e->getMessage());\n\n return null;\n }\n }\n\n private function processParticipants(\n ServiceInterface $crmService,\n EmailHelper $emailHelper,\n Activity $activity\n ): void {\n $team = $activity->getTeam();\n $user = $activity->getUser();\n $participants = $activity->getParticipants();\n\n foreach ($participants as $participant) {\n if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {\n continue;\n }\n\n $emailAddress = $participant->getEmailAddress();\n if ($emailHelper->isCompanyEmail($team, $emailAddress)) {\n continue;\n }\n\n try {\n $opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());\n } catch (Throwable $e) {\n $this->error('Could not find opportunity: ' . $e->getMessage());\n\n $opportunity = null;\n }\n\n if ($opportunity === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $activity->update(['opportunity_id' => $opportunity->getId()]);\n\n $this->info('Opportunity updated for activity: ' . $activity->getId());\n }\n }\n\n private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity\n {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n $match = $decorator->matchExactlyByEmail($emailAddress, $userId);\n\n if (empty($match)) {\n $match = $decorator->matchByDomain($emailAddress, $userId);\n }\n\n if (empty($match)) {\n return null;\n }\n\n [, , $opportunity, ,] = $match;\n\n return $opportunity;\n }\n\n private function resetActivityOpportunity(Activity $activity): void\n {\n $this->info('Reset opportunity for activity: ' . $activity->getId());\n $activity->update(['opportunity_id' => null]);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\EmailHelper;\nuse Throwable;\n\nclass FixActivitiesOpportunity extends Command\n{\n protected $signature = 'activity:fix-opportunity {--from=} {--to=}';\n\n public function handle(EmailHelper $emailHelper): int\n {\n $from = $this->option('from');\n $to = $this->option('to');\n\n $validator = Validator::make(\n ['from' => $from, 'to' => $to],\n [\n 'from' => ['required', 'date'],\n 'to' => ['required', 'date'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return Command::FAILURE;\n }\n\n $this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);\n\n $activityIds = Activity::select('activities.id')\n ->whereBetween('activities.created_at', [$from, $to])\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')\n ->whereColumn('opportunities.team_id', '<>', 'users.team_id')\n ->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n\n foreach ($activityIds as $activityId) {\n $activity = Activity::where('id', $activityId)\n ->with(['user', 'participants'])\n ->first();\n\n $crmService = $this->getCrmService($activity->getTeam());\n if ($crmService === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $this->processParticipants($crmService, $emailHelper, $activity);\n }\n\n return Command::SUCCESS;\n }\n\n private function getCrmService(Team $team): ?ServiceInterface\n {\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n try {\n return $crmResolver->prepareCrmService();\n } catch (Throwable $e) {\n $this->error('Could not prepare CRM service: ' . $e->getMessage());\n\n return null;\n }\n }\n\n private function processParticipants(\n ServiceInterface $crmService,\n EmailHelper $emailHelper,\n Activity $activity\n ): void {\n $team = $activity->getTeam();\n $user = $activity->getUser();\n $participants = $activity->getParticipants();\n\n foreach ($participants as $participant) {\n if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {\n continue;\n }\n\n $emailAddress = $participant->getEmailAddress();\n if ($emailHelper->isCompanyEmail($team, $emailAddress)) {\n continue;\n }\n\n try {\n $opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());\n } catch (Throwable $e) {\n $this->error('Could not find opportunity: ' . $e->getMessage());\n\n $opportunity = null;\n }\n\n if ($opportunity === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $activity->update(['opportunity_id' => $opportunity->getId()]);\n\n $this->info('Opportunity updated for activity: ' . $activity->getId());\n }\n }\n\n private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity\n {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n $match = $decorator->matchExactlyByEmail($emailAddress, $userId);\n\n if (empty($match)) {\n $match = $decorator->matchByDomain($emailAddress, $userId);\n }\n\n if (empty($match)) {\n return null;\n }\n\n [, , $opportunity, ,] = $match;\n\n return $opportunity;\n }\n\n private function resetActivityOpportunity(Activity $activity): void\n {\n $this->info('Reset opportunity for activity: ' . $activity->getId());\n $activity->update(['opportunity_id' => null]);\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}]...
|
-2062729057537069259
|
-8744680853507163644
|
click
|
accessibility
|
NULL
|
Pushed 1 commit to origin/JY-20903-update_activity Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change
text/html
text/html
text/html
View pull request
1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Activities;
use Illuminate\Support\Facades\Validator;
use Jiminny\Console\Commands\Command;
use Jiminny\Jobs\Crm\MatchActivityCrmData;
use Jiminny\Models\Activity;
use Jiminny\Models\Team;
use Symfony\Component\Console\Command\Command as CommandAlias;
class ActivitiesMatchCrmCommand extends Command
{
protected $signature = 'activity:match-crm
{--teamId=}
{--from=}
{--to=}
{--activityId=}
{--matchFromOtherCrm}
{--remoteSearch}
{--sync}
';
public function handle(): int
{
$teamId = $this->option('teamId');
$from = $this->option('from');
$to = $this->option('to');
$matchFromOtherCrm = $this->option('matchFromOtherCrm');
$remoteSearch = $this->option('remoteSearch');
$activityId = $this->option('activityId');
$validator = Validator::make(
[
'teamId' => $teamId,
'from' => $from,
'to' => $to,
'matchFromOtherCrm' => $matchFromOtherCrm,
'activityId' => $activityId,
'remoteSearch' => $remoteSearch,
],
[
'teamId' => ['required_without:activityId', 'numeric', 'nullable'],
'from' => ['required_without:activityId', 'date', 'nullable'],
'to' => ['required_without:activityId', 'date', 'nullable'],
'matchFromOtherCrm' => ['required', 'boolean'],
'remoteSearch' => ['required', 'boolean'],
'activityId' => ['numeric', 'nullable'],
]
);
if ($validator->fails()) {
$this->error('Validation failed:');
$this->output->block($validator->errors()->all());
return CommandAlias::FAILURE;
}
if ($activityId) {
$activity = Activity::find((int) $activityId);
if ($activity === null) {
$this->error('Cannot find activity.');
return CommandAlias::FAILURE;
}
$team = $activity->getTeam();
$this->info($activity->getTitle() . ' found.');
$activityIds = [$activity->getId()];
} else {
$team = Team::find($teamId);
if ($team === null) {
$this->error('Cannot find team.');
return CommandAlias::FAILURE;
}
$this->info($team->getName() . ' | matching activities from ' . $from . ' to ' . $to);
$activities = Activity::select('activities.id')
->join('users', 'activities.user_id', '=', 'users.id')
->where('users.team_id', '=', $team->getId())
->whereBetween('activities.created_at', [$from, $to]);
if ($matchFromOtherCrm) {
$activities->where('activities.crm_configuration_id', '!=', $team->getCrmConfigurationId());
}
$activityIds = $activities->pluck('id');
$this->info('Found activities: ' . $activityIds->count());
}
if (! $this->confirm('Do you want to continue?')) {
die();
}
foreach ($activityIds as $activityId) {
$this->dispatch(
new MatchActivityCrmData(
activityId: (int) $activityId,
fromConfiguration: $matchFromOtherCrm ? $team->getCrmConfiguration() : null,
remoteSearch: $remoteSearch,
)
);
}
return CommandAlias::SUCCESS;
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Activities;
use Illuminate\Support\Facades\Validator;
use Jiminny\Console\Commands\Command;
use Jiminny\Contracts\Services\Crm\ServiceInterface;
use Jiminny\Models\Activity;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\EmailHelper;
use Throwable;
class FixActivitiesOpportunity extends Command
{
protected $signature = 'activity:fix-opportunity {--from=} {--to=}';
public function handle(EmailHelper $emailHelper): int
{
$from = $this->option('from');
$to = $this->option('to');
$validator = Validator::make(
['from' => $from, 'to' => $to],
[
'from' => ['required', 'date'],
'to' => ['required', 'date'],
]
);
if ($validator->fails()) {
$this->error('Validation failed:');
$this->output->block($validator->errors()->all());
return Command::FAILURE;
}
$this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);
$activityIds = Activity::select('activities.id')
->whereBetween('activities.created_at', [$from, $to])
->join('users', 'activities.user_id', '=', 'users.id')
->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')
->whereColumn('opportunities.team_id', '<>', 'users.team_id')
->pluck('id');
$this->info('Found activities: ' . $activityIds->count());
foreach ($activityIds as $activityId) {
$activity = Activity::where('id', $activityId)
->with(['user', 'participants'])
->first();
$crmService = $this->getCrmService($activity->getTeam());
if ($crmService === null) {
$this->resetActivityOpportunity($activity);
continue;
}
$this->processParticipants($crmService, $emailHelper, $activity);
}
return Command::SUCCESS;
}
private function getCrmService(Team $team): ?ServiceInterface
{
$config = $team->getCrmConfiguration();
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $team->getOwner(),
'providerSlug' => $config->getProviderName(),
]);
try {
return $crmResolver->prepareCrmService();
} catch (Throwable $e) {
$this->error('Could not prepare CRM service: ' . $e->getMessage());
return null;
}
}
private function processParticipants(
ServiceInterface $crmService,
EmailHelper $emailHelper,
Activity $activity
): void {
$team = $activity->getTeam();
$user = $activity->getUser();
$participants = $activity->getParticipants();
foreach ($participants as $participant) {
if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {
continue;
}
$emailAddress = $participant->getEmailAddress();
if ($emailHelper->isCompanyEmail($team, $emailAddress)) {
continue;
}
try {
$opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());
} catch (Throwable $e) {
$this->error('Could not find opportunity: ' . $e->getMessage());
$opportunity = null;
}
if ($opportunity === null) {
$this->resetActivityOpportunity($activity);
continue;
}
$activity->update(['opportunity_id' => $opportunity->getId()]);
$this->info('Opportunity updated for activity: ' . $activity->getId());
}
}
private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity
{
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
$match = $decorator->matchExactlyByEmail($emailAddress, $userId);
if (empty($match)) {
$match = $decorator->matchByDomain($emailAddress, $userId);
}
if (empty($match)) {
return null;
}
[, , $opportunity, ,] = $match;
return $opportunity;
}
private function resetActivityOpportunity(Activity $activity): void
{
$this->info('Reset opportunity for activity: ' . $activity->getId());
$activity->update(['opportunity_id' => null]);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
43625
|
NULL
|
NULL
|
NULL
|
|
43628
|
1591
|
4
|
2026-05-14T13:03:03.818270+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763783818_m1.jpg...
|
PhpStorm
|
faVsco.js – ActivitiesMatchCrmCommand.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Pushed 1 commit to origin/JY-20903-update_activity Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change
text/html
text/html
text/html
View pull request
1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Activities;
use Illuminate\Support\Facades\Validator;
use Jiminny\Console\Commands\Command;
use Jiminny\Jobs\Crm\MatchActivityCrmData;
use Jiminny\Models\Activity;
use Jiminny\Models\Team;
use Symfony\Component\Console\Command\Command as CommandAlias;
class ActivitiesMatchCrmCommand extends Command
{
protected $signature = 'activity:match-crm
{--teamId=}
{--from=}
{--to=}
{--activityId=}
{--matchFromOtherCrm}
{--remoteSearch}
{--sync}
';
public function handle(): int
{
$teamId = $this->option('teamId');
$from = $this->option('from');
$to = $this->option('to');
$matchFromOtherCrm = $this->option('matchFromOtherCrm');
$remoteSearch = $this->option('remoteSearch');
$activityId = $this->option('activityId');
$validator = Validator::make(
[
'teamId' => $teamId,
'from' => $from,
'to' => $to,
'matchFromOtherCrm' => $matchFromOtherCrm,
'activityId' => $activityId,
'remoteSearch' => $remoteSearch,
],
[
'teamId' => ['required_without:activityId', 'numeric', 'nullable'],
'from' => ['required_without:activityId', 'date', 'nullable'],
'to' => ['required_without:activityId', 'date', 'nullable'],
'matchFromOtherCrm' => ['required', 'boolean'],
'remoteSearch' => ['required', 'boolean'],
'activityId' => ['numeric', 'nullable'],
]
);
if ($validator->fails()) {
$this->error('Validation failed:');
$this->output->block($validator->errors()->all());
return CommandAlias::FAILURE;
}
if ($activityId) {
$activity = Activity::find((int) $activityId);
if ($activity === null) {
$this->error('Cannot find activity.');
return CommandAlias::FAILURE;
}
$team = $activity->getTeam();
$this->info($activity->getTitle() . ' found.');
$activityIds = [$activity->getId()];
} else {
$team = Team::find($teamId);
if ($team === null) {
$this->error('Cannot find team.');
return CommandAlias::FAILURE;
}
$this->info($team->getName() . ' | matching activities from ' . $from . ' to ' . $to);
$activities = Activity::select('activities.id')
->join('users', 'activities.user_id', '=', 'users.id')
->where('users.team_id', '=', $team->getId())
->whereBetween('activities.created_at', [$from, $to]);
if ($matchFromOtherCrm) {
$activities->where('activities.crm_configuration_id', '!=', $team->getCrmConfigurationId());
}
$activityIds = $activities->pluck('id');
$this->info('Found activities: ' . $activityIds->count());
}
if (! $this->confirm('Do you want to continue?')) {
die();
}
foreach ($activityIds as $activityId) {
$this->dispatch(
new MatchActivityCrmData(
activityId: (int) $activityId,
fromConfiguration: $matchFromOtherCrm ? $team->getCrmConfiguration() : null,
remoteSearch: $remoteSearch,
)
);
}
return CommandAlias::SUCCESS;
}
}
Sync Changes
Hide This Notification...
|
[{"role":"AXTextField","text [{"role":"AXTextField","text":"Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change","depth":3,"on_screen":true,"value":"Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"View pull request","depth":2,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1 file committed","depth":2,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20903 revert changes in command","depth":3,"on_screen":true,"value":"JY-20903 revert changes in command","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"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":"#12077 on JY-20903-update_activity-stage-on…hange, menu","depth":5,"on_screen":true,"help_text":"Pull request #12077 exists for current branch JY-20903-update__activity-stage-on…hange","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":"4","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\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Jobs\\Crm\\MatchActivityCrmData;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Team;\nuse Symfony\\Component\\Console\\Command\\Command as CommandAlias;\n\nclass ActivitiesMatchCrmCommand extends Command\n{\n protected $signature = 'activity:match-crm\n {--teamId=}\n {--from=}\n {--to=}\n {--activityId=}\n {--matchFromOtherCrm}\n {--remoteSearch}\n {--sync}\n ';\n\n public function handle(): int\n {\n $teamId = $this->option('teamId');\n $from = $this->option('from');\n $to = $this->option('to');\n $matchFromOtherCrm = $this->option('matchFromOtherCrm');\n $remoteSearch = $this->option('remoteSearch');\n $activityId = $this->option('activityId');\n\n $validator = Validator::make(\n [\n 'teamId' => $teamId,\n 'from' => $from,\n 'to' => $to,\n 'matchFromOtherCrm' => $matchFromOtherCrm,\n 'activityId' => $activityId,\n 'remoteSearch' => $remoteSearch,\n ],\n [\n 'teamId' => ['required_without:activityId', 'numeric', 'nullable'],\n 'from' => ['required_without:activityId', 'date', 'nullable'],\n 'to' => ['required_without:activityId', 'date', 'nullable'],\n 'matchFromOtherCrm' => ['required', 'boolean'],\n 'remoteSearch' => ['required', 'boolean'],\n 'activityId' => ['numeric', 'nullable'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return CommandAlias::FAILURE;\n }\n\n if ($activityId) {\n $activity = Activity::find((int) $activityId);\n if ($activity === null) {\n $this->error('Cannot find activity.');\n\n return CommandAlias::FAILURE;\n }\n $team = $activity->getTeam();\n $this->info($activity->getTitle() . ' found.');\n\n $activityIds = [$activity->getId()];\n } else {\n $team = Team::find($teamId);\n if ($team === null) {\n $this->error('Cannot find team.');\n\n return CommandAlias::FAILURE;\n }\n\n $this->info($team->getName() . ' | matching activities from ' . $from . ' to ' . $to);\n\n $activities = Activity::select('activities.id')\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->where('users.team_id', '=', $team->getId())\n ->whereBetween('activities.created_at', [$from, $to]);\n if ($matchFromOtherCrm) {\n $activities->where('activities.crm_configuration_id', '!=', $team->getCrmConfigurationId());\n }\n\n $activityIds = $activities->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n }\n\n if (! $this->confirm('Do you want to continue?')) {\n die();\n }\n\n foreach ($activityIds as $activityId) {\n $this->dispatch(\n new MatchActivityCrmData(\n activityId: (int) $activityId,\n fromConfiguration: $matchFromOtherCrm ? $team->getCrmConfiguration() : null,\n remoteSearch: $remoteSearch,\n )\n );\n }\n\n return CommandAlias::SUCCESS;\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Jobs\\Crm\\MatchActivityCrmData;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Team;\nuse Symfony\\Component\\Console\\Command\\Command as CommandAlias;\n\nclass ActivitiesMatchCrmCommand extends Command\n{\n protected $signature = 'activity:match-crm\n {--teamId=}\n {--from=}\n {--to=}\n {--activityId=}\n {--matchFromOtherCrm}\n {--remoteSearch}\n {--sync}\n ';\n\n public function handle(): int\n {\n $teamId = $this->option('teamId');\n $from = $this->option('from');\n $to = $this->option('to');\n $matchFromOtherCrm = $this->option('matchFromOtherCrm');\n $remoteSearch = $this->option('remoteSearch');\n $activityId = $this->option('activityId');\n\n $validator = Validator::make(\n [\n 'teamId' => $teamId,\n 'from' => $from,\n 'to' => $to,\n 'matchFromOtherCrm' => $matchFromOtherCrm,\n 'activityId' => $activityId,\n 'remoteSearch' => $remoteSearch,\n ],\n [\n 'teamId' => ['required_without:activityId', 'numeric', 'nullable'],\n 'from' => ['required_without:activityId', 'date', 'nullable'],\n 'to' => ['required_without:activityId', 'date', 'nullable'],\n 'matchFromOtherCrm' => ['required', 'boolean'],\n 'remoteSearch' => ['required', 'boolean'],\n 'activityId' => ['numeric', 'nullable'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return CommandAlias::FAILURE;\n }\n\n if ($activityId) {\n $activity = Activity::find((int) $activityId);\n if ($activity === null) {\n $this->error('Cannot find activity.');\n\n return CommandAlias::FAILURE;\n }\n $team = $activity->getTeam();\n $this->info($activity->getTitle() . ' found.');\n\n $activityIds = [$activity->getId()];\n } else {\n $team = Team::find($teamId);\n if ($team === null) {\n $this->error('Cannot find team.');\n\n return CommandAlias::FAILURE;\n }\n\n $this->info($team->getName() . ' | matching activities from ' . $from . ' to ' . $to);\n\n $activities = Activity::select('activities.id')\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->where('users.team_id', '=', $team->getId())\n ->whereBetween('activities.created_at', [$from, $to]);\n if ($matchFromOtherCrm) {\n $activities->where('activities.crm_configuration_id', '!=', $team->getCrmConfigurationId());\n }\n\n $activityIds = $activities->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n }\n\n if (! $this->confirm('Do you want to continue?')) {\n die();\n }\n\n foreach ($activityIds as $activityId) {\n $this->dispatch(\n new MatchActivityCrmData(\n activityId: (int) $activityId,\n fromConfiguration: $matchFromOtherCrm ? $team->getCrmConfiguration() : null,\n remoteSearch: $remoteSearch,\n )\n );\n }\n\n return CommandAlias::SUCCESS;\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}]...
|
7683757606334404006
|
-8740212531662190524
|
click
|
accessibility
|
NULL
|
Pushed 1 commit to origin/JY-20903-update_activity Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change
text/html
text/html
text/html
View pull request
1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Activities;
use Illuminate\Support\Facades\Validator;
use Jiminny\Console\Commands\Command;
use Jiminny\Jobs\Crm\MatchActivityCrmData;
use Jiminny\Models\Activity;
use Jiminny\Models\Team;
use Symfony\Component\Console\Command\Command as CommandAlias;
class ActivitiesMatchCrmCommand extends Command
{
protected $signature = 'activity:match-crm
{--teamId=}
{--from=}
{--to=}
{--activityId=}
{--matchFromOtherCrm}
{--remoteSearch}
{--sync}
';
public function handle(): int
{
$teamId = $this->option('teamId');
$from = $this->option('from');
$to = $this->option('to');
$matchFromOtherCrm = $this->option('matchFromOtherCrm');
$remoteSearch = $this->option('remoteSearch');
$activityId = $this->option('activityId');
$validator = Validator::make(
[
'teamId' => $teamId,
'from' => $from,
'to' => $to,
'matchFromOtherCrm' => $matchFromOtherCrm,
'activityId' => $activityId,
'remoteSearch' => $remoteSearch,
],
[
'teamId' => ['required_without:activityId', 'numeric', 'nullable'],
'from' => ['required_without:activityId', 'date', 'nullable'],
'to' => ['required_without:activityId', 'date', 'nullable'],
'matchFromOtherCrm' => ['required', 'boolean'],
'remoteSearch' => ['required', 'boolean'],
'activityId' => ['numeric', 'nullable'],
]
);
if ($validator->fails()) {
$this->error('Validation failed:');
$this->output->block($validator->errors()->all());
return CommandAlias::FAILURE;
}
if ($activityId) {
$activity = Activity::find((int) $activityId);
if ($activity === null) {
$this->error('Cannot find activity.');
return CommandAlias::FAILURE;
}
$team = $activity->getTeam();
$this->info($activity->getTitle() . ' found.');
$activityIds = [$activity->getId()];
} else {
$team = Team::find($teamId);
if ($team === null) {
$this->error('Cannot find team.');
return CommandAlias::FAILURE;
}
$this->info($team->getName() . ' | matching activities from ' . $from . ' to ' . $to);
$activities = Activity::select('activities.id')
->join('users', 'activities.user_id', '=', 'users.id')
->where('users.team_id', '=', $team->getId())
->whereBetween('activities.created_at', [$from, $to]);
if ($matchFromOtherCrm) {
$activities->where('activities.crm_configuration_id', '!=', $team->getCrmConfigurationId());
}
$activityIds = $activities->pluck('id');
$this->info('Found activities: ' . $activityIds->count());
}
if (! $this->confirm('Do you want to continue?')) {
die();
}
foreach ($activityIds as $activityId) {
$this->dispatch(
new MatchActivityCrmData(
activityId: (int) $activityId,
fromConfiguration: $matchFromOtherCrm ? $team->getCrmConfiguration() : null,
remoteSearch: $remoteSearch,
)
);
}
return CommandAlias::SUCCESS;
}
}
Sync Changes
Hide This Notification...
|
43626
|
NULL
|
NULL
|
NULL
|
|
43629
|
1592
|
3
|
2026-05-14T13:03:03.827701+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763783827_m2.jpg...
|
PhpStorm
|
faVsco.js – ActivitiesMatchCrmCommand.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pushed 1 commit to origin/JY-20903-update_activity Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change
text/html
text/html
text/html
View pull request
1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'...
|
[{"role":"AXTextField","text [{"role":"AXTextField","text":"Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change","depth":3,"bounds":{"left":0.8753325,"top":0.82521945,"width":0.11037234,"height":0.040702313},"on_screen":true,"value":"Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.82521945,"width":0.10305851,"height":0.040702313},"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"View pull request","depth":2,"bounds":{"left":0.8753325,"top":0.87150836,"width":0.03523936,"height":0.013567438},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1 file committed","depth":2,"bounds":{"left":0.8753325,"top":0.91300875,"width":0.100398935,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20903 revert changes in command","depth":3,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.11037234,"height":0.013567438},"on_screen":true,"value":"JY-20903 revert changes in command","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.0787899,"height":0.013567438},"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"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":"#12077 on JY-20903-update_activity-stage-on…hange, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12566489,"height":0.025538707},"on_screen":true,"help_text":"Pull request #12077 exists for current branch JY-20903-update__activity-stage-on…hange","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}]...
|
-5456309374881777246
|
-7380058956750977578
|
click
|
accessibility
|
NULL
|
Pushed 1 commit to origin/JY-20903-update_activity Pushed 1 commit to origin/JY-20903-update_activity-stage-on-opportunity-change
text/html
text/html
text/html
View pull request
1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43630
|
1592
|
4
|
2026-05-14T13:03:06.544242+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763786544_m2.jpg...
|
PhpStorm
|
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project Files
Preview
Filter
Open in Find Tool Win Project Files
Preview
Filter
Open in Find Tool Window
Services/Crm/Hubspot/Service.php
Service.php .../app/Services/Crm/Hubspot/Service.php, class
ServiceTest.php .../tests/Unit/Services/Crm/Hubspot/ServiceTest.php, final class
ServiceResponseNormalizeTest.php .../tests/Unit/Services/Crm/Hubspot/ServiceResponseNormalizeTest.php, class
Service.php.html build/coverage/Services/Crm/Hubspot
DealFieldsService.php .../app/Services/Crm/Hubspot/DealFieldsService.php
BatchSyncRedisService.php .../app/Services/Crm/Hubspot/BatchSyncRedisService.php, class
ClosedDealStagesService.php .../app/Services/Crm/Hubspot/ClosedDealStagesService.php, class
HubspotPaginationService.php .../app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php, class
DealFieldsServiceTest.php .../tests/Unit/Services/Crm/Hubspot/DealFieldsServiceTest.php, class
HubspotDealWebhookService.php .../app/Services/Crm/Hubspot/Journal/HubspotDealWebhookService.php
HubspotJournalPollingService.php .../app/Services/Crm/Hubspot/Journal/HubspotJournalPollingService.php, class
HubspotWebhookMetricsService.php .../app/Services/Crm/Hubspot/Webhook/HubspotWebhookMetricsService.php, class
BatchSyncRedisServiceTest.php .../tests/Unit/Services/Crm/Hubspot/BatchSyncRedisServiceTest.php, class
ClosedDealStagesServiceTest.php .../tests/Unit/Services/Crm/Hubspot/ClosedDealStagesServiceTest.php, class
HubspotWebhookSubscriptionService.php .../app/.../Crm/Hubspot/Journal/HubspotWebhookSubscriptionService.php, class
… more
Service.php .../app/Services/Crm/Hubspot/Service.php, class
ServiceTest.php .../tests/Unit/Services/Crm/Hubspot/ServiceTest.php, final class
ServiceResponseNormalizeTest.php .../tests/Unit/Services/Crm/Hubspot/ServiceResponseNormalizeTest.php, class
Service.php.html build/coverage/Services/Crm/Hubspot
DealFieldsService.php .../app/Services/Crm/Hubspot/DealFieldsService.php
BatchSyncRedisService.php .../app/Services/Crm/Hubspot/BatchSyncRedisService.php, class
ClosedDealStagesService.php .../app/Services/Crm/Hubspot/ClosedDealStagesService.php, class
HubspotPaginationService.php .../app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php, class
DealFieldsServiceTest.php .../tests/Unit/Services/Crm/Hubspot/DealFieldsServiceTest.php, class
HubspotDealWebhookService.php .../app/Services/Crm/Hubspot/Journal/HubspotDealWebhookService.php
HubspotJournalPollingService.php .../app/Services/Crm/Hubspot/Journal/HubspotJournalPollingService.php, class...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project Files","depth":2,"bounds":{"left":0.6968085,"top":0.24181964,"width":0.03557181,"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","depth":2,"bounds":{"left":0.73238033,"top":0.24181964,"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":"Filter","depth":2,"bounds":{"left":0.74102396,"top":0.24181964,"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":"Open in Find Tool Window","depth":2,"bounds":{"left":0.7496675,"top":0.24181964,"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":"AXTextField","text":"Services/Crm/Hubspot/Service.php","depth":1,"bounds":{"left":0.50232714,"top":0.27214685,"width":0.25598404,"height":0.023144454},"on_screen":true,"value":"Services/Crm/Hubspot/Service.php","role_description":"text field","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Service.php .../app/Services/Crm/Hubspot/Service.php, class","depth":2,"bounds":{"left":0.4993351,"top":0.30407023,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ServiceTest.php .../tests/Unit/Services/Crm/Hubspot/ServiceTest.php, final class","depth":2,"bounds":{"left":0.4993351,"top":0.3216281,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ServiceResponseNormalizeTest.php .../tests/Unit/Services/Crm/Hubspot/ServiceResponseNormalizeTest.php, class","depth":2,"bounds":{"left":0.4993351,"top":0.33918595,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Service.php.html build/coverage/Services/Crm/Hubspot","depth":2,"bounds":{"left":0.4993351,"top":0.3567438,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"DealFieldsService.php .../app/Services/Crm/Hubspot/DealFieldsService.php","depth":2,"bounds":{"left":0.4993351,"top":0.37430167,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"BatchSyncRedisService.php .../app/Services/Crm/Hubspot/BatchSyncRedisService.php, class","depth":2,"bounds":{"left":0.4993351,"top":0.39185953,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ClosedDealStagesService.php .../app/Services/Crm/Hubspot/ClosedDealStagesService.php, class","depth":2,"bounds":{"left":0.4993351,"top":0.4094174,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HubspotPaginationService.php .../app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php, class","depth":2,"bounds":{"left":0.4993351,"top":0.42697525,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"DealFieldsServiceTest.php .../tests/Unit/Services/Crm/Hubspot/DealFieldsServiceTest.php, class","depth":2,"bounds":{"left":0.4993351,"top":0.4445331,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HubspotDealWebhookService.php .../app/Services/Crm/Hubspot/Journal/HubspotDealWebhookService.php","depth":2,"bounds":{"left":0.4993351,"top":0.46209097,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HubspotJournalPollingService.php .../app/Services/Crm/Hubspot/Journal/HubspotJournalPollingService.php, class","depth":2,"bounds":{"left":0.4993351,"top":0.47964883,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HubspotWebhookMetricsService.php .../app/Services/Crm/Hubspot/Webhook/HubspotWebhookMetricsService.php, class","depth":2,"bounds":{"left":0.4993351,"top":0.49720672,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"BatchSyncRedisServiceTest.php .../tests/Unit/Services/Crm/Hubspot/BatchSyncRedisServiceTest.php, class","depth":2,"bounds":{"left":0.4993351,"top":0.51476455,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ClosedDealStagesServiceTest.php .../tests/Unit/Services/Crm/Hubspot/ClosedDealStagesServiceTest.php, class","depth":2,"bounds":{"left":0.4993351,"top":0.5323224,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HubspotWebhookSubscriptionService.php .../app/.../Crm/Hubspot/Journal/HubspotWebhookSubscriptionService.php, class","depth":2,"bounds":{"left":0.4993351,"top":0.54988027,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"… more","depth":2,"bounds":{"left":0.4993351,"top":0.5674381,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Service.php .../app/Services/Crm/Hubspot/Service.php, class","depth":4,"bounds":{"left":0.4993351,"top":0.30407023,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ServiceTest.php .../tests/Unit/Services/Crm/Hubspot/ServiceTest.php, final class","depth":4,"bounds":{"left":0.4993351,"top":0.3216281,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ServiceResponseNormalizeTest.php .../tests/Unit/Services/Crm/Hubspot/ServiceResponseNormalizeTest.php, class","depth":4,"bounds":{"left":0.4993351,"top":0.33918595,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Service.php.html build/coverage/Services/Crm/Hubspot","depth":4,"bounds":{"left":0.4993351,"top":0.3567438,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"DealFieldsService.php .../app/Services/Crm/Hubspot/DealFieldsService.php","depth":4,"bounds":{"left":0.4993351,"top":0.37430167,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"BatchSyncRedisService.php .../app/Services/Crm/Hubspot/BatchSyncRedisService.php, class","depth":4,"bounds":{"left":0.4993351,"top":0.39185953,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ClosedDealStagesService.php .../app/Services/Crm/Hubspot/ClosedDealStagesService.php, class","depth":4,"bounds":{"left":0.4993351,"top":0.4094174,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HubspotPaginationService.php .../app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php, class","depth":4,"bounds":{"left":0.4993351,"top":0.42697525,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"DealFieldsServiceTest.php .../tests/Unit/Services/Crm/Hubspot/DealFieldsServiceTest.php, class","depth":4,"bounds":{"left":0.4993351,"top":0.4445331,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HubspotDealWebhookService.php .../app/Services/Crm/Hubspot/Journal/HubspotDealWebhookService.php","depth":4,"bounds":{"left":0.4993351,"top":0.46209097,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HubspotJournalPollingService.php .../app/Services/Crm/Hubspot/Journal/HubspotJournalPollingService.php, class","depth":4,"bounds":{"left":0.4993351,"top":0.47964883,"width":0.26196808,"height":0.017557861},"on_screen":true,"role_description":"text"}]...
|
-2292188737818227141
|
50864151294179239
|
visual_change
|
accessibility
|
NULL
|
Project Files
Preview
Filter
Open in Find Tool Win Project Files
Preview
Filter
Open in Find Tool Window
Services/Crm/Hubspot/Service.php
Service.php .../app/Services/Crm/Hubspot/Service.php, class
ServiceTest.php .../tests/Unit/Services/Crm/Hubspot/ServiceTest.php, final class
ServiceResponseNormalizeTest.php .../tests/Unit/Services/Crm/Hubspot/ServiceResponseNormalizeTest.php, class
Service.php.html build/coverage/Services/Crm/Hubspot
DealFieldsService.php .../app/Services/Crm/Hubspot/DealFieldsService.php
BatchSyncRedisService.php .../app/Services/Crm/Hubspot/BatchSyncRedisService.php, class
ClosedDealStagesService.php .../app/Services/Crm/Hubspot/ClosedDealStagesService.php, class
HubspotPaginationService.php .../app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php, class
DealFieldsServiceTest.php .../tests/Unit/Services/Crm/Hubspot/DealFieldsServiceTest.php, class
HubspotDealWebhookService.php .../app/Services/Crm/Hubspot/Journal/HubspotDealWebhookService.php
HubspotJournalPollingService.php .../app/Services/Crm/Hubspot/Journal/HubspotJournalPollingService.php, class
HubspotWebhookMetricsService.php .../app/Services/Crm/Hubspot/Webhook/HubspotWebhookMetricsService.php, class
BatchSyncRedisServiceTest.php .../tests/Unit/Services/Crm/Hubspot/BatchSyncRedisServiceTest.php, class
ClosedDealStagesServiceTest.php .../tests/Unit/Services/Crm/Hubspot/ClosedDealStagesServiceTest.php, class
HubspotWebhookSubscriptionService.php .../app/.../Crm/Hubspot/Journal/HubspotWebhookSubscriptionService.php, class
… more
Service.php .../app/Services/Crm/Hubspot/Service.php, class
ServiceTest.php .../tests/Unit/Services/Crm/Hubspot/ServiceTest.php, final class
ServiceResponseNormalizeTest.php .../tests/Unit/Services/Crm/Hubspot/ServiceResponseNormalizeTest.php, class
Service.php.html build/coverage/Services/Crm/Hubspot
DealFieldsService.php .../app/Services/Crm/Hubspot/DealFieldsService.php
BatchSyncRedisService.php .../app/Services/Crm/Hubspot/BatchSyncRedisService.php, class
ClosedDealStagesService.php .../app/Services/Crm/Hubspot/ClosedDealStagesService.php, class
HubspotPaginationService.php .../app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php, class
DealFieldsServiceTest.php .../tests/Unit/Services/Crm/Hubspot/DealFieldsServiceTest.php, class
HubspotDealWebhookService.php .../app/Services/Crm/Hubspot/Journal/HubspotDealWebhookService.php
HubspotJournalPollingService.php .../app/Services/Crm/Hubspot/Journal/HubspotJournalPollingService.php, class...
|
43629
|
NULL
|
NULL
|
NULL
|
|
43631
|
1591
|
5
|
2026-05-14T13:03:08.966748+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763788966_m1.jpg...
|
PhpStorm
|
faVsco.js – Service.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
1 file committed
JY-20903 revert changes in comman 1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"1 file committed","depth":2,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20903 revert changes in command","depth":3,"on_screen":true,"value":"JY-20903 revert changes in command","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"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":"#12077 on JY-20903-update_activity-stage-on…hange, menu","depth":5,"on_screen":true,"help_text":"Pull request #12077 exists for current branch JY-20903-update__activity-stage-on…hange","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}]...
|
5894029797904591786
|
-8717346915791731262
|
click
|
hybrid
|
NULL
|
1 file committed
JY-20903 revert changes in comman 1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
SlackFileEditViewGoHistoryWindowHelpDescribe what you are looking forAneliya AngelovaMessagesAdd canvas@ Files+lhl100% C8• Thu 14 May 16:03:08HomeDMsActivityFilesLaterMoreJiminny ...scnicrat# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Direct messagesP. Aneliya Angelova€. Vasil Vasilev E. Galya Dimitrova&. Stefka Stoyanova: Todor StamatovMario GeorgievNikolay IvanovLo James Graham2 Stoyan TanevSteliyan GeorgievPetko KashinskiLukas Kovalik y...AppsToastJira Cloud6 0Monday, May 11th ~Today ~Aneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?при останалите CRMi трябва ръчно да се въведатLukas Kovalik 2:47 PMздрастиами не знам по принцип се вика при всичкитрябва да се за всички, някъде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725Jira CloudX Bug IV-20725 in Jira Cloud[HubSpot] Optimise CRM rematching on delete hubspot ac...StatusReady for QAPriority= MediumAssigneeAA Aneliya AngelovaAs of today at 4:00 PMOpen in Jirait SummariseLukas Kovalik 4:02 PMдазвьни направоMessage Aneliya Angelova...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43632
|
1592
|
5
|
2026-05-14T13:03:08.992816+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763788992_m2.jpg...
|
PhpStorm
|
faVsco.js – Service.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
1 file committed
JY-20903 revert changes in comman 1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"1 file committed","depth":2,"bounds":{"left":0.8753325,"top":0.91300875,"width":0.100398935,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20903 revert changes in command","depth":3,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.11037234,"height":0.013567438},"on_screen":true,"value":"JY-20903 revert changes in command","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.0787899,"height":0.013567438},"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"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":"#12077 on JY-20903-update_activity-stage-on…hange, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12566489,"height":0.025538707},"on_screen":true,"help_text":"Pull request #12077 exists for current branch JY-20903-update__activity-stage-on…hange","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}]...
|
-2882211440500900753
|
-8861532472595053376
|
click
|
hybrid
|
NULL
|
1 file committed
JY-20903 revert changes in comman 1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
PhostormINavicarecodeLaravelKeractorFV faVsco.js( #12077 on JY-20903-update_activity-stage-on...haProiectyUserinvitationdro.onp) CheckAndRetryRemoteMatch.php= custom.logscratch &.ison= laravel.l0gA SF jiminny@localhost]& ho_local Uiminny@localnost& console [PROD]> D Utils> D Webhook© BatchSyncCollector.phj© BatchSyncRedisServiceo ullentonec closeaDealstagesservi© DealFieldsService.phpc DecorateAcuivity.onp© FieldDefinitions.phpc rieldlypeconverter.ohg* HubspotClientinterfacec) Huospoul okenmanaderC) PavloadBuilder.ohp© RemoteCrmObiectMani@ ResponseNormalize.phtC) Service.oho@ SvncFieldAction.phpC) SuncRe atedActivitvMailLocal Chances• Chanaes 2 files.env.local appphp logging.php configUInvercioned Filec Q filesCo kematchactviyoncrmoojectbetach.ong© Service.php x© MatchActivityCrmData.phpA console (EU]tiò accounts [EU]ii stages (EU]tid teams (EU]ImporbotkecoraingJoo.pnp© Activity.php© FixActivitiesOpportunity.php x© Opportunity.php& console SlAGiNGclass service excenas baseservice imolemencsclass rixacciviclesupoorcunlcy excenas commanopubLic tunccion tinauoportunitles escrino scrmaccouncio, scrino scrmconcacclo, cant suserid = nulu. arriorivace tunccion processrarulcloancsSresults = Sthis->client->getPaginatedData(Spayload, type: 'deals'):Sopportunity = null;foreach (Sresults['results'] as Sobiect) {802Sorovertles = sobiectorovertles'=116-117if (Sopportunity === null) {$this->resetActivity0pportunity(Sactivity):Samount = null.Tі119if Cemotv(Soroperties|'amount') z== false) *concinue:Scurrencv = Soroberties 'deal currency code' ?? Sthis->confia->default currency:Sactivity->update(['opportunity_ id' => Sopportunity->getIdOl):808810// Values can contain commas and any junk so strip them.Svalue = (float) preg_replace( pattern: '/[^\d.]/',Samount = Formatcurrenev Svalte. Scurrenev).replacement:"', $properties('amount'])sthis->info( string: "Opportunity updated for activity: ' • Sactivity->getid):LO0 XISide-bv-side viewerDo not ignore₴ e883ed5b confia/lcurrent version<>×E.env.nikilocal appE.env.other app(@ CanAccessAiReportsTest.php tests/Unit/Policies© CreateMockAskJiminnyReportResultCommand.php app/Console/Commands/R_E favicon.ico publicE ids.txt appTa raw sal_query.sal app© SimulateWebhooksCommand.php app/Console/Commands/Crm/HubspotM+ WEBHOOK_FILTERING_IMPLEMENTATION.md apd"Level' = env'L0b LevaL', "1nt0')"nath = storage pathl' loas/Laravel.Lo0')cascadekell100% S2• Thu 14 May 16:03:08AskJiminnyReportActivityServiceTest vPipedrive SDK EvaluaActivity Stage DiscrerImport CRM Activity T+0 ..m 82^Caccade Code |*• ..Kick off a new project. Make changesdeross your entire codeoasecACtiVily stage Discrepancy AnalysisC Import CRM Activity Types• AM CMTAled weekly usage quota is exhausted. Purchase exttra usage to continue using premium models. Quota resets May 1/, 11:00where is+ <> Code SWE-1.61 difference'level' => env('LOG LEVEL', 'info').'path' => storage_path( 'logs/Laravel.log'),custom channel' =>'path' => storage_path('Logs/custom.log').evell => envic lod LEVEl info')# 1 file committedJY-20903 revert changes in commandEdit Commit Messaae.WN Windsurf Toams 700-41UTF.8io 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43633
|
1592
|
6
|
2026-05-14T13:03:11.416331+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763791416_m2.jpg...
|
PhpStorm
|
faVsco.js – Service.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
1 file committed
JY-20903 revert changes in comman 1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
7
51
1
33
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Hubspot;
use Carbon\Carbon;
use Exception;
use Generator;
use GuzzleHttp\Exception\RequestException;
use HubSpot\Client\Crm\Owners\Model\PublicOwner;
use Illuminate\Support\Facades\Cache;
use InvalidArgumentException;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Contracts\Services\Crm\ClientInterface;
use Jiminny\Contracts\Services\Crm\FetchRelatedActivityInterface;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\HubspotInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SavePlaybackLinkToCrmInterface;
use Jiminny\Contracts\Services\Crm\SendSummaryToCrmInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Contracts\ActivityContract;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\Layout;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Participant;
use Jiminny\Models\Playbook;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Repositories\ParticipantRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Hubspot\Actions\SyncArchivedProfilesAction;
use Jiminny\Services\Crm\Hubspot\Fields\ValueNormalizer;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\OpportunitySyncTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncCrmEntitiesTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncFieldsTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\WriteCrmTrait;
use Jiminny\Services\Crm\MatchDomainByEmailInterface;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\ResolveCompanyNameByEmailTrait;
use Jiminny\Utils\PlaybackUrlBuilder;
use Sentry;
use SevenShores\Hubspot\Exceptions\BadRequest;
use Throwable;
use UnexpectedValueException;
/**
* @phpstan-type CrmFieldDefinition array{
* name: string,
* label: string,
* description: string,
* type: string,
* fieldType: string,
* hidden: bool,
* showCurrencySymbol: bool,
* options: array<array{
* id: string,
* label: string,
* value?: string,
* }
*/
class Service extends BaseService implements
HubspotInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
SendSummaryToCrmInterface,
MatchDomainByEmailInterface,
SavePlaybackLinkToCrmInterface,
RemoteEntityManipulationInterface,
FetchRelatedActivityInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use ResolveCompanyNameByEmailTrait;
use SyncCrmEntitiesTrait;
use WriteCrmTrait;
use SyncFieldsTrait;
use OpportunitySyncTrait;
private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;
private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';
private const int BATCH_UPDATE_LIMIT = 100;
private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';
private const int TEN_SECONDLY_ROLLING_LIMIT = 10;
private const string CALLS_SEARCH_ENDPOINT = '[URL_WITH_CREDENTIALS] ClientInterface|Client
*/
protected $client;
protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;
protected CrmEntityRepository $crmEntityRepository;
protected ProspectPhotoPathService $prospectPhotoPathService;
private SyncFieldAction $syncFieldAction;
private PayloadBuilder $payloadBuilder;
private SyncRelatedActivityManager $syncRelatedActivityManager;
private SyncArchivedProfilesAction $syncArchivedProfilesAction;
private WebhookSyncBatchProcessor $batchProcessor;
public function __construct(
Client $client,
SyncFieldAction $syncFieldAction,
PayloadBuilder $payloadBuilder,
ProspectPhotoPathService $prospectPhotoPathService,
SyncArchivedProfilesAction $syncArchivedProfilesAction,
WebhookSyncBatchProcessor $batchProcessor,
) {
parent::__construct();
$this->client = $client;
$this->syncFieldAction = $syncFieldAction;
$this->prospectPhotoPathService = $prospectPhotoPathService;
$this->payloadBuilder = $payloadBuilder;
$this->syncArchivedProfilesAction = $syncArchivedProfilesAction;
$this->batchProcessor = $batchProcessor;
$this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->client,
]);
$this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [
'client' => $this->client,
'payloadBuilder' => $this->payloadBuilder,
'logger' => $this->logger,
]);
$this->crmEntityRepository = app(CrmEntityRepository::class);
$this->dealFieldsService = app(DealFieldsService::class);
}
public function getDisplayName(): string
{
return 'HubSpot';
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
$owner = $user->team->owner;
return $owner->getSocialAccount(SocialAccount::PROVIDER_HUBSPOT);
}
public function getClient(): Client
{
/** @var Client */
return $this->client;
}
/**
* Convert raw field data into a format compatible with CRM APIs.
*
* @param bool $internal Direction of the conversion.
* True is pulling from CRM, false normalize before sending to CRM.
*/
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return ValueNormalizer::normalize(
fieldType: $fieldType,
fieldValue: $fieldValue,
isInbound: $internal,
);
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
/** @var Field $activityField */
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'activityType',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
/**
* @inheritdoc
*/
public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
// Outcome should always be provided calls/meetings.
$fieldData = [
[
'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',
'object_type' => Field::OBJECT_TASK,
],
];
foreach ($fieldData as $data) {
$field = $this->config->fields()->where($data)->first();
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
}
return $fields;
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldData = FieldDefinitions::followupFieldsFilter();
foreach ($fieldData as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function syncField(Field $field): void
{
switch ($field->object_type) {
case Field::OBJECT_ACCOUNT:
$crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_CONTACT:
$crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_OPPORTUNITY:
$crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_TASK:
$this->syncSingleTaskField($field);
return;
default:
return;
}
$this->syncFieldAction->execute($field, $crmField->toArray());
}
/**
* @param array<array{
* id:string,
* label:string,
* value?:string
* }> $options
*
* @throws CrmException
*
* @return FieldData[]
*
*/
public function importPicklistValues(
Field $field,
array $options = [['id' => '', 'label' => '', 'value' => '']],
): array {
if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {
// We already have the options, no need to fetch them again
return $this->importOptions($field, $options);
}
$options = [];
switch ($field->getObjectType()) {
case Field::OBJECT_ACCOUNT:
$options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());
break;
case Field::OBJECT_CONTACT:
$options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());
break;
case Field::OBJECT_OPPORTUNITY:
// Hubspot has different endpoint for stages
$options = $this->getClient()->fetchOpportunityFieldOptions($field);
break;
case Field::OBJECT_TASK:
if ($field->getCrmProviderId() === 'disposition') {
$options = $this->getClient()->fetchDispositionFieldOptions();
} elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {
$options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);
}
break;
default:
$this->logger->warning('Invalid object type', [
'object_type' => $field->getObjectType(),
'field_id' => $field->getId(),
]);
throw new CrmException('Invalid object type');
}
return $this->importOptions($field, $options);
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
$missingStage = null;
try {
// Use the HubSpot API client instead of the SDK crmPipelines() method
$endpoint = self::getDealsPipelinesEndpoint();
$pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);
$pipelines = $pipelinesResponse->data->results;
} catch (RequestException|BadRequest $exception) {
throw $exception;
}
foreach ($pipelines as $pipeline) {
$stages = [];
// We create a business process to contain the pipeline, and store all stages against it.
$p = ResponseNormalize::normalizePipeline($pipeline);
// Create/update business process for this pipeline
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => $p['active'],
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
// Create/update record type clone
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'is_selectable' => $p['active'],
'business_process_id' => $businessProcess->id ?? null,
]);
// Stages - fetch all existing stages upfront to avoid N+1 queries
$existingStages = $this->config->stages()
->withTrashed()
->where('type', Stage::TYPE_OPPORTUNITY)
->get()
->keyBy('crm_provider_id');
foreach ($p['stages'] as $dealStage) {
$s = ResponseNormalize::normalizeDealStage($dealStage);
/** @var ?Stage $existingStage */
$existingStage = $existingStages->get($s['id']);
// Restore soft-deleted stages that are now active in HubSpot
if ($existingStage?->trashed() && $s['active']) {
$existingStage->restore();
}
// Upsert stage (updates soft-deleted records without restoring them)
$stage = $this->config->stages()->withTrashed()->updateOrCreate([
'crm_provider_id' => $s['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($s['label'], 0, 50),
'label' => mb_strimwidth($s['label'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $s['displayOrder'],
'is_selectable' => $s['active'],
'probability' => $s['probability'] * 100,
]);
if ($missingStageName === $s['id']) {
$missingStage = $stage;
}
$stages[] = $stage->id;
}
$businessProcess->stages()->sync($stages);
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
try {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
/** @var array<int, array<string, mixed>> */
return Cache::remember(
key: $this->team->getId() . $name . $count . $offset,
ttl: 300,
callback: function () use ($name, $offset, $count): array {
$data = [];
// Use the new V3 API to find contacts based on additional fields.
foreach (['companies', 'contacts'] as $objectType) {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
if ($crmAccountId === null) {
return $data;
}
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
$closedStages = $this->getClosedDealStages();
$payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(
$this->config,
$crmAccountId,
$closedStages,
);
$results = $this->client->getPaginatedData($payload, 'deals');
foreach ($results['results'] as $object) {
$properties = $object['properties'];
$amount = null;
if (empty($properties['amount']) === false) {
$currency = $properties['deal_currency_code'] ?? $this->config->default_currency;
// Values can contain commas and any junk so strip them.
$value = (float) preg_replace('/[^\d.]/', '', $properties['amount']);
$amount = formatCurrency($value, $currency);
}
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
if ($businessProcess === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
} else {
$stage = $businessProcess
->stages()
->where('crm_provider_id', $properties['dealstage'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages(null, $properties['dealstage']);
}
}
$recordType = null;
if ($businessProcess) {
$recordType = $businessProcess->recordTypes()->first();
}
$isWon = in_array($properties['dealstage'], $closedStages['won']);
$isLost = in_array($properties['dealstage'], $closedStages['lost']);
$record = [
'crmId' => $object['id'],
'name' => $properties['dealname'] ?? 'Unknown Deal',
'value' => $amount,
'won' => $isWon,
'closed' => $isWon || $isLost,
'stage' => [
'id' => $stage?->getUuid() ?? '',
'name' => $stage?->getName() ?? '',
],
];
if ($recordType) {
$record += [
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
}
if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
if (! empty($ownerData)) {
return $ownerData;
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(?string $objectType, string $objectId, ?string $opportunityId): array
{
$data = [];
switch ($objectType) {
case 'contact':
$hsObject = 'contact';
break;
case 'account':
$hsObject = 'company';
break;
default:
// This is a hack to prioritise and override a contact/company with a deal.
if ($opportunityId) {
$hsObject = 'deal';
$objectId = $opportunityId;
} else {
throw new InvalidArgumentException('Object type not supported.');
}
}
$engagementTypes = ['meetings', 'tasks'];
foreach ($engagementTypes as $engagementType) {
$payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);
$this->logger->info('[HubSpot] CRM Search requested', [
'request' => $payload,
]);
$engagements = $this->client->getPaginatedData($payload, $engagementType);
foreach ($engagements['results'] as $engagement) {
if ($engagementType == 'meetings') {
$title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';
} elseif ($engagementType == 'tasks') {
$title = $engagement['properties']['hs_task_subject'];
} else {
$title = 'Scheduled meeting';
}
$data[] = [
'crmId' => $engagement['id'],
'subject' => $title,
'due' => $engagement['properties']['hs_timestamp'],
'type' => $engagement['properties']['hs_activity_type'] ?? null,
];
}
}
usort($data, function ($item1, $item2) {
return $item2['due'] <=> $item1['due'];
});
return $data;
}
/**
* Try to find CRM Objects using email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$contactProperties = [
'email',
'firstname',
'lastname',
'country',
'phone',
'mobilephone',
'jobtitle',
'hubspot_owner_id',
'associatedcompanyid',
'photo',
];
$contact = null;
$account = null;
try {
$hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);
if ($hsContact) {
$contact = $this->importContact($hsContact);
$account = $contact->account;
}
$data = $this->convertCrmData($contact, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
} catch (BadRequest $e) {
$this->logger->warning('[HubSpot] Search failed', [
'team_id' => $this->team->getId(),
'search_identifier' => $email,
'reason' => $e->getMessage(),
]);
}
return null;
}
public function getDomain(string $email): ?string
{
return $this->getDomainFromEmail($email);
}
/**
* Try to find CRM objects using domain name of the email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByDomain(string $domain, ?int $userId = null): ?array
{
$companyName = $domain;
// Try to find a company matching their email domain.
$companyProperties = [
'country',
'phone',
'name',
'hs_avatar_filemanager_key',
'industry',
'hubspot_owner_id',
'domain',
];
try {
$hsAccounts = $this->client
->getInstance()
->companies()
->searchByDomain($companyName, $companyProperties);
} catch (Throwable $e) {
$this->logger->info('[HubSpot] Search failed', [
'error' => $e->getMessage(),
'domain' => $domain,
]);
return null;
}
$account = null;
// If there are multiple accounts, don't guess, we'll ask later.
if (\count($hsAccounts->data->results) === 1) {
// Persist this remote object.
$account = $this->syncAccount($hsAccounts->data->results[0]->companyId);
}
$data = $this->convertCrmData(null, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
}
/**
* @return array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array
{
$countryCode = null;
if ($contact && $contact->country_code) {
$countryCode = $contact->country_code;
} elseif ($account && $account->country_code) {
$countryCode = $account->country_code;
}
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
// If there are multiple opportunities, don't guess, we'll ask later.
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
protected function getCacheKey(string $object, ?int $userId = null): ?string
{
$key = $this->team->getId() . $object;
$keySuffix = $this->getOwnerKeySuffix($userId);
return $key . $keySuffix;
}
private function getOwnerKeySuffix(?int $userId = null): string
{
return $userId === null ? '' : (string) $userId;
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array
{
if (str_contains($phone, '**')) {
return null;
}
// trim all whitespaces if present so the lookup doesn't fail
$phone = str_replace(' ', '', $phone);
// Check if the user is internal.
if ($this->isPhoneNumberOfTeamMember($phone)) {
return null;
}
$response = $this->searchForPhoneNumber($phone);
if (empty($response)) {
return null;
}
// This would ideally importContact instead but the response type differs.
$contact = $this->findAndSyncContact($response['results'][0]['id']);
if (! $contact instanceof Contact) {
return null;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account?->crm_provider_id,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
try {
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
} catch (Exception $e) {
$this->logger->debug('[HubSpot] Opportunity failed to sync.', [
'reason' => $e->getMessage(),
]);
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
private function isPhoneNumberOfTeamMember(string $phone): bool
{
$teamRepository = app(TeamRepository::class);
$user = $teamRepository->findTeamMemberByPhone($this->team, $phone);
if ($user instanceof User) {
return true;
}
return false;
}
private function findAndSyncContact(string $crmId): ?Contact
{
try {
return $this->syncContact($crmId);
} catch (Exception $exception) {
$this->logger->info('[HubSpot] Phone match failed', [
'reason' => $exception->getMessage(),
]);
return null;
}
}
private function hasResults(array $response): bool
{
return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;
}
private function searchForPhoneNumber(string $phone): array
{
// Normalizes the provided phone number for the API search.
$normalizedPhone = $this->normalizePhoneNumber($phone);
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);
$this->logger->info('[HubSpot] Phone match search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);
if (! $this->hasResults($response)) {
$nationalPhone = preg_replace('/\D/', '', phone_national(null, $phone));
$payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);
$this->logger->info('[HubSpot] Phone match national number search triggered', [
'phone' => $phone,
'nationalPhone' => $nationalPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
if (! $this->hasResults($response)) {
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);
$this->logger->info('[HubSpot] Phone match alternative search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
return $this->hasResults($response) ? $response : [];
}
private function handlePhoneSearchRequest(string $phone, array $payload): array
{
$endpoint = '[URL_WITH_CREDENTIALS] null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByName(string $name, ?int $userId = null): ?array
{
// Don't waste time searching for single character strings.
if (\strlen($name) <= 1) {
return null;
}
$cacheKey = $this->getCacheKey($name, $userId);
$result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {
$payload = $this->payloadBuilder->generateSearchContactsByNamePayload(
$name,
$this->getContactFields()
);
$hsContacts = $this->client->getPaginatedData($payload, 'contact');
if (empty($hsContacts['results'])) {
return false;
}
$contact = $this->importContact($hsContacts['results'][0]);
if ($contact === null) {
return false;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
});
return is_array($result) ? $result : null;
}
private function convertActivityAssociations(Activity $activity): array
{
return [
'contactIds' => $this->getParticipantsIds($activity),
'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],
'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],
'ownerIds' => [],
];
}
private function getParticipantsIds(Activity $activity): array
{
$attendees = [];
$participantRepository = app(ParticipantRepository::class);
$participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);
foreach ($participants as $participant) {
if ($participant->user_id || $participant->isCoach()) {
continue;
}
$contact = $participant->contact()->first();
if ($contact && $contact->crm_provider_id) {
$attendees[] = $contact->crm_provider_id;
} else {
if (! empty($participant->name)) {
$attendeeData = $this->fetchMissingAttendeeInfo($participant);
}
if (! empty($attendeeData['id'])) {
$attendees[] = $attendeeData['id'];
}
}
}
if ($activity->hasContact()) {
$attendees[] = $activity->contact->crm_provider_id;
}
return array_unique($attendees);
}
private function fetchMissingAttendeeInfo(Participant $participant): array
{
// Check if we need to look inside an account context.
$activity = $participant->getActivity();
$companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;
// First check the local data.
/** @var Contact[] $contacts */
$contacts = $this->team->contacts()
->with('account')
->where('name', $participant->name)
->whereNotNull('email')
->get();
foreach ($contacts as $contact) {
// If we have a company in scope, check the contact is associated to it.
if (
$companyId !== null
&& ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)
) {
continue;
}
return [
'id' => $contact->crm_provider_id,
'email' => $contact->email,
];
}
$payload = $this->generateNameSearchPayload($participant->name, 0, 20);
try {
$response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);
// TODO add some logic to choose the most suitable contact if multiple
foreach ($response['results'] as $object) {
$properties = $object['properties'];
if (empty($object['properties']) === false) {
// Check the company matches the contact.
// Todo: Move this check inside the API search.
if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {
continue;
}
return [
'id' => $object['id'],
'email' => $properties['email'],
];
}
}
} catch (Exception $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [
'teamId' => $this->team->id_string,
'request' => $payload,
'reason' => $e->getMessage(),
]);
}
return [];
}
/**
* Store transcripts as note engagement.
*
* @throws Exception
*/
public function createTranscriptNotes(Activity $activity): void
{
// For HS no need to check if Crm profile - Log Notes field is enabled
// We only check if store_transcript toggle is enabled on crm profile.
$engagement = [
'active' => true,
'ownerId' => $this->profile->crm_provider_i...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"1 file committed","depth":2,"bounds":{"left":0.8753325,"top":0.91300875,"width":0.100398935,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20903 revert changes in command","depth":3,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.11037234,"height":0.013567438},"on_screen":true,"value":"JY-20903 revert changes in command","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.0787899,"height":0.013567438},"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"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":"#12077 on JY-20903-update_activity-stage-on…hange, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12566489,"height":0.025538707},"on_screen":true,"help_text":"Pull request #12077 exists for current branch JY-20903-update__activity-stage-on…hange","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":"7","depth":4,"bounds":{"left":0.34175533,"top":0.12529927,"width":0.0076462766,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"51","depth":4,"bounds":{"left":0.35139626,"top":0.12529927,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.36303192,"top":0.12529927,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"33","depth":4,"bounds":{"left":0.3723404,"top":0.12529927,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.38464096,"top":0.12529927,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.39361703,"top":0.123703115,"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.40093085,"top":0.123703115,"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\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse Generator;\nuse GuzzleHttp\\Exception\\RequestException;\nuse HubSpot\\Client\\Crm\\Owners\\Model\\PublicOwner;\nuse Illuminate\\Support\\Facades\\Cache;\nuse InvalidArgumentException;\nuse Jiminny\\Contracts\\Repositories\\TeamRepository;\nuse Jiminny\\Contracts\\Services\\Crm\\ClientInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\FetchRelatedActivityInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\HubspotInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SavePlaybackLinkToCrmInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SendSummaryToCrmInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Contracts\\ActivityContract;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\Layout;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Participant;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Repositories\\ParticipantRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Hubspot\\Actions\\SyncArchivedProfilesAction;\nuse Jiminny\\Services\\Crm\\Hubspot\\Fields\\ValueNormalizer;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\OpportunitySyncTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\SyncCrmEntitiesTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\SyncFieldsTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\WriteCrmTrait;\nuse Jiminny\\Services\\Crm\\MatchDomainByEmailInterface;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Services\\Crm\\ResolveCompanyNameByEmailTrait;\nuse Jiminny\\Utils\\PlaybackUrlBuilder;\nuse Sentry;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse Throwable;\nuse UnexpectedValueException;\n\n/**\n * @phpstan-type CrmFieldDefinition array{\n * name: string,\n * label: string,\n * description: string,\n * type: string,\n * fieldType: string,\n * hidden: bool,\n * showCurrencySymbol: bool,\n * options: array<array{\n * id: string,\n * label: string,\n * value?: string,\n * }\n */\nclass Service extends BaseService implements\n HubspotInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n SendSummaryToCrmInterface,\n MatchDomainByEmailInterface,\n SavePlaybackLinkToCrmInterface,\n RemoteEntityManipulationInterface,\n FetchRelatedActivityInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n VerifyTaskExistsInterface\n{\n use ResolveCompanyNameByEmailTrait;\n use SyncCrmEntitiesTrait;\n use WriteCrmTrait;\n use SyncFieldsTrait;\n use OpportunitySyncTrait;\n\n private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;\n\n private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';\n private const int BATCH_UPDATE_LIMIT = 100;\n private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';\n private const int TEN_SECONDLY_ROLLING_LIMIT = 10;\n private const string CALLS_SEARCH_ENDPOINT = 'https://api.hubapi.com/crm/v3/objects/calls/search';\n\n private const string TYPE_NOTE = 'NOTE';\n\n private const string TYPE_MEETING = 'MEETING';\n\n private const string TYPE_CALL = 'CALL';\n\n private const string API_URL = 'https://api.hubapi.com';\n\n // NB: v1 is legacy - v3 is the newest\n private const string ENDPOINT_PIPELINES = '/crm-pipelines/v1/pipelines/';\n private const string PIPELINE_OBJECT_TYPE_DEALS = 'deals';\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n /**\n * @var ClientInterface|Client\n */\n protected $client;\n protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;\n protected CrmEntityRepository $crmEntityRepository;\n protected ProspectPhotoPathService $prospectPhotoPathService;\n\n private SyncFieldAction $syncFieldAction;\n private PayloadBuilder $payloadBuilder;\n private SyncRelatedActivityManager $syncRelatedActivityManager;\n private SyncArchivedProfilesAction $syncArchivedProfilesAction;\n private WebhookSyncBatchProcessor $batchProcessor;\n\n public function __construct(\n Client $client,\n SyncFieldAction $syncFieldAction,\n PayloadBuilder $payloadBuilder,\n ProspectPhotoPathService $prospectPhotoPathService,\n SyncArchivedProfilesAction $syncArchivedProfilesAction,\n WebhookSyncBatchProcessor $batchProcessor,\n ) {\n parent::__construct();\n\n $this->client = $client;\n $this->syncFieldAction = $syncFieldAction;\n $this->prospectPhotoPathService = $prospectPhotoPathService;\n $this->payloadBuilder = $payloadBuilder;\n $this->syncArchivedProfilesAction = $syncArchivedProfilesAction;\n $this->batchProcessor = $batchProcessor;\n $this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->client,\n ]);\n $this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [\n 'client' => $this->client,\n 'payloadBuilder' => $this->payloadBuilder,\n 'logger' => $this->logger,\n ]);\n $this->crmEntityRepository = app(CrmEntityRepository::class);\n $this->dealFieldsService = app(DealFieldsService::class);\n }\n\n public function getDisplayName(): string\n {\n return 'HubSpot';\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n $owner = $user->team->owner;\n\n return $owner->getSocialAccount(SocialAccount::PROVIDER_HUBSPOT);\n }\n\n public function getClient(): Client\n {\n /** @var Client */\n return $this->client;\n }\n\n /**\n * Convert raw field data into a format compatible with CRM APIs.\n *\n * @param bool $internal Direction of the conversion.\n * True is pulling from CRM, false normalize before sending to CRM.\n */\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return ValueNormalizer::normalize(\n fieldType: $fieldType,\n fieldValue: $fieldValue,\n isInbound: $internal,\n );\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n /** @var Field $activityField */\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'activityType',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n // Outcome should always be provided calls/meetings.\n $fieldData = [\n [\n 'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',\n 'object_type' => Field::OBJECT_TASK,\n ],\n ];\n\n foreach ($fieldData as $data) {\n $field = $this->config->fields()->where($data)->first();\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n }\n\n return $fields;\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n $fieldData = FieldDefinitions::followupFieldsFilter();\n\n foreach ($fieldData as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function syncField(Field $field): void\n {\n switch ($field->object_type) {\n case Field::OBJECT_ACCOUNT:\n $crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_CONTACT:\n $crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_OPPORTUNITY:\n $crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_TASK:\n $this->syncSingleTaskField($field);\n\n return;\n default:\n return;\n }\n\n $this->syncFieldAction->execute($field, $crmField->toArray());\n }\n\n /**\n * @param array<array{\n * id:string,\n * label:string,\n * value?:string\n * }> $options\n *\n * @throws CrmException\n *\n * @return FieldData[]\n *\n */\n public function importPicklistValues(\n Field $field,\n array $options = [['id' => '', 'label' => '', 'value' => '']],\n ): array {\n if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {\n // We already have the options, no need to fetch them again\n return $this->importOptions($field, $options);\n }\n\n $options = [];\n\n switch ($field->getObjectType()) {\n case Field::OBJECT_ACCOUNT:\n $options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());\n\n break;\n\n case Field::OBJECT_CONTACT:\n $options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());\n\n break;\n\n case Field::OBJECT_OPPORTUNITY:\n // Hubspot has different endpoint for stages\n $options = $this->getClient()->fetchOpportunityFieldOptions($field);\n\n break;\n\n case Field::OBJECT_TASK:\n if ($field->getCrmProviderId() === 'disposition') {\n $options = $this->getClient()->fetchDispositionFieldOptions();\n } elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {\n $options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);\n }\n\n break;\n\n default:\n $this->logger->warning('Invalid object type', [\n 'object_type' => $field->getObjectType(),\n 'field_id' => $field->getId(),\n ]);\n\n throw new CrmException('Invalid object type');\n }\n\n return $this->importOptions($field, $options);\n }\n\n /**\n * @inheritdoc\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n $missingStage = null;\n\n try {\n // Use the HubSpot API client instead of the SDK crmPipelines() method\n $endpoint = self::getDealsPipelinesEndpoint();\n $pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);\n $pipelines = $pipelinesResponse->data->results;\n } catch (RequestException|BadRequest $exception) {\n throw $exception;\n }\n\n foreach ($pipelines as $pipeline) {\n $stages = [];\n\n // We create a business process to contain the pipeline, and store all stages against it.\n $p = ResponseNormalize::normalizePipeline($pipeline);\n\n // Create/update business process for this pipeline\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => $p['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($p['label'], 0, 150),\n 'type' => BusinessProcess::TYPE_OPPORTUNITY,\n 'is_selectable' => $p['active'],\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n // Create/update record type clone\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => $p['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($p['label'], 0, 150),\n 'is_selectable' => $p['active'],\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n // Stages - fetch all existing stages upfront to avoid N+1 queries\n $existingStages = $this->config->stages()\n ->withTrashed()\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->get()\n ->keyBy('crm_provider_id');\n\n foreach ($p['stages'] as $dealStage) {\n $s = ResponseNormalize::normalizeDealStage($dealStage);\n\n /** @var ?Stage $existingStage */\n $existingStage = $existingStages->get($s['id']);\n\n // Restore soft-deleted stages that are now active in HubSpot\n if ($existingStage?->trashed() && $s['active']) {\n $existingStage->restore();\n }\n\n // Upsert stage (updates soft-deleted records without restoring them)\n $stage = $this->config->stages()->withTrashed()->updateOrCreate([\n 'crm_provider_id' => $s['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($s['label'], 0, 50),\n 'label' => mb_strimwidth($s['label'], 0, 191),\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'sequence' => $s['displayOrder'],\n 'is_selectable' => $s['active'],\n 'probability' => $s['probability'] * 100,\n ]);\n\n if ($missingStageName === $s['id']) {\n $missingStage = $stage;\n }\n\n $stages[] = $stage->id;\n }\n\n $businessProcess->stages()->sync($stages);\n }\n\n return $missingStage;\n }\n\n /**\n * @inheritdoc\n */\n public function syncOrganization(): void\n {\n try {\n $endpoint = 'https://api.hubapi.com/integrations/v1/me';\n $response = $this->client->getInstance()->getClient()->request('get', $endpoint);\n\n $accountData = $response->data;\n $this->config->update(['default_currency' => $accountData->currency]);\n } catch (BadRequest $e) {\n throw new CrmException('Could not sync the organization.', $e->getCode(), $e);\n }\n }\n\n /**\n * @inheritdoc\n *\n * @throws CrmException\n */\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n $this->syncArchivedProfilesAction->execute($this->team, $this->client, $this->config);\n\n try {\n $owners = $this->client->getOwners();\n } catch (\\HubSpot\\Client\\Crm\\Owners\\ApiException $e) {\n $this->handleOwnersApiException($e);\n }\n\n $profileRepository = app(ProfileRepository::class);\n $teamRepository = app(TeamRepository::class);\n\n foreach ($owners as $owner) {\n $profile = $this->processOwner($owner, $teamRepository, $profileRepository);\n\n if ($profile && $userToSearch && $userToSearch->getId() === $profile->getUserId()) {\n return $profile;\n }\n }\n\n return null;\n }\n\n private function handleOwnersApiException(\\HubSpot\\Client\\Crm\\Owners\\ApiException $e): never\n {\n $statusCode = $e->getCode();\n $errorMessage = $e->getMessage();\n $responseBody = $this->parseResponseBody($e->getResponseBody());\n\n $isPermissionError = $this->isPermissionError($statusCode, $errorMessage, $responseBody);\n\n $logContext = [\n 'team_id' => $this->team->getId(),\n 'team_uuid' => $this->team->getUuid(),\n 'config_id' => $this->config->getId(),\n 'status_code' => $statusCode,\n 'error_message' => $errorMessage,\n 'response_body' => $responseBody,\n ];\n\n if ($isPermissionError) {\n $this->logPermissionError($logContext);\n } else {\n $this->logger->error('[HubSpot] Could not sync the profiles.', $logContext);\n }\n\n throw new CrmException('Could not sync the profiles.', $e->getCode(), $e);\n }\n\n private function parseResponseBody(?string $rawBody): ?array\n {\n if ($rawBody === null || $rawBody === '') {\n return null;\n }\n\n try {\n return json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR);\n } catch (\\JsonException) {\n return null;\n }\n }\n\n private function logPermissionError(array $logContext): void\n {\n $this->logger->critical(\n '[HubSpot] ⚠️ PERMISSION ERROR: Cannot sync profiles - Missing OAuth scopes',\n array_merge($logContext, [\n 'action_required' => 'Request additional HubSpot OAuth scopes',\n 'required_scope' => 'crm.objects.owners.read',\n 'impact' => 'Opportunities will have owner_id but NO user_id - AI automation and reporting will fail',\n 'resolution' => 'Manually request scope from HubSpot account admin or re-authenticate',\n ])\n );\n }\n\n private function processOwner(\n PublicOwner $owner,\n TeamRepository $teamRepository,\n ProfileRepository $profileRepository\n ): ?Profile {\n if ($owner->getArchived()) {\n $this->logger->warning('[HubSpot] Found archived owner', [\n 'crm_provider_id' => $owner->getId(),\n 'email' => $owner->getEmail(),\n ]);\n\n return null;\n }\n\n $email = $owner->getEmail();\n if ($email === null) {\n return null;\n }\n\n $user = $teamRepository->findActiveTeamMemberByEmail($this->team, $email);\n if (! $user instanceof User) {\n return null;\n }\n\n return $profileRepository->updateOrCreateProfile($user, [\n 'crm_configuration_id' => $this->config->getId(),\n 'crm_provider_id' => $owner->getId(),\n ]);\n }\n\n private function isPermissionError(int $statusCode, string $errorMessage, ?array $responseBody): bool\n {\n // Check HTTP 403 Forbidden\n if ($statusCode === 403) {\n return true;\n }\n\n // Check for scope-related keywords in error message\n $scopeKeywords = ['scope', 'permission', 'forbidden', 'unauthorized', 'access denied', 'oauth'];\n $lowerErrorMessage = strtolower($errorMessage);\n\n foreach ($scopeKeywords as $keyword) {\n if (str_contains($lowerErrorMessage, $keyword)) {\n return true;\n }\n }\n\n // Check response body for scope errors\n if ($responseBody !== null) {\n return $this->arrayContainsKeyword($responseBody, $scopeKeywords);\n }\n\n return false;\n }\n\n /**\n * Recursively search array for keywords in values\n */\n private function arrayContainsKeyword(array $data, array $keywords): bool\n {\n foreach ($data as $value) {\n if (is_array($value)) {\n if ($this->arrayContainsKeyword($value, $keywords)) {\n return true;\n }\n } elseif (is_string($value)) {\n $lowerValue = strtolower($value);\n foreach ($keywords as $keyword) {\n if (str_contains($lowerValue, $keyword)) {\n return true;\n }\n }\n }\n }\n\n return false;\n }\n\n private function generateNameSearchPayload(string $name, int $offset, int $limit): array\n {\n $payload = [\n 'query' => $name,\n 'sorts' => [\n [\n 'propertyName' => 'modifieddate',\n 'direction' => 'DESCENDING',\n ],\n ],\n 'properties' => [\n 'email',\n 'firstname',\n 'lastname',\n 'country',\n 'phone',\n 'mobilephone',\n 'jobtitle',\n 'hubspot_owner_id',\n 'associatedcompanyid',\n 'photo',\n 'industry',\n 'name',\n 'company',\n ],\n 'limit' => $limit,\n 'after' => $offset,\n ];\n\n $this->logger->debug('[HubSpot] CRM Search requested', [\n 'request' => $payload,\n ]);\n\n return $payload;\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n /** @var array<int, array<string, mixed>> */\n return Cache::remember(\n key: $this->team->getId() . $name . $count . $offset,\n ttl: 300,\n callback: function () use ($name, $offset, $count): array {\n $data = [];\n\n // Use the new V3 API to find contacts based on additional fields.\n foreach (['companies', 'contacts'] as $objectType) {\n $endpoint = 'https://api.hubapi.com/crm/v3/objects/' . $objectType . '/search';\n $payload = $this->generateNameSearchPayload($name, $offset, $count);\n $type = $objectType === 'companies' ? 'account' : 'contact';\n\n try {\n $response = $this->client->getInstance()->getClient()->request('POST', $endpoint, [\n 'json' => $payload,\n ]);\n\n // Build mapped list.\n foreach ($response['results'] as $object) {\n $properties = $object['properties'];\n\n $objectName = $this->buildContactName($properties);\n\n $record = [\n 'crmId' => $object['id'],\n // Pass crmUrl to the FE, needed for success message in the extension when you log activity.\n 'crmUrl' => $this->generateProviderUrl($object['id'], $type),\n 'name' => $objectName,\n 'prospectType' => $type,\n 'phoneNumbers' => [],\n ];\n\n if ($type === 'account') {\n $record['industry'] = $properties['industry'] ?? null;\n } else {\n $record['title'] = $properties['jobtitle'] ?? null;\n $record['organization'] = $properties['company'] ?? null;\n }\n\n $countryCode = $this->buildContactCountry($properties);\n $parsedNumber = $this->buildContactPhone($countryCode, $properties);\n\n // Add phone number to record.\n if (! empty($parsedNumber['phone'])) {\n $record['phoneNumbers'][] = [\n 'number' => $parsedNumber['phone'],\n 'nationalFormat' => phone_national($countryCode, $parsedNumber['phone']),\n 'type' => 'phone',\n ];\n }\n\n // Add mobile phone number to record.\n if (! empty($properties['mobilephone'])) {\n $mobileNumber = phone_e164($countryCode, $properties['mobilephone']);\n if ($mobileNumber !== null) {\n $record['phoneNumbers'][] = [\n 'number' => $mobileNumber,\n 'nationalFormat' => phone_national($countryCode, $mobileNumber),\n 'type' => 'mobile',\n ];\n }\n }\n\n $data[] = $record;\n }\n } catch (BadRequest $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [\n 'teamId' => $this->team->getUuid(),\n 'request' => $payload,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n }\n\n return $data;\n },\n );\n }\n\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n\n if ($crmAccountId === null) {\n return $data;\n }\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n $closedStages = $this->getClosedDealStages();\n $payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(\n $this->config,\n $crmAccountId,\n $closedStages,\n );\n\n $results = $this->client->getPaginatedData($payload, 'deals');\n\n foreach ($results['results'] as $object) {\n $properties = $object['properties'];\n\n $amount = null;\n if (empty($properties['amount']) === false) {\n $currency = $properties['deal_currency_code'] ?? $this->config->default_currency;\n\n // Values can contain commas and any junk so strip them.\n $value = (float) preg_replace('/[^\\d.]/', '', $properties['amount']);\n $amount = formatCurrency($value, $currency);\n }\n\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', $properties['pipeline'])\n ->first();\n\n if ($businessProcess === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', $properties['pipeline'])\n ->first();\n } else {\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', $properties['dealstage'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages(null, $properties['dealstage']);\n }\n }\n\n $recordType = null;\n if ($businessProcess) {\n $recordType = $businessProcess->recordTypes()->first();\n }\n\n $isWon = in_array($properties['dealstage'], $closedStages['won']);\n $isLost = in_array($properties['dealstage'], $closedStages['lost']);\n\n $record = [\n 'crmId' => $object['id'],\n 'name' => $properties['dealname'] ?? 'Unknown Deal',\n 'value' => $amount,\n 'won' => $isWon,\n 'closed' => $isWon || $isLost,\n 'stage' => [\n 'id' => $stage?->getUuid() ?? '',\n 'name' => $stage?->getName() ?? '',\n ],\n ];\n\n if ($recordType) {\n $record += [\n 'recordType' => [\n 'id' => $recordType->id_string,\n 'name' => $recordType->name,\n ],\n ];\n }\n\n if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(?string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = [];\n switch ($objectType) {\n case 'contact':\n $hsObject = 'contact';\n\n break;\n case 'account':\n $hsObject = 'company';\n\n break;\n default:\n // This is a hack to prioritise and override a contact/company with a deal.\n if ($opportunityId) {\n $hsObject = 'deal';\n $objectId = $opportunityId;\n } else {\n throw new InvalidArgumentException('Object type not supported.');\n }\n }\n\n $engagementTypes = ['meetings', 'tasks'];\n\n foreach ($engagementTypes as $engagementType) {\n $payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);\n\n $this->logger->info('[HubSpot] CRM Search requested', [\n 'request' => $payload,\n ]);\n\n $engagements = $this->client->getPaginatedData($payload, $engagementType);\n\n foreach ($engagements['results'] as $engagement) {\n if ($engagementType == 'meetings') {\n $title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';\n } elseif ($engagementType == 'tasks') {\n $title = $engagement['properties']['hs_task_subject'];\n } else {\n $title = 'Scheduled meeting';\n }\n\n $data[] = [\n 'crmId' => $engagement['id'],\n 'subject' => $title,\n 'due' => $engagement['properties']['hs_timestamp'],\n 'type' => $engagement['properties']['hs_activity_type'] ?? null,\n ];\n }\n }\n\n usort($data, function ($item1, $item2) {\n return $item2['due'] <=> $item1['due'];\n });\n\n return $data;\n }\n\n /**\n * Try to find CRM Objects using email address\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $contactProperties = [\n 'email',\n 'firstname',\n 'lastname',\n 'country',\n 'phone',\n 'mobilephone',\n 'jobtitle',\n 'hubspot_owner_id',\n 'associatedcompanyid',\n 'photo',\n ];\n $contact = null;\n $account = null;\n\n try {\n $hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);\n\n if ($hsContact) {\n $contact = $this->importContact($hsContact);\n $account = $contact->account;\n }\n\n $data = $this->convertCrmData($contact, $account, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n } catch (BadRequest $e) {\n $this->logger->warning('[HubSpot] Search failed', [\n 'team_id' => $this->team->getId(),\n 'search_identifier' => $email,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return null;\n }\n\n public function getDomain(string $email): ?string\n {\n return $this->getDomainFromEmail($email);\n }\n\n /**\n * Try to find CRM objects using domain name of the email address\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByDomain(string $domain, ?int $userId = null): ?array\n {\n $companyName = $domain;\n\n // Try to find a company matching their email domain.\n $companyProperties = [\n 'country',\n 'phone',\n 'name',\n 'hs_avatar_filemanager_key',\n 'industry',\n 'hubspot_owner_id',\n 'domain',\n ];\n\n try {\n $hsAccounts = $this->client\n ->getInstance()\n ->companies()\n ->searchByDomain($companyName, $companyProperties);\n } catch (Throwable $e) {\n $this->logger->info('[HubSpot] Search failed', [\n 'error' => $e->getMessage(),\n 'domain' => $domain,\n ]);\n\n return null;\n }\n\n $account = null;\n // If there are multiple accounts, don't guess, we'll ask later.\n if (\\count($hsAccounts->data->results) === 1) {\n // Persist this remote object.\n $account = $this->syncAccount($hsAccounts->data->results[0]->companyId);\n }\n\n $data = $this->convertCrmData(null, $account, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n /**\n * @return array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array\n {\n $countryCode = null;\n if ($contact && $contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account && $account->country_code) {\n $countryCode = $account->country_code;\n }\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n // If there are multiple opportunities, don't guess, we'll ask later.\n $opportunity = null;\n $stage = null;\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n protected function getCacheKey(string $object, ?int $userId = null): ?string\n {\n $key = $this->team->getId() . $object;\n $keySuffix = $this->getOwnerKeySuffix($userId);\n\n return $key . $keySuffix;\n }\n\n private function getOwnerKeySuffix(?int $userId = null): string\n {\n return $userId === null ? '' : (string) $userId;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n if (str_contains($phone, '**')) {\n return null;\n }\n\n // trim all whitespaces if present so the lookup doesn't fail\n $phone = str_replace(' ', '', $phone);\n\n // Check if the user is internal.\n if ($this->isPhoneNumberOfTeamMember($phone)) {\n return null;\n }\n\n $response = $this->searchForPhoneNumber($phone);\n if (empty($response)) {\n return null;\n }\n\n // This would ideally importContact instead but the response type differs.\n $contact = $this->findAndSyncContact($response['results'][0]['id']);\n if (! $contact instanceof Contact) {\n return null;\n }\n\n $account = $contact->account;\n $countryCode = $contact->country_code ?? $account->country_code ?? null;\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n $opportunity = null;\n $stage = null;\n\n try {\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (Exception $e) {\n $this->logger->debug('[HubSpot] Opportunity failed to sync.', [\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n private function isPhoneNumberOfTeamMember(string $phone): bool\n {\n $teamRepository = app(TeamRepository::class);\n $user = $teamRepository->findTeamMemberByPhone($this->team, $phone);\n\n if ($user instanceof User) {\n return true;\n }\n\n return false;\n }\n\n private function findAndSyncContact(string $crmId): ?Contact\n {\n try {\n return $this->syncContact($crmId);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Phone match failed', [\n 'reason' => $exception->getMessage(),\n ]);\n\n return null;\n }\n }\n\n private function hasResults(array $response): bool\n {\n return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;\n }\n\n private function searchForPhoneNumber(string $phone): array\n {\n // Normalizes the provided phone number for the API search.\n $normalizedPhone = $this->normalizePhoneNumber($phone);\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);\n\n $this->logger->info('[HubSpot] Phone match search triggered', [\n 'phone' => $phone,\n 'normalizedPhone' => $normalizedPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);\n\n if (! $this->hasResults($response)) {\n $nationalPhone = preg_replace('/\\D/', '', phone_national(null, $phone));\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);\n\n $this->logger->info('[HubSpot] Phone match national number search triggered', [\n 'phone' => $phone,\n 'nationalPhone' => $nationalPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($phone, $payload);\n }\n\n if (! $this->hasResults($response)) {\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);\n\n $this->logger->info('[HubSpot] Phone match alternative search triggered', [\n 'phone' => $phone,\n 'normalizedPhone' => $normalizedPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($phone, $payload);\n }\n\n return $this->hasResults($response) ? $response : [];\n }\n\n private function handlePhoneSearchRequest(string $phone, array $payload): array\n {\n $endpoint = 'https://api.hubapi.com/crm/v3/objects/contacts/search';\n\n try {\n $response = $this->client->getInstance()->getClient()->request(\n 'POST',\n $endpoint,\n ['json' => ($payload)],\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Phone match failed', [\n 'phone' => $phone,\n 'reason' => $exception->getMessage(),\n ]);\n\n return [];\n }\n\n $this->logger->info('[HubSpot] Phone match completed', [\n 'phone' => $phone,\n 'response' => $response,\n ]);\n\n return $response->toArray();\n }\n\n private function normalizePhoneNumber(string $phone): string\n {\n return ltrim(phone_e164(null, $phone), '+0');\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $cacheKey = $this->getCacheKey($name, $userId);\n\n $result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {\n $payload = $this->payloadBuilder->generateSearchContactsByNamePayload(\n $name,\n $this->getContactFields()\n );\n\n $hsContacts = $this->client->getPaginatedData($payload, 'contact');\n if (empty($hsContacts['results'])) {\n return false;\n }\n\n $contact = $this->importContact($hsContacts['results'][0]);\n if ($contact === null) {\n return false;\n }\n\n $account = $contact->account;\n $countryCode = $contact->country_code ?? $account->country_code ?? null;\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact->crm_provider_id,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n $opportunity = null;\n $stage = null;\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n });\n\n return is_array($result) ? $result : null;\n }\n\n\n private function convertActivityAssociations(Activity $activity): array\n {\n return [\n 'contactIds' => $this->getParticipantsIds($activity),\n 'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],\n 'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],\n 'ownerIds' => [],\n ];\n }\n\n private function getParticipantsIds(Activity $activity): array\n {\n $attendees = [];\n\n $participantRepository = app(ParticipantRepository::class);\n $participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);\n foreach ($participants as $participant) {\n if ($participant->user_id || $participant->isCoach()) {\n continue;\n }\n\n $contact = $participant->contact()->first();\n if ($contact && $contact->crm_provider_id) {\n $attendees[] = $contact->crm_provider_id;\n } else {\n if (! empty($participant->name)) {\n $attendeeData = $this->fetchMissingAttendeeInfo($participant);\n }\n if (! empty($attendeeData['id'])) {\n $attendees[] = $attendeeData['id'];\n }\n }\n }\n\n if ($activity->hasContact()) {\n $attendees[] = $activity->contact->crm_provider_id;\n }\n\n return array_unique($attendees);\n }\n\n private function fetchMissingAttendeeInfo(Participant $participant): array\n {\n // Check if we need to look inside an account context.\n $activity = $participant->getActivity();\n $companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;\n\n // First check the local data.\n /** @var Contact[] $contacts */\n $contacts = $this->team->contacts()\n ->with('account')\n ->where('name', $participant->name)\n ->whereNotNull('email')\n ->get();\n\n foreach ($contacts as $contact) {\n // If we have a company in scope, check the contact is associated to it.\n if (\n $companyId !== null\n && ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)\n ) {\n continue;\n }\n\n return [\n 'id' => $contact->crm_provider_id,\n 'email' => $contact->email,\n ];\n }\n\n $payload = $this->generateNameSearchPayload($participant->name, 0, 20);\n\n try {\n $response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);\n\n // TODO add some logic to choose the most suitable contact if multiple\n foreach ($response['results'] as $object) {\n $properties = $object['properties'];\n if (empty($object['properties']) === false) {\n // Check the company matches the contact.\n // Todo: Move this check inside the API search.\n if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {\n continue;\n }\n\n return [\n 'id' => $object['id'],\n 'email' => $properties['email'],\n ];\n }\n }\n } catch (Exception $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [\n 'teamId' => $this->team->id_string,\n 'request' => $payload,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return [];\n }\n\n /**\n * Store transcripts as note engagement.\n *\n * @throws Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n // For HS no need to check if Crm profile - Log Notes field is enabled\n // We only check if store_transcript toggle is enabled on crm profile.\n $engagement = [\n 'active' => true,\n 'ownerId' => $this->profile->crm_provider_id,\n 'timestamp' => $activity->created_at->tz($activity->user->timezone)->getTimestamp() * 1000,\n 'type' => 'NOTE',\n ];\n\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, static::ENGAGEMENT_BODY_MAX_LENGTH);\n\n $metadata = [\n 'body' => $transcripts,\n ];\n\n $associations = $this->convertActivityAssociations($activity);\n\n try {\n $hsEngagement = $this->client\n ->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n\n $this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);\n\n $noteId = $hsEngagement->data->engagement->id;\n\n // Store crm logged id in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $noteId;\n $transcription->save();\n } catch (Exception $e) {\n Sentry::captureException($e);\n }\n }\n\n /*\n * @inheritdoc\n */\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $payload = [\n 'properties' => $data,\n ];\n\n try {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n $this->client->getNewInstance()->crm()->deals()->basicApi()->update($objectId, $payload);\n\n break;\n case FieldData::OBJECT_CONTACT:\n $this->client->getNewInstance()->crm()->contacts()->basicApi()->update($objectId, $payload);\n\n break;\n\n case FieldData::OBJECT_ACCOUNT:\n $this->client->getNewInstance()->crm()->companies()->basicApi()->update($objectId, $payload);\n\n break;\n\n case FieldData::OBJECT_TASK:\n // Endpoint for Engagements not ready\n $engagements = [\n 'type' => 'TASK',\n ];\n $metadata = $data;\n $this->client->getInstance()->engagements()->update($objectId, $engagements, $metadata);\n\n $this->logCrmEngagementManipulation(\n self::ACTION_UPDATE,\n ['crmId' => $objectId],\n $metadata,\n );\n\n break;\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n } catch (\\HubSpot\\Client\\Crm\\Deals\\ApiException $apiException) {\n $errorMessage = $apiException->getMessage();\n if ($apiException->getResponseBody()) {\n $responseBody = json_decode($apiException->getResponseBody(), true, 512, JSON_THROW_ON_ERROR);\n $errorMessage = $responseBody['message'] ?? $apiException->getMessage();\n }\n\n $this->logger->error(\n '[HubSpot] Update record failed',\n [\n 'objectType' => $objectType,\n 'objectId' => $objectId,\n 'payload' => $payload,\n 'reason' => $errorMessage,\n 'team' => $this->team->getUuid(),\n ]\n );\n\n throw new CrmException($errorMessage);\n }\n }\n\n /*\n * @inheritdoc\n */\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n return $this->client->getInstance()->deals()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_CONTACT:\n return $this->client->getInstance()->contacts()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_ACCOUNT:\n return $this->client->getInstance()->companies()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_TASK:\n return $this->client->getInstance()->engagements()->get($objectId)->toArray();\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n }\n\n /**\n * @throws BadRequest\n * @throws CrmException\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n $payload = [\n 'properties' => [\n [\n 'name' => 'dealstage',\n 'value' => $stage->crm_provider_id,\n ],\n ],\n ];\n\n try {\n $this->client->getInstance()->deals()->update($crmObject->crm_provider_id, $payload);\n } catch (BadRequest $badRequest) {\n if ($badRequest->getCode() === 403) {\n throw new CrmException(\n \"Sorry, you don't have permission to update this stage.\",\n $badRequest->getCode(),\n $badRequest,\n );\n }\n\n $this->logger->warning('[HubSpot] Stage update failed', [\n 'dealId' => $crmObject->crm_provider_id,\n 'payload' => $payload,\n 'message' => $badRequest->getMessage(),\n ]);\n\n throw $badRequest;\n }\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $url = null;\n $baseUrl = 'https://app.hubspot.com/contacts/' . $this->config->crm_provider_id . '/';\n\n switch ($objectType) {\n case 'account':\n $url = $baseUrl . 'company/' . $providerId;\n\n break;\n\n case 'contact':\n $url = $baseUrl . 'contact/' . $providerId;\n\n break;\n\n case 'opportunity':\n $url = $baseUrl . 'deal/' . $providerId;\n\n break;\n\n case 'task':\n case 'activity':\n return null;\n\n // This should not be deep-linked as per JMNY-3934.\n //$url = $baseUrl.'tasks/list/view/all/?taskId='.$providerId;\n break;\n }\n\n return $url;\n }\n\n public function searchCalls(Carbon $from, Carbon $to, string $activityProvider): array\n {\n $this->logger->info('[HubSpot] Search calls', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n ]);\n\n $calls = [];\n $page = 1;\n\n do {\n try {\n $payload = $this->payloadBuilder->generateGetCallsPayload($from, $to, $activityProvider, $page);\n $response = $this->client->getInstance()->getClient()->request(\n 'POST',\n self::CALLS_SEARCH_ENDPOINT,\n ['json' => ($payload)],\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search calls failed', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n 'reason' => $exception->getMessage(),\n ]);\n $response = null;\n }\n\n $responseResults = empty($response['results']) ? [] : $response['results'];\n $calls = array_merge($calls, $responseResults);\n $page++;\n } while (! empty($responseResults));\n\n return $calls;\n }\n\n public function searchCallsForPeriodByPage(Carbon $from, Carbon $to, int $page, bool $retry = true)\n {\n try {\n $payload = $this->payloadBuilder->generateSearchCallsByPeriodPayload($from, $to, $page);\n $response = $this->client->getInstance()->getClient()->request(\n 'POST',\n self::CALLS_SEARCH_ENDPOINT,\n ['json' => ($payload)],\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search calls for period failed', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n 'reason' => $exception->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep(1);\n\n return $this->searchCallsForPeriodByPage($from, $to, $page, false);\n }\n $response = null;\n }\n\n return $response;\n }\n\n public function searchCallsForPeriod(Carbon $from, Carbon $to): Generator\n {\n $this->logger->info('[HubSpot] Search calls for period', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n ]);\n\n $page = 1;\n\n do {\n $response = $this->searchCallsForPeriodByPage($from, $to, $page);\n\n $responseResults = empty($response['results']) ? [] : $response['results'];\n\n $associationContacts = $this->getAssociationDataForCollection($responseResults, 'calls', 'contacts');\n $associationCompanies = $this->getAssociationDataForCollection($responseResults, 'calls', 'companies');\n $associationDeals = $this->getAssociationDataForCollection($responseResults, 'calls', 'deals');\n\n foreach ($responseResults as $call) {\n $call['associations'] = [\n 'contacts' => $this->importAssociationData($call, $associationContacts),\n 'companies' => $this->importAssociationData($call, $associationCompanies),\n 'deals' => $this->importAssociationData($call, $associationDeals),\n ];\n\n yield $call;\n }\n $page++;\n } while (! empty($responseResults));\n }\n\n public function getCall(string $callId): array\n {\n $this->logger->info('[HubSpot] Get call', [\n 'call_id' => $callId,\n ]);\n\n $searchAttributes = $this->payloadBuilder->getSearchCallAttributes();\n $endpoint = sprintf(\n 'https://api.hubapi.com/crm/v3/objects/calls/%s',\n $callId,\n );\n\n try {\n $response = $this->client->getInstance()->getClient()->request(\n 'GET',\n $endpoint,\n [],\n sprintf(\n 'properties=%s&associations=contacts,companies,deals',\n implode(',', $searchAttributes),\n ),\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Get call failed', [\n 'call_id' => $callId,\n 'reason' => $exception->getMessage(),\n ]);\n $response = null;\n }\n\n return empty($response) ? [] : $response->toArray();\n }\n\n public function bulkAddPlaybackURLToDescription(array $crmUpdateData): array\n {\n $crmUpdateBatches = array_chunk($crmUpdateData, self::BATCH_UPDATE_LIMIT);\n\n $updatedCrmIds = [];\n\n foreach ($crmUpdateBatches as $crmBatch) {\n $payload = $this->payloadBuilder->generatePlaybackAddUrlBatchPayload($crmBatch);\n $updateSuccess = $this->bulkAddPlaybackURLToDescriptionRequest($payload);\n if ($updateSuccess) {\n $updatedCrmIds = array_merge($updatedCrmIds, array_column($crmBatch, 'crm_id'));\n }\n }\n\n return $updatedCrmIds;\n }\n\n private function bulkAddPlaybackURLToDescriptionRequest(array $payload, bool $retry = true): bool\n {\n try {\n $this->client->getNewInstance()->crm()->objects()->batchApi()->update('calls', $payload);\n\n return true;\n } catch (\\HubSpot\\Client\\Crm\\Objects\\ApiException $e) {\n $response = json_decode($e->getResponseBody(), true);\n $retryAfter =\n isset($response['policyName'])\n && $response['policyName'] == self::TEN_SECONDLY_ROLLING_POLICY\n ? self::TEN_SECONDLY_ROLLING_LIMIT\n : 1;\n } catch (Exception $e) {\n $retryAfter = 1;\n }\n\n $this->logger->warning('[HubSpot] Bulk add playback url to CRM failed', [\n 'reason' => $e->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep($retryAfter);\n\n return $this->bulkAddPlaybackURLToDescriptionRequest($payload, false);\n }\n\n return false;\n }\n\n /**\n * Sometimes we have secondly rate limit error, then retry request after 1 second\n */\n public function searchCallByRecordingURLToken(string $playbackURLToken, bool $retry = true): array\n {\n $endpoint = 'https://api.hubapi.com/crm/v3/objects/calls/search';\n $payload = $this->payloadBuilder->generateSearchCallByTokenPayload($playbackURLToken);\n\n $this->logger->info('[HubSpot] CRM Search by playback URL token requested', [\n 'request' => $payload,\n ]);\n\n try {\n $response = $this->client->getInstance()->getClient()->request('POST', $endpoint, ['json' => ($payload)]);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search by playback URL token failed', [\n 'playbackURLToken' => $playbackURLToken,\n 'reason' => $exception->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep(1);\n\n return $this->searchCallByRecordingURLToken($playbackURLToken, false);\n }\n\n return [];\n }\n\n return empty($response['results']) ? [] : $response['results'][0];\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! $this->config->store_transcript) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n $transcriptionSegments = $this->transcriptionService->findTranscriptionByActivity($activity);\n\n if ($transcriptionSegments->isEmpty()) {\n return '';\n }\n\n $transcription = sprintf(\n '<p><strong>Transcript for %s</strong></p><p></p>',\n $activity->title ?? $activity->activity_title,\n );\n\n $roomOwnerParticipant = $activity->findParticipantRoomOwner();\n $roomOwnerParticipantId = $roomOwnerParticipant !== null\n ? $roomOwnerParticipant->getId()\n : null;\n\n\n $transcription .= $transcriptionSegments\n ->map(static function (array $transcriptionSegment) use ($roomOwnerParticipantId): string {\n $isOrganiser = $roomOwnerParticipantId === $transcriptionSegment['participantId']\n && $roomOwnerParticipantId !== null;\n $transcriptColor = $isOrganiser ? '#000000' : '#f0415a';\n\n return sprintf(\n '<span style=\"color: %s;\">%s | </span>%s',\n $transcriptColor,\n $transcriptionSegment['formattedStartsAt'],\n $transcriptionSegment['transcript'],\n );\n })\n ->implode('<br />');\n\n return $transcription;\n }\n\n /**\n * @param array<array{\n * id: string,\n * label: string,\n * value?: string,\n * }> $options\n *\n * @return FieldData[]\n */\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $values = [];\n $sequence = 0;\n\n foreach ($options as $option) {\n $values[] = [\n 'value' => $option['value'] ?? $option['id'],\n 'label' => substr($option['label'], 0, 255),\n 'sequence' => $sequence++,\n ];\n }\n\n $fieldsToPurge = $field->values()->get()->pluck('value')->toArray();\n\n foreach ($values as $value) {\n $value['value'] = substr($value['value'], 0, 255);\n $fieldValues[] = $field->values()->updateOrCreate([\n 'value' => $value['value'],\n ], $value);\n\n // Remove this value from the ones we are going to purge.\n if (($key = array_search($value['value'], $fieldsToPurge, false)) !== false) {\n unset($fieldsToPurge[$key]);\n }\n }\n\n // Delete the old values that are no longer used.\n $field->values()->whereIn('value', $fieldsToPurge)->delete();\n\n return $fieldValues;\n }\n\n public function saveTranscriptionSummaryAsNote(\n ActivityContract $activity,\n string $title,\n string $body,\n ?string $objectId,\n ?NoteObject $noteObject = null,\n ): ?string {\n if ($noteObject === null || $objectId === null) {\n return null;\n }\n\n /** @var User $user */\n $user = $activity->getUser();\n\n $profile = $this->assignCrmOwner($user, $activity);\n if (! $profile instanceof Profile) {\n return null;\n }\n\n $timestamp = Carbon::now($user->getTimezone())->getTimestamp() * 1000;\n $engagement = [\n 'active' => true,\n 'ownerId' => $profile->getAttribute('crm_provider_id'),\n 'timestamp' => $timestamp,\n 'type' => 'NOTE',\n ];\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $body = mb_strimwidth($body, 0, self::ENGAGEMENT_BODY_MAX_LENGTH);\n $metadata = [\n 'body' => $body,\n ];\n\n $associations = $this->convertActivityAssociations($activity);\n\n try {\n $hsActivityId = $this->client->createNote(\n body: $body,\n ownerId: $profile->getCrmProviderId(),\n timestamp: $timestamp,\n objectId: $objectId,\n noteObject: $noteObject,\n );\n\n $this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);\n\n $this->logger->info('[HubSpot] Saving Transcription Summary as Note', [\n 'activity' => $activity->getUuid(),\n 'crmActivity' => $hsActivityId,\n ]);\n\n return $hsActivityId;\n } catch (Exception $e) {\n Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function attachSummaryToActivity(ActivityContract $activity, string $summaryTitle, string $summaryContents): bool\n {\n $this->logger->info('[HubSpot] Attaching summary to activity', [\n 'activity' => $activity->getUuid(),\n 'summary_content' => $summaryContents,\n ]);\n\n if (! $activity instanceof Activity) {\n throw new InvalidArgumentException('Expected instance of Activity');\n }\n\n $summary = '<p><strong>' . $summaryTitle . '</strong></p>';\n $summary .= '<p>' . $summaryContents . '</p>';\n $metadata = $this->buildMetadataForSummaryUpdate($activity, $summary);\n\n try {\n $type = $this->matchActivityEngagementType($activity);\n $engagement = ['type' => $type];\n\n $this->client->updateEngagement($activity->getCrmProviderId(), $engagement, $metadata);\n } catch (Exception $e) {\n $this->logger->warning('[HubSpot] Update summary failed', [\n 'activity' => $activity->getUuid(),\n 'reason' => $e->getMessage(),\n ]);\n\n return false;\n }\n\n $this->logCrmEngagementManipulation(\n self::ACTION_UPDATE,\n ['crmId' => $activity->getCrmProviderId()],\n $metadata,\n );\n\n return true;\n }\n\n private function buildMetadataForSummaryUpdate(Activity $activity, string $summary): array\n {\n $descriptionField = $activity->getType() === Activity::TYPE_CONFERENCE ? 'internalMeetingNotes' : 'body';\n $engagement = $this->client->getEngagementData($activity->getCrmProviderId());\n // Meeting without internalMeetingNotes might mean it just does not have any notes;\n $description = $engagement['metadata'][$descriptionField] ?? null;\n\n if (empty($description)) {\n $data = $summary;\n } else {\n // avoid playbook url link to Jiminny being sent twice in the activity description\n $targetUrl = PlaybackUrlBuilder::build($activity);\n\n if (str_contains($description, $targetUrl)) {\n $jiminnyUrl = '<p><a href=\"' . $targetUrl . '\" title=\"Play at Jiminny\">Play at Jiminny</a></p>';\n $summary = str_replace($jiminnyUrl, '', $summary);\n\n $this->logger->info('[HubSpot] Summary modified', [\n 'activity' => $activity->getUuid(),\n 'target_url' => $jiminnyUrl,\n 'modified_summary_content' => $summary,\n ]);\n }\n\n $data = $description . '<p></p>' . $summary;\n }\n\n return [\n $descriptionField => $data,\n ];\n }\n\n public function fetchAndAssociateRelatedActivity(Activity $activity): ?Activity\n {\n return $this->syncRelatedActivityManager->fetchAndAssociateRelatedActivity($activity);\n }\n\n public function fetchRelatedActivity(Activity $activity): array\n {\n return [];\n }\n\n public function getDealsInBulk(array $dealIds): array\n {\n $payload = $this->payloadBuilder->getDealsInBulkPayload($dealIds);\n\n return $this->client->getPaginatedData($payload, 'deals');\n }\n\n /**\n * Extract deal IDs from HubSpot search response.\n *\n * @param array $hubspotResponse The raw HubSpot search API response.\n * @param bool $includeArchived Whether to include archived deals (default: false).\n *\n * @return string[] Array of deal IDs as strings.\n */\n public function extractDealIds(array $hubspotResponse, bool $includeArchived = false): array\n {\n if (empty($hubspotResponse['results'])) {\n return [];\n }\n\n return array_values(\n array_map(\n fn ($deal) => $deal['id'],\n array_filter(\n $hubspotResponse['results'],\n fn ($deal) => $includeArchived || empty($deal['archived'])\n )\n )\n );\n }\n\n public function matchActivityEngagementType(Activity $activity): string\n {\n return match ($activity->getType()) {\n Activity::TYPE_CONFERENCE => self::TYPE_MEETING,\n Activity::TYPE_SOFTPHONE, Activity::TYPE_SOFTPHONE_INBOUND => self::TYPE_CALL,\n default => self::TYPE_NOTE,\n };\n }\n\n private function assignCrmOwner(User $user, ActivityContract $activity): ?Profile\n {\n $profile = $user->getProfile();\n if ($profile instanceof Profile) {\n return $profile;\n }\n\n $this->logger->info('[HubSpot] Unable to save summary. No profile', [\n 'activity' => $activity->getUuid(),\n ]);\n\n return null;\n }\n\n private static function getDealsPipelinesEndpoint(): string\n {\n return self::API_URL . self::ENDPOINT_PIPELINES . self::PIPELINE_OBJECT_TYPE_DEALS;\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n $engagement = $this->client->getEngagementData($crmProviderId);\n\n return ! empty($engagement);\n } catch (HttpNotFoundException|BadRequest) {\n // Engagement not found in CRM - this is expected and permanent\n $this->logger->info('[Hubspot] Engagement not found during verification', [\n 'engagement_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\n });\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse Generator;\nuse GuzzleHttp\\Exception\\RequestException;\nuse HubSpot\\Client\\Crm\\Owners\\Model\\PublicOwner;\nuse Illuminate\\Support\\Facades\\Cache;\nuse InvalidArgumentException;\nuse Jiminny\\Contracts\\Repositories\\TeamRepository;\nuse Jiminny\\Contracts\\Services\\Crm\\ClientInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\FetchRelatedActivityInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\HubspotInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SavePlaybackLinkToCrmInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SendSummaryToCrmInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Contracts\\ActivityContract;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\Layout;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Participant;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Repositories\\ParticipantRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Hubspot\\Actions\\SyncArchivedProfilesAction;\nuse Jiminny\\Services\\Crm\\Hubspot\\Fields\\ValueNormalizer;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\OpportunitySyncTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\SyncCrmEntitiesTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\SyncFieldsTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\WriteCrmTrait;\nuse Jiminny\\Services\\Crm\\MatchDomainByEmailInterface;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Services\\Crm\\ResolveCompanyNameByEmailTrait;\nuse Jiminny\\Utils\\PlaybackUrlBuilder;\nuse Sentry;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse Throwable;\nuse UnexpectedValueException;\n\n/**\n * @phpstan-type CrmFieldDefinition array{\n * name: string,\n * label: string,\n * description: string,\n * type: string,\n * fieldType: string,\n * hidden: bool,\n * showCurrencySymbol: bool,\n * options: array<array{\n * id: string,\n * label: string,\n * value?: string,\n * }\n */\nclass Service extends BaseService implements\n HubspotInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n SendSummaryToCrmInterface,\n MatchDomainByEmailInterface,\n SavePlaybackLinkToCrmInterface,\n RemoteEntityManipulationInterface,\n FetchRelatedActivityInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n VerifyTaskExistsInterface\n{\n use ResolveCompanyNameByEmailTrait;\n use SyncCrmEntitiesTrait;\n use WriteCrmTrait;\n use SyncFieldsTrait;\n use OpportunitySyncTrait;\n\n private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;\n\n private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';\n private const int BATCH_UPDATE_LIMIT = 100;\n private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';\n private const int TEN_SECONDLY_ROLLING_LIMIT = 10;\n private const string CALLS_SEARCH_ENDPOINT = 'https://api.hubapi.com/crm/v3/objects/calls/search';\n\n private const string TYPE_NOTE = 'NOTE';\n\n private const string TYPE_MEETING = 'MEETING';\n\n private const string TYPE_CALL = 'CALL';\n\n private const string API_URL = 'https://api.hubapi.com';\n\n // NB: v1 is legacy - v3 is the newest\n private const string ENDPOINT_PIPELINES = '/crm-pipelines/v1/pipelines/';\n private const string PIPELINE_OBJECT_TYPE_DEALS = 'deals';\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n /**\n * @var ClientInterface|Client\n */\n protected $client;\n protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;\n protected CrmEntityRepository $crmEntityRepository;\n protected ProspectPhotoPathService $prospectPhotoPathService;\n\n private SyncFieldAction $syncFieldAction;\n private PayloadBuilder $payloadBuilder;\n private SyncRelatedActivityManager $syncRelatedActivityManager;\n private SyncArchivedProfilesAction $syncArchivedProfilesAction;\n private WebhookSyncBatchProcessor $batchProcessor;\n\n public function __construct(\n Client $client,\n SyncFieldAction $syncFieldAction,\n PayloadBuilder $payloadBuilder,\n ProspectPhotoPathService $prospectPhotoPathService,\n SyncArchivedProfilesAction $syncArchivedProfilesAction,\n WebhookSyncBatchProcessor $batchProcessor,\n ) {\n parent::__construct();\n\n $this->client = $client;\n $this->syncFieldAction = $syncFieldAction;\n $this->prospectPhotoPathService = $prospectPhotoPathService;\n $this->payloadBuilder = $payloadBuilder;\n $this->syncArchivedProfilesAction = $syncArchivedProfilesAction;\n $this->batchProcessor = $batchProcessor;\n $this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->client,\n ]);\n $this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [\n 'client' => $this->client,\n 'payloadBuilder' => $this->payloadBuilder,\n 'logger' => $this->logger,\n ]);\n $this->crmEntityRepository = app(CrmEntityRepository::class);\n $this->dealFieldsService = app(DealFieldsService::class);\n }\n\n public function getDisplayName(): string\n {\n return 'HubSpot';\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n $owner = $user->team->owner;\n\n return $owner->getSocialAccount(SocialAccount::PROVIDER_HUBSPOT);\n }\n\n public function getClient(): Client\n {\n /** @var Client */\n return $this->client;\n }\n\n /**\n * Convert raw field data into a format compatible with CRM APIs.\n *\n * @param bool $internal Direction of the conversion.\n * True is pulling from CRM, false normalize before sending to CRM.\n */\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return ValueNormalizer::normalize(\n fieldType: $fieldType,\n fieldValue: $fieldValue,\n isInbound: $internal,\n );\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n /** @var Field $activityField */\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'activityType',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n // Outcome should always be provided calls/meetings.\n $fieldData = [\n [\n 'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',\n 'object_type' => Field::OBJECT_TASK,\n ],\n ];\n\n foreach ($fieldData as $data) {\n $field = $this->config->fields()->where($data)->first();\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n }\n\n return $fields;\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n $fieldData = FieldDefinitions::followupFieldsFilter();\n\n foreach ($fieldData as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function syncField(Field $field): void\n {\n switch ($field->object_type) {\n case Field::OBJECT_ACCOUNT:\n $crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_CONTACT:\n $crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_OPPORTUNITY:\n $crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_TASK:\n $this->syncSingleTaskField($field);\n\n return;\n default:\n return;\n }\n\n $this->syncFieldAction->execute($field, $crmField->toArray());\n }\n\n /**\n * @param array<array{\n * id:string,\n * label:string,\n * value?:string\n * }> $options\n *\n * @throws CrmException\n *\n * @return FieldData[]\n *\n */\n public function importPicklistValues(\n Field $field,\n array $options = [['id' => '', 'label' => '', 'value' => '']],\n ): array {\n if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {\n // We already have the options, no need to fetch them again\n return $this->importOptions($field, $options);\n }\n\n $options = [];\n\n switch ($field->getObjectType()) {\n case Field::OBJECT_ACCOUNT:\n $options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());\n\n break;\n\n case Field::OBJECT_CONTACT:\n $options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());\n\n break;\n\n case Field::OBJECT_OPPORTUNITY:\n // Hubspot has different endpoint for stages\n $options = $this->getClient()->fetchOpportunityFieldOptions($field);\n\n break;\n\n case Field::OBJECT_TASK:\n if ($field->getCrmProviderId() === 'disposition') {\n $options = $this->getClient()->fetchDispositionFieldOptions();\n } elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {\n $options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);\n }\n\n break;\n\n default:\n $this->logger->warning('Invalid object type', [\n 'object_type' => $field->getObjectType(),\n 'field_id' => $field->getId(),\n ]);\n\n throw new CrmException('Invalid object type');\n }\n\n return $this->importOptions($field, $options);\n }\n\n /**\n * @inheritdoc\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n $missingStage = null;\n\n try {\n // Use the HubSpot API client instead of the SDK crmPipelines() method\n $endpoint = self::getDealsPipelinesEndpoint();\n $pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);\n $pipelines = $pipelinesResponse->data->results;\n } catch (RequestException|BadRequest $exception) {\n throw $exception;\n }\n\n foreach ($pipelines as $pipeline) {\n $stages = [];\n\n // We create a business process to contain the pipeline, and store all stages against it.\n $p = ResponseNormalize::normalizePipeline($pipeline);\n\n // Create/update business process for this pipeline\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => $p['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($p['label'], 0, 150),\n 'type' => BusinessProcess::TYPE_OPPORTUNITY,\n 'is_selectable' => $p['active'],\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n // Create/update record type clone\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => $p['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($p['label'], 0, 150),\n 'is_selectable' => $p['active'],\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n // Stages - fetch all existing stages upfront to avoid N+1 queries\n $existingStages = $this->config->stages()\n ->withTrashed()\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->get()\n ->keyBy('crm_provider_id');\n\n foreach ($p['stages'] as $dealStage) {\n $s = ResponseNormalize::normalizeDealStage($dealStage);\n\n /** @var ?Stage $existingStage */\n $existingStage = $existingStages->get($s['id']);\n\n // Restore soft-deleted stages that are now active in HubSpot\n if ($existingStage?->trashed() && $s['active']) {\n $existingStage->restore();\n }\n\n // Upsert stage (updates soft-deleted records without restoring them)\n $stage = $this->config->stages()->withTrashed()->updateOrCreate([\n 'crm_provider_id' => $s['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($s['label'], 0, 50),\n 'label' => mb_strimwidth($s['label'], 0, 191),\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'sequence' => $s['displayOrder'],\n 'is_selectable' => $s['active'],\n 'probability' => $s['probability'] * 100,\n ]);\n\n if ($missingStageName === $s['id']) {\n $missingStage = $stage;\n }\n\n $stages[] = $stage->id;\n }\n\n $businessProcess->stages()->sync($stages);\n }\n\n return $missingStage;\n }\n\n /**\n * @inheritdoc\n */\n public function syncOrganization(): void\n {\n try {\n $endpoint = 'https://api.hubapi.com/integrations/v1/me';\n $response = $this->client->getInstance()->getClient()->request('get', $endpoint);\n\n $accountData = $response->data;\n $this->config->update(['default_currency' => $accountData->currency]);\n } catch (BadRequest $e) {\n throw new CrmException('Could not sync the organization.', $e->getCode(), $e);\n }\n }\n\n /**\n * @inheritdoc\n *\n * @throws CrmException\n */\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n $this->syncArchivedProfilesAction->execute($this->team, $this->client, $this->config);\n\n try {\n $owners = $this->client->getOwners();\n } catch (\\HubSpot\\Client\\Crm\\Owners\\ApiException $e) {\n $this->handleOwnersApiException($e);\n }\n\n $profileRepository = app(ProfileRepository::class);\n $teamRepository = app(TeamRepository::class);\n\n foreach ($owners as $owner) {\n $profile = $this->processOwner($owner, $teamRepository, $profileRepository);\n\n if ($profile && $userToSearch && $userToSearch->getId() === $profile->getUserId()) {\n return $profile;\n }\n }\n\n return null;\n }\n\n private function handleOwnersApiException(\\HubSpot\\Client\\Crm\\Owners\\ApiException $e): never\n {\n $statusCode = $e->getCode();\n $errorMessage = $e->getMessage();\n $responseBody = $this->parseResponseBody($e->getResponseBody());\n\n $isPermissionError = $this->isPermissionError($statusCode, $errorMessage, $responseBody);\n\n $logContext = [\n 'team_id' => $this->team->getId(),\n 'team_uuid' => $this->team->getUuid(),\n 'config_id' => $this->config->getId(),\n 'status_code' => $statusCode,\n 'error_message' => $errorMessage,\n 'response_body' => $responseBody,\n ];\n\n if ($isPermissionError) {\n $this->logPermissionError($logContext);\n } else {\n $this->logger->error('[HubSpot] Could not sync the profiles.', $logContext);\n }\n\n throw new CrmException('Could not sync the profiles.', $e->getCode(), $e);\n }\n\n private function parseResponseBody(?string $rawBody): ?array\n {\n if ($rawBody === null || $rawBody === '') {\n return null;\n }\n\n try {\n return json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR);\n } catch (\\JsonException) {\n return null;\n }\n }\n\n private function logPermissionError(array $logContext): void\n {\n $this->logger->critical(\n '[HubSpot] ⚠️ PERMISSION ERROR: Cannot sync profiles - Missing OAuth scopes',\n array_merge($logContext, [\n 'action_required' => 'Request additional HubSpot OAuth scopes',\n 'required_scope' => 'crm.objects.owners.read',\n 'impact' => 'Opportunities will have owner_id but NO user_id - AI automation and reporting will fail',\n 'resolution' => 'Manually request scope from HubSpot account admin or re-authenticate',\n ])\n );\n }\n\n private function processOwner(\n PublicOwner $owner,\n TeamRepository $teamRepository,\n ProfileRepository $profileRepository\n ): ?Profile {\n if ($owner->getArchived()) {\n $this->logger->warning('[HubSpot] Found archived owner', [\n 'crm_provider_id' => $owner->getId(),\n 'email' => $owner->getEmail(),\n ]);\n\n return null;\n }\n\n $email = $owner->getEmail();\n if ($email === null) {\n return null;\n }\n\n $user = $teamRepository->findActiveTeamMemberByEmail($this->team, $email);\n if (! $user instanceof User) {\n return null;\n }\n\n return $profileRepository->updateOrCreateProfile($user, [\n 'crm_configuration_id' => $this->config->getId(),\n 'crm_provider_id' => $owner->getId(),\n ]);\n }\n\n private function isPermissionError(int $statusCode, string $errorMessage, ?array $responseBody): bool\n {\n // Check HTTP 403 Forbidden\n if ($statusCode === 403) {\n return true;\n }\n\n // Check for scope-related keywords in error message\n $scopeKeywords = ['scope', 'permission', 'forbidden', 'unauthorized', 'access denied', 'oauth'];\n $lowerErrorMessage = strtolower($errorMessage);\n\n foreach ($scopeKeywords as $keyword) {\n if (str_contains($lowerErrorMessage, $keyword)) {\n return true;\n }\n }\n\n // Check response body for scope errors\n if ($responseBody !== null) {\n return $this->arrayContainsKeyword($responseBody, $scopeKeywords);\n }\n\n return false;\n }\n\n /**\n * Recursively search array for keywords in values\n */\n private function arrayContainsKeyword(array $data, array $keywords): bool\n {\n foreach ($data as $value) {\n if (is_array($value)) {\n if ($this->arrayContainsKeyword($value, $keywords)) {\n return true;\n }\n } elseif (is_string($value)) {\n $lowerValue = strtolower($value);\n foreach ($keywords as $keyword) {\n if (str_contains($lowerValue, $keyword)) {\n return true;\n }\n }\n }\n }\n\n return false;\n }\n\n private function generateNameSearchPayload(string $name, int $offset, int $limit): array\n {\n $payload = [\n 'query' => $name,\n 'sorts' => [\n [\n 'propertyName' => 'modifieddate',\n 'direction' => 'DESCENDING',\n ],\n ],\n 'properties' => [\n 'email',\n 'firstname',\n 'lastname',\n 'country',\n 'phone',\n 'mobilephone',\n 'jobtitle',\n 'hubspot_owner_id',\n 'associatedcompanyid',\n 'photo',\n 'industry',\n 'name',\n 'company',\n ],\n 'limit' => $limit,\n 'after' => $offset,\n ];\n\n $this->logger->debug('[HubSpot] CRM Search requested', [\n 'request' => $payload,\n ]);\n\n return $payload;\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n /** @var array<int, array<string, mixed>> */\n return Cache::remember(\n key: $this->team->getId() . $name . $count . $offset,\n ttl: 300,\n callback: function () use ($name, $offset, $count): array {\n $data = [];\n\n // Use the new V3 API to find contacts based on additional fields.\n foreach (['companies', 'contacts'] as $objectType) {\n $endpoint = 'https://api.hubapi.com/crm/v3/objects/' . $objectType . '/search';\n $payload = $this->generateNameSearchPayload($name, $offset, $count);\n $type = $objectType === 'companies' ? 'account' : 'contact';\n\n try {\n $response = $this->client->getInstance()->getClient()->request('POST', $endpoint, [\n 'json' => $payload,\n ]);\n\n // Build mapped list.\n foreach ($response['results'] as $object) {\n $properties = $object['properties'];\n\n $objectName = $this->buildContactName($properties);\n\n $record = [\n 'crmId' => $object['id'],\n // Pass crmUrl to the FE, needed for success message in the extension when you log activity.\n 'crmUrl' => $this->generateProviderUrl($object['id'], $type),\n 'name' => $objectName,\n 'prospectType' => $type,\n 'phoneNumbers' => [],\n ];\n\n if ($type === 'account') {\n $record['industry'] = $properties['industry'] ?? null;\n } else {\n $record['title'] = $properties['jobtitle'] ?? null;\n $record['organization'] = $properties['company'] ?? null;\n }\n\n $countryCode = $this->buildContactCountry($properties);\n $parsedNumber = $this->buildContactPhone($countryCode, $properties);\n\n // Add phone number to record.\n if (! empty($parsedNumber['phone'])) {\n $record['phoneNumbers'][] = [\n 'number' => $parsedNumber['phone'],\n 'nationalFormat' => phone_national($countryCode, $parsedNumber['phone']),\n 'type' => 'phone',\n ];\n }\n\n // Add mobile phone number to record.\n if (! empty($properties['mobilephone'])) {\n $mobileNumber = phone_e164($countryCode, $properties['mobilephone']);\n if ($mobileNumber !== null) {\n $record['phoneNumbers'][] = [\n 'number' => $mobileNumber,\n 'nationalFormat' => phone_national($countryCode, $mobileNumber),\n 'type' => 'mobile',\n ];\n }\n }\n\n $data[] = $record;\n }\n } catch (BadRequest $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [\n 'teamId' => $this->team->getUuid(),\n 'request' => $payload,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n }\n\n return $data;\n },\n );\n }\n\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n\n if ($crmAccountId === null) {\n return $data;\n }\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n $closedStages = $this->getClosedDealStages();\n $payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(\n $this->config,\n $crmAccountId,\n $closedStages,\n );\n\n $results = $this->client->getPaginatedData($payload, 'deals');\n\n foreach ($results['results'] as $object) {\n $properties = $object['properties'];\n\n $amount = null;\n if (empty($properties['amount']) === false) {\n $currency = $properties['deal_currency_code'] ?? $this->config->default_currency;\n\n // Values can contain commas and any junk so strip them.\n $value = (float) preg_replace('/[^\\d.]/', '', $properties['amount']);\n $amount = formatCurrency($value, $currency);\n }\n\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', $properties['pipeline'])\n ->first();\n\n if ($businessProcess === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', $properties['pipeline'])\n ->first();\n } else {\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', $properties['dealstage'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages(null, $properties['dealstage']);\n }\n }\n\n $recordType = null;\n if ($businessProcess) {\n $recordType = $businessProcess->recordTypes()->first();\n }\n\n $isWon = in_array($properties['dealstage'], $closedStages['won']);\n $isLost = in_array($properties['dealstage'], $closedStages['lost']);\n\n $record = [\n 'crmId' => $object['id'],\n 'name' => $properties['dealname'] ?? 'Unknown Deal',\n 'value' => $amount,\n 'won' => $isWon,\n 'closed' => $isWon || $isLost,\n 'stage' => [\n 'id' => $stage?->getUuid() ?? '',\n 'name' => $stage?->getName() ?? '',\n ],\n ];\n\n if ($recordType) {\n $record += [\n 'recordType' => [\n 'id' => $recordType->id_string,\n 'name' => $recordType->name,\n ],\n ];\n }\n\n if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(?string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = [];\n switch ($objectType) {\n case 'contact':\n $hsObject = 'contact';\n\n break;\n case 'account':\n $hsObject = 'company';\n\n break;\n default:\n // This is a hack to prioritise and override a contact/company with a deal.\n if ($opportunityId) {\n $hsObject = 'deal';\n $objectId = $opportunityId;\n } else {\n throw new InvalidArgumentException('Object type not supported.');\n }\n }\n\n $engagementTypes = ['meetings', 'tasks'];\n\n foreach ($engagementTypes as $engagementType) {\n $payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);\n\n $this->logger->info('[HubSpot] CRM Search requested', [\n 'request' => $payload,\n ]);\n\n $engagements = $this->client->getPaginatedData($payload, $engagementType);\n\n foreach ($engagements['results'] as $engagement) {\n if ($engagementType == 'meetings') {\n $title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';\n } elseif ($engagementType == 'tasks') {\n $title = $engagement['properties']['hs_task_subject'];\n } else {\n $title = 'Scheduled meeting';\n }\n\n $data[] = [\n 'crmId' => $engagement['id'],\n 'subject' => $title,\n 'due' => $engagement['properties']['hs_timestamp'],\n 'type' => $engagement['properties']['hs_activity_type'] ?? null,\n ];\n }\n }\n\n usort($data, function ($item1, $item2) {\n return $item2['due'] <=> $item1['due'];\n });\n\n return $data;\n }\n\n /**\n * Try to find CRM Objects using email address\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $contactProperties = [\n 'email',\n 'firstname',\n 'lastname',\n 'country',\n 'phone',\n 'mobilephone',\n 'jobtitle',\n 'hubspot_owner_id',\n 'associatedcompanyid',\n 'photo',\n ];\n $contact = null;\n $account = null;\n\n try {\n $hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);\n\n if ($hsContact) {\n $contact = $this->importContact($hsContact);\n $account = $contact->account;\n }\n\n $data = $this->convertCrmData($contact, $account, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n } catch (BadRequest $e) {\n $this->logger->warning('[HubSpot] Search failed', [\n 'team_id' => $this->team->getId(),\n 'search_identifier' => $email,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return null;\n }\n\n public function getDomain(string $email): ?string\n {\n return $this->getDomainFromEmail($email);\n }\n\n /**\n * Try to find CRM objects using domain name of the email address\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByDomain(string $domain, ?int $userId = null): ?array\n {\n $companyName = $domain;\n\n // Try to find a company matching their email domain.\n $companyProperties = [\n 'country',\n 'phone',\n 'name',\n 'hs_avatar_filemanager_key',\n 'industry',\n 'hubspot_owner_id',\n 'domain',\n ];\n\n try {\n $hsAccounts = $this->client\n ->getInstance()\n ->companies()\n ->searchByDomain($companyName, $companyProperties);\n } catch (Throwable $e) {\n $this->logger->info('[HubSpot] Search failed', [\n 'error' => $e->getMessage(),\n 'domain' => $domain,\n ]);\n\n return null;\n }\n\n $account = null;\n // If there are multiple accounts, don't guess, we'll ask later.\n if (\\count($hsAccounts->data->results) === 1) {\n // Persist this remote object.\n $account = $this->syncAccount($hsAccounts->data->results[0]->companyId);\n }\n\n $data = $this->convertCrmData(null, $account, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n /**\n * @return array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array\n {\n $countryCode = null;\n if ($contact && $contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account && $account->country_code) {\n $countryCode = $account->country_code;\n }\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n // If there are multiple opportunities, don't guess, we'll ask later.\n $opportunity = null;\n $stage = null;\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n protected function getCacheKey(string $object, ?int $userId = null): ?string\n {\n $key = $this->team->getId() . $object;\n $keySuffix = $this->getOwnerKeySuffix($userId);\n\n return $key . $keySuffix;\n }\n\n private function getOwnerKeySuffix(?int $userId = null): string\n {\n return $userId === null ? '' : (string) $userId;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n if (str_contains($phone, '**')) {\n return null;\n }\n\n // trim all whitespaces if present so the lookup doesn't fail\n $phone = str_replace(' ', '', $phone);\n\n // Check if the user is internal.\n if ($this->isPhoneNumberOfTeamMember($phone)) {\n return null;\n }\n\n $response = $this->searchForPhoneNumber($phone);\n if (empty($response)) {\n return null;\n }\n\n // This would ideally importContact instead but the response type differs.\n $contact = $this->findAndSyncContact($response['results'][0]['id']);\n if (! $contact instanceof Contact) {\n return null;\n }\n\n $account = $contact->account;\n $countryCode = $contact->country_code ?? $account->country_code ?? null;\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n $opportunity = null;\n $stage = null;\n\n try {\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (Exception $e) {\n $this->logger->debug('[HubSpot] Opportunity failed to sync.', [\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n private function isPhoneNumberOfTeamMember(string $phone): bool\n {\n $teamRepository = app(TeamRepository::class);\n $user = $teamRepository->findTeamMemberByPhone($this->team, $phone);\n\n if ($user instanceof User) {\n return true;\n }\n\n return false;\n }\n\n private function findAndSyncContact(string $crmId): ?Contact\n {\n try {\n return $this->syncContact($crmId);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Phone match failed', [\n 'reason' => $exception->getMessage(),\n ]);\n\n return null;\n }\n }\n\n private function hasResults(array $response): bool\n {\n return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;\n }\n\n private function searchForPhoneNumber(string $phone): array\n {\n // Normalizes the provided phone number for the API search.\n $normalizedPhone = $this->normalizePhoneNumber($phone);\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);\n\n $this->logger->info('[HubSpot] Phone match search triggered', [\n 'phone' => $phone,\n 'normalizedPhone' => $normalizedPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);\n\n if (! $this->hasResults($response)) {\n $nationalPhone = preg_replace('/\\D/', '', phone_national(null, $phone));\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);\n\n $this->logger->info('[HubSpot] Phone match national number search triggered', [\n 'phone' => $phone,\n 'nationalPhone' => $nationalPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($phone, $payload);\n }\n\n if (! $this->hasResults($response)) {\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);\n\n $this->logger->info('[HubSpot] Phone match alternative search triggered', [\n 'phone' => $phone,\n 'normalizedPhone' => $normalizedPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($phone, $payload);\n }\n\n return $this->hasResults($response) ? $response : [];\n }\n\n private function handlePhoneSearchRequest(string $phone, array $payload): array\n {\n $endpoint = 'https://api.hubapi.com/crm/v3/objects/contacts/search';\n\n try {\n $response = $this->client->getInstance()->getClient()->request(\n 'POST',\n $endpoint,\n ['json' => ($payload)],\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Phone match failed', [\n 'phone' => $phone,\n 'reason' => $exception->getMessage(),\n ]);\n\n return [];\n }\n\n $this->logger->info('[HubSpot] Phone match completed', [\n 'phone' => $phone,\n 'response' => $response,\n ]);\n\n return $response->toArray();\n }\n\n private function normalizePhoneNumber(string $phone): string\n {\n return ltrim(phone_e164(null, $phone), '+0');\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $cacheKey = $this->getCacheKey($name, $userId);\n\n $result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {\n $payload = $this->payloadBuilder->generateSearchContactsByNamePayload(\n $name,\n $this->getContactFields()\n );\n\n $hsContacts = $this->client->getPaginatedData($payload, 'contact');\n if (empty($hsContacts['results'])) {\n return false;\n }\n\n $contact = $this->importContact($hsContacts['results'][0]);\n if ($contact === null) {\n return false;\n }\n\n $account = $contact->account;\n $countryCode = $contact->country_code ?? $account->country_code ?? null;\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact->crm_provider_id,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n $opportunity = null;\n $stage = null;\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n });\n\n return is_array($result) ? $result : null;\n }\n\n\n private function convertActivityAssociations(Activity $activity): array\n {\n return [\n 'contactIds' => $this->getParticipantsIds($activity),\n 'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],\n 'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],\n 'ownerIds' => [],\n ];\n }\n\n private function getParticipantsIds(Activity $activity): array\n {\n $attendees = [];\n\n $participantRepository = app(ParticipantRepository::class);\n $participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);\n foreach ($participants as $participant) {\n if ($participant->user_id || $participant->isCoach()) {\n continue;\n }\n\n $contact = $participant->contact()->first();\n if ($contact && $contact->crm_provider_id) {\n $attendees[] = $contact->crm_provider_id;\n } else {\n if (! empty($participant->name)) {\n $attendeeData = $this->fetchMissingAttendeeInfo($participant);\n }\n if (! empty($attendeeData['id'])) {\n $attendees[] = $attendeeData['id'];\n }\n }\n }\n\n if ($activity->hasContact()) {\n $attendees[] = $activity->contact->crm_provider_id;\n }\n\n return array_unique($attendees);\n }\n\n private function fetchMissingAttendeeInfo(Participant $participant): array\n {\n // Check if we need to look inside an account context.\n $activity = $participant->getActivity();\n $companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;\n\n // First check the local data.\n /** @var Contact[] $contacts */\n $contacts = $this->team->contacts()\n ->with('account')\n ->where('name', $participant->name)\n ->whereNotNull('email')\n ->get();\n\n foreach ($contacts as $contact) {\n // If we have a company in scope, check the contact is associated to it.\n if (\n $companyId !== null\n && ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)\n ) {\n continue;\n }\n\n return [\n 'id' => $contact->crm_provider_id,\n 'email' => $contact->email,\n ];\n }\n\n $payload = $this->generateNameSearchPayload($participant->name, 0, 20);\n\n try {\n $response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);\n\n // TODO add some logic to choose the most suitable contact if multiple\n foreach ($response['results'] as $object) {\n $properties = $object['properties'];\n if (empty($object['properties']) === false) {\n // Check the company matches the contact.\n // Todo: Move this check inside the API search.\n if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {\n continue;\n }\n\n return [\n 'id' => $object['id'],\n 'email' => $properties['email'],\n ];\n }\n }\n } catch (Exception $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [\n 'teamId' => $this->team->id_string,\n 'request' => $payload,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return [];\n }\n\n /**\n * Store transcripts as note engagement.\n *\n * @throws Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n // For HS no need to check if Crm profile - Log Notes field is enabled\n // We only check if store_transcript toggle is enabled on crm profile.\n $engagement = [\n 'active' => true,\n 'ownerId' => $this->profile->crm_provider_id,\n 'timestamp' => $activity->created_at->tz($activity->user->timezone)->getTimestamp() * 1000,\n 'type' => 'NOTE',\n ];\n\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, static::ENGAGEMENT_BODY_MAX_LENGTH);\n\n $metadata = [\n 'body' => $transcripts,\n ];\n\n $associations = $this->convertActivityAssociations($activity);\n\n try {\n $hsEngagement = $this->client\n ->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n\n $this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);\n\n $noteId = $hsEngagement->data->engagement->id;\n\n // Store crm logged id in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $noteId;\n $transcription->save();\n } catch (Exception $e) {\n Sentry::captureException($e);\n }\n }\n\n /*\n * @inheritdoc\n */\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $payload = [\n 'properties' => $data,\n ];\n\n try {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n $this->client->getNewInstance()->crm()->deals()->basicApi()->update($objectId, $payload);\n\n break;\n case FieldData::OBJECT_CONTACT:\n $this->client->getNewInstance()->crm()->contacts()->basicApi()->update($objectId, $payload);\n\n break;\n\n case FieldData::OBJECT_ACCOUNT:\n $this->client->getNewInstance()->crm()->companies()->basicApi()->update($objectId, $payload);\n\n break;\n\n case FieldData::OBJECT_TASK:\n // Endpoint for Engagements not ready\n $engagements = [\n 'type' => 'TASK',\n ];\n $metadata = $data;\n $this->client->getInstance()->engagements()->update($objectId, $engagements, $metadata);\n\n $this->logCrmEngagementManipulation(\n self::ACTION_UPDATE,\n ['crmId' => $objectId],\n $metadata,\n );\n\n break;\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n } catch (\\HubSpot\\Client\\Crm\\Deals\\ApiException $apiException) {\n $errorMessage = $apiException->getMessage();\n if ($apiException->getResponseBody()) {\n $responseBody = json_decode($apiException->getResponseBody(), true, 512, JSON_THROW_ON_ERROR);\n $errorMessage = $responseBody['message'] ?? $apiException->getMessage();\n }\n\n $this->logger->error(\n '[HubSpot] Update record failed',\n [\n 'objectType' => $objectType,\n 'objectId' => $objectId,\n 'payload' => $payload,\n 'reason' => $errorMessage,\n 'team' => $this->team->getUuid(),\n ]\n );\n\n throw new CrmException($errorMessage);\n }\n }\n\n /*\n * @inheritdoc\n */\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n return $this->client->getInstance()->deals()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_CONTACT:\n return $this->client->getInstance()->contacts()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_ACCOUNT:\n return $this->client->getInstance()->companies()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_TASK:\n return $this->client->getInstance()->engagements()->get($objectId)->toArray();\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n }\n\n /**\n * @throws BadRequest\n * @throws CrmException\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n $payload = [\n 'properties' => [\n [\n 'name' => 'dealstage',\n 'value' => $stage->crm_provider_id,\n ],\n ],\n ];\n\n try {\n $this->client->getInstance()->deals()->update($crmObject->crm_provider_id, $payload);\n } catch (BadRequest $badRequest) {\n if ($badRequest->getCode() === 403) {\n throw new CrmException(\n \"Sorry, you don't have permission to update this stage.\",\n $badRequest->getCode(),\n $badRequest,\n );\n }\n\n $this->logger->warning('[HubSpot] Stage update failed', [\n 'dealId' => $crmObject->crm_provider_id,\n 'payload' => $payload,\n 'message' => $badRequest->getMessage(),\n ]);\n\n throw $badRequest;\n }\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $url = null;\n $baseUrl = 'https://app.hubspot.com/contacts/' . $this->config->crm_provider_id . '/';\n\n switch ($objectType) {\n case 'account':\n $url = $baseUrl . 'company/' . $providerId;\n\n break;\n\n case 'contact':\n $url = $baseUrl . 'contact/' . $providerId;\n\n break;\n\n case 'opportunity':\n $url = $baseUrl . 'deal/' . $providerId;\n\n break;\n\n case 'task':\n case 'activity':\n return null;\n\n // This should not be deep-linked as per JMNY-3934.\n //$url = $baseUrl.'tasks/list/view/all/?taskId='.$providerId;\n break;\n }\n\n return $url;\n }\n\n public function searchCalls(Carbon $from, Carbon $to, string $activityProvider): array\n {\n $this->logger->info('[HubSpot] Search calls', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n ]);\n\n $calls = [];\n $page = 1;\n\n do {\n try {\n $payload = $this->payloadBuilder->generateGetCallsPayload($from, $to, $activityProvider, $page);\n $response = $this->client->getInstance()->getClient()->request(\n 'POST',\n self::CALLS_SEARCH_ENDPOINT,\n ['json' => ($payload)],\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search calls failed', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n 'reason' => $exception->getMessage(),\n ]);\n $response = null;\n }\n\n $responseResults = empty($response['results']) ? [] : $response['results'];\n $calls = array_merge($calls, $responseResults);\n $page++;\n } while (! empty($responseResults));\n\n return $calls;\n }\n\n public function searchCallsForPeriodByPage(Carbon $from, Carbon $to, int $page, bool $retry = true)\n {\n try {\n $payload = $this->payloadBuilder->generateSearchCallsByPeriodPayload($from, $to, $page);\n $response = $this->client->getInstance()->getClient()->request(\n 'POST',\n self::CALLS_SEARCH_ENDPOINT,\n ['json' => ($payload)],\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search calls for period failed', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n 'reason' => $exception->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep(1);\n\n return $this->searchCallsForPeriodByPage($from, $to, $page, false);\n }\n $response = null;\n }\n\n return $response;\n }\n\n public function searchCallsForPeriod(Carbon $from, Carbon $to): Generator\n {\n $this->logger->info('[HubSpot] Search calls for period', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n ]);\n\n $page = 1;\n\n do {\n $response = $this->searchCallsForPeriodByPage($from, $to, $page);\n\n $responseResults = empty($response['results']) ? [] : $response['results'];\n\n $associationContacts = $this->getAssociationDataForCollection($responseResults, 'calls', 'contacts');\n $associationCompanies = $this->getAssociationDataForCollection($responseResults, 'calls', 'companies');\n $associationDeals = $this->getAssociationDataForCollection($responseResults, 'calls', 'deals');\n\n foreach ($responseResults as $call) {\n $call['associations'] = [\n 'contacts' => $this->importAssociationData($call, $associationContacts),\n 'companies' => $this->importAssociationData($call, $associationCompanies),\n 'deals' => $this->importAssociationData($call, $associationDeals),\n ];\n\n yield $call;\n }\n $page++;\n } while (! empty($responseResults));\n }\n\n public function getCall(string $callId): array\n {\n $this->logger->info('[HubSpot] Get call', [\n 'call_id' => $callId,\n ]);\n\n $searchAttributes = $this->payloadBuilder->getSearchCallAttributes();\n $endpoint = sprintf(\n 'https://api.hubapi.com/crm/v3/objects/calls/%s',\n $callId,\n );\n\n try {\n $response = $this->client->getInstance()->getClient()->request(\n 'GET',\n $endpoint,\n [],\n sprintf(\n 'properties=%s&associations=contacts,companies,deals',\n implode(',', $searchAttributes),\n ),\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Get call failed', [\n 'call_id' => $callId,\n 'reason' => $exception->getMessage(),\n ]);\n $response = null;\n }\n\n return empty($response) ? [] : $response->toArray();\n }\n\n public function bulkAddPlaybackURLToDescription(array $crmUpdateData): array\n {\n $crmUpdateBatches = array_chunk($crmUpdateData, self::BATCH_UPDATE_LIMIT);\n\n $updatedCrmIds = [];\n\n foreach ($crmUpdateBatches as $crmBatch) {\n $payload = $this->payloadBuilder->generatePlaybackAddUrlBatchPayload($crmBatch);\n $updateSuccess = $this->bulkAddPlaybackURLToDescriptionRequest($payload);\n if ($updateSuccess) {\n $updatedCrmIds = array_merge($updatedCrmIds, array_column($crmBatch, 'crm_id'));\n }\n }\n\n return $updatedCrmIds;\n }\n\n private function bulkAddPlaybackURLToDescriptionRequest(array $payload, bool $retry = true): bool\n {\n try {\n $this->client->getNewInstance()->crm()->objects()->batchApi()->update('calls', $payload);\n\n return true;\n } catch (\\HubSpot\\Client\\Crm\\Objects\\ApiException $e) {\n $response = json_decode($e->getResponseBody(), true);\n $retryAfter =\n isset($response['policyName'])\n && $response['policyName'] == self::TEN_SECONDLY_ROLLING_POLICY\n ? self::TEN_SECONDLY_ROLLING_LIMIT\n : 1;\n } catch (Exception $e) {\n $retryAfter = 1;\n }\n\n $this->logger->warning('[HubSpot] Bulk add playback url to CRM failed', [\n 'reason' => $e->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep($retryAfter);\n\n return $this->bulkAddPlaybackURLToDescriptionRequest($payload, false);\n }\n\n return false;\n }\n\n /**\n * Sometimes we have secondly rate limit error, then retry request after 1 second\n */\n public function searchCallByRecordingURLToken(string $playbackURLToken, bool $retry = true): array\n {\n $endpoint = 'https://api.hubapi.com/crm/v3/objects/calls/search';\n $payload = $this->payloadBuilder->generateSearchCallByTokenPayload($playbackURLToken);\n\n $this->logger->info('[HubSpot] CRM Search by playback URL token requested', [\n 'request' => $payload,\n ]);\n\n try {\n $response = $this->client->getInstance()->getClient()->request('POST', $endpoint, ['json' => ($payload)]);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search by playback URL token failed', [\n 'playbackURLToken' => $playbackURLToken,\n 'reason' => $exception->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep(1);\n\n return $this->searchCallByRecordingURLToken($playbackURLToken, false);\n }\n\n return [];\n }\n\n return empty($response['results']) ? [] : $response['results'][0];\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! $this->config->store_transcript) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n $transcriptionSegments = $this->transcriptionService->findTranscriptionByActivity($activity);\n\n if ($transcriptionSegments->isEmpty()) {\n return '';\n }\n\n $transcription = sprintf(\n '<p><strong>Transcript for %s</strong></p><p></p>',\n $activity->title ?? $activity->activity_title,\n );\n\n $roomOwnerParticipant = $activity->findParticipantRoomOwner();\n $roomOwnerParticipantId = $roomOwnerParticipant !== null\n ? $roomOwnerParticipant->getId()\n : null;\n\n\n $transcription .= $transcriptionSegments\n ->map(static function (array $transcriptionSegment) use ($roomOwnerParticipantId): string {\n $isOrganiser = $roomOwnerParticipantId === $transcriptionSegment['participantId']\n && $roomOwnerParticipantId !== null;\n $transcriptColor = $isOrganiser ? '#000000' : '#f0415a';\n\n return sprintf(\n '<span style=\"color: %s;\">%s | </span>%s',\n $transcriptColor,\n $transcriptionSegment['formattedStartsAt'],\n $transcriptionSegment['transcript'],\n );\n })\n ->implode('<br />');\n\n return $transcription;\n }\n\n /**\n * @param array<array{\n * id: string,\n * label: string,\n * value?: string,\n * }> $options\n *\n * @return FieldData[]\n */\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $values = [];\n $sequence = 0;\n\n foreach ($options as $option) {\n $values[] = [\n 'value' => $option['value'] ?? $option['id'],\n 'label' => substr($option['label'], 0, 255),\n 'sequence' => $sequence++,\n ];\n }\n\n $fieldsToPurge = $field->values()->get()->pluck('value')->toArray();\n\n foreach ($values as $value) {\n $value['value'] = substr($value['value'], 0, 255);\n $fieldValues[] = $field->values()->updateOrCreate([\n 'value' => $value['value'],\n ], $value);\n\n // Remove this value from the ones we are going to purge.\n if (($key = array_search($value['value'], $fieldsToPurge, false)) !== false) {\n unset($fieldsToPurge[$key]);\n }\n }\n\n // Delete the old values that are no longer used.\n $field->values()->whereIn('value', $fieldsToPurge)->delete();\n\n return $fieldValues;\n }\n\n public function saveTranscriptionSummaryAsNote(\n ActivityContract $activity,\n string $title,\n string $body,\n ?string $objectId,\n ?NoteObject $noteObject = null,\n ): ?string {\n if ($noteObject === null || $objectId === null) {\n return null;\n }\n\n /** @var User $user */\n $user = $activity->getUser();\n\n $profile = $this->assignCrmOwner($user, $activity);\n if (! $profile instanceof Profile) {\n return null;\n }\n\n $timestamp = Carbon::now($user->getTimezone())->getTimestamp() * 1000;\n $engagement = [\n 'active' => true,\n 'ownerId' => $profile->getAttribute('crm_provider_id'),\n 'timestamp' => $timestamp,\n 'type' => 'NOTE',\n ];\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $body = mb_strimwidth($body, 0, self::ENGAGEMENT_BODY_MAX_LENGTH);\n $metadata = [\n 'body' => $body,\n ];\n\n $associations = $this->convertActivityAssociations($activity);\n\n try {\n $hsActivityId = $this->client->createNote(\n body: $body,\n ownerId: $profile->getCrmProviderId(),\n timestamp: $timestamp,\n objectId: $objectId,\n noteObject: $noteObject,\n );\n\n $this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);\n\n $this->logger->info('[HubSpot] Saving Transcription Summary as Note', [\n 'activity' => $activity->getUuid(),\n 'crmActivity' => $hsActivityId,\n ]);\n\n return $hsActivityId;\n } catch (Exception $e) {\n Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function attachSummaryToActivity(ActivityContract $activity, string $summaryTitle, string $summaryContents): bool\n {\n $this->logger->info('[HubSpot] Attaching summary to activity', [\n 'activity' => $activity->getUuid(),\n 'summary_content' => $summaryContents,\n ]);\n\n if (! $activity instanceof Activity) {\n throw new InvalidArgumentException('Expected instance of Activity');\n }\n\n $summary = '<p><strong>' . $summaryTitle . '</strong></p>';\n $summary .= '<p>' . $summaryContents . '</p>';\n $metadata = $this->buildMetadataForSummaryUpdate($activity, $summary);\n\n try {\n $type = $this->matchActivityEngagementType($activity);\n $engagement = ['type' => $type];\n\n $this->client->updateEngagement($activity->getCrmProviderId(), $engagement, $metadata);\n } catch (Exception $e) {\n $this->logger->warning('[HubSpot] Update summary failed', [\n 'activity' => $activity->getUuid(),\n 'reason' => $e->getMessage(),\n ]);\n\n return false;\n }\n\n $this->logCrmEngagementManipulation(\n self::ACTION_UPDATE,\n ['crmId' => $activity->getCrmProviderId()],\n $metadata,\n );\n\n return true;\n }\n\n private function buildMetadataForSummaryUpdate(Activity $activity, string $summary): array\n {\n $descriptionField = $activity->getType() === Activity::TYPE_CONFERENCE ? 'internalMeetingNotes' : 'body';\n $engagement = $this->client->getEngagementData($activity->getCrmProviderId());\n // Meeting without internalMeetingNotes might mean it just does not have any notes;\n $description = $engagement['metadata'][$descriptionField] ?? null;\n\n if (empty($description)) {\n $data = $summary;\n } else {\n // avoid playbook url link to Jiminny being sent twice in the activity description\n $targetUrl = PlaybackUrlBuilder::build($activity);\n\n if (str_contains($description, $targetUrl)) {\n $jiminnyUrl = '<p><a href=\"' . $targetUrl . '\" title=\"Play at Jiminny\">Play at Jiminny</a></p>';\n $summary = str_replace($jiminnyUrl, '', $summary);\n\n $this->logger->info('[HubSpot] Summary modified', [\n 'activity' => $activity->getUuid(),\n 'target_url' => $jiminnyUrl,\n 'modified_summary_content' => $summary,\n ]);\n }\n\n $data = $description . '<p></p>' . $summary;\n }\n\n return [\n $descriptionField => $data,\n ];\n }\n\n public function fetchAndAssociateRelatedActivity(Activity $activity): ?Activity\n {\n return $this->syncRelatedActivityManager->fetchAndAssociateRelatedActivity($activity);\n }\n\n public function fetchRelatedActivity(Activity $activity): array\n {\n return [];\n }\n\n public function getDealsInBulk(array $dealIds): array\n {\n $payload = $this->payloadBuilder->getDealsInBulkPayload($dealIds);\n\n return $this->client->getPaginatedData($payload, 'deals');\n }\n\n /**\n * Extract deal IDs from HubSpot search response.\n *\n * @param array $hubspotResponse The raw HubSpot search API response.\n * @param bool $includeArchived Whether to include archived deals (default: false).\n *\n * @return string[] Array of deal IDs as strings.\n */\n public function extractDealIds(array $hubspotResponse, bool $includeArchived = false): array\n {\n if (empty($hubspotResponse['results'])) {\n return [];\n }\n\n return array_values(\n array_map(\n fn ($deal) => $deal['id'],\n array_filter(\n $hubspotResponse['results'],\n fn ($deal) => $includeArchived || empty($deal['archived'])\n )\n )\n );\n }\n\n public function matchActivityEngagementType(Activity $activity): string\n {\n return match ($activity->getType()) {\n Activity::TYPE_CONFERENCE => self::TYPE_MEETING,\n Activity::TYPE_SOFTPHONE, Activity::TYPE_SOFTPHONE_INBOUND => self::TYPE_CALL,\n default => self::TYPE_NOTE,\n };\n }\n\n private function assignCrmOwner(User $user, ActivityContract $activity): ?Profile\n {\n $profile = $user->getProfile();\n if ($profile instanceof Profile) {\n return $profile;\n }\n\n $this->logger->info('[HubSpot] Unable to save summary. No profile', [\n 'activity' => $activity->getUuid(),\n ]);\n\n return null;\n }\n\n private static function getDealsPipelinesEndpoint(): string\n {\n return self::API_URL . self::ENDPOINT_PIPELINES . self::PIPELINE_OBJECT_TYPE_DEALS;\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n $engagement = $this->client->getEngagementData($crmProviderId);\n\n return ! empty($engagement);\n } catch (HttpNotFoundException|BadRequest) {\n // Engagement not found in CRM - this is expected and permanent\n $this->logger->info('[Hubspot] Engagement not found during verification', [\n 'engagement_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\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":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.7140958,"top":0.12529927,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7237367,"top":0.123703115,"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.73105055,"top":0.123703115,"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\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\EmailHelper;\nuse Throwable;\n\nclass FixActivitiesOpportunity extends Command\n{\n protected $signature = 'activity:fix-opportunity {--from=} {--to=}';\n\n public function handle(EmailHelper $emailHelper): int\n {\n $from = $this->option('from');\n $to = $this->option('to');\n\n $validator = Validator::make(\n ['from' => $from, 'to' => $to],\n [\n 'from' => ['required', 'date'],\n 'to' => ['required', 'date'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return Command::FAILURE;\n }\n\n $this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);\n\n $activityIds = Activity::select('activities.id')\n ->whereBetween('activities.created_at', [$from, $to])\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')\n ->whereColumn('opportunities.team_id', '<>', 'users.team_id')\n ->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n\n foreach ($activityIds as $activityId) {\n $activity = Activity::where('id', $activityId)\n ->with(['user', 'participants'])\n ->first();\n\n $crmService = $this->getCrmService($activity->getTeam());\n if ($crmService === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $this->processParticipants($crmService, $emailHelper, $activity);\n }\n\n return Command::SUCCESS;\n }\n\n private function getCrmService(Team $team): ?ServiceInterface\n {\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n try {\n return $crmResolver->prepareCrmService();\n } catch (Throwable $e) {\n $this->error('Could not prepare CRM service: ' . $e->getMessage());\n\n return null;\n }\n }\n\n private function processParticipants(\n ServiceInterface $crmService,\n EmailHelper $emailHelper,\n Activity $activity\n ): void {\n $team = $activity->getTeam();\n $user = $activity->getUser();\n $participants = $activity->getParticipants();\n\n foreach ($participants as $participant) {\n if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {\n continue;\n }\n\n $emailAddress = $participant->getEmailAddress();\n if ($emailHelper->isCompanyEmail($team, $emailAddress)) {\n continue;\n }\n\n try {\n $opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());\n } catch (Throwable $e) {\n $this->error('Could not find opportunity: ' . $e->getMessage());\n\n $opportunity = null;\n }\n\n if ($opportunity === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $activity->update(['opportunity_id' => $opportunity->getId()]);\n\n $this->info('Opportunity updated for activity: ' . $activity->getId());\n }\n }\n\n private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity\n {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n $match = $decorator->matchExactlyByEmail($emailAddress, $userId);\n\n if (empty($match)) {\n $match = $decorator->matchByDomain($emailAddress, $userId);\n }\n\n if (empty($match)) {\n return null;\n }\n\n [, , $opportunity, ,] = $match;\n\n return $opportunity;\n }\n\n private function resetActivityOpportunity(Activity $activity): void\n {\n $this->info('Reset opportunity for activity: ' . $activity->getId());\n $activity->update(['opportunity_id' => null]);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\EmailHelper;\nuse Throwable;\n\nclass FixActivitiesOpportunity extends Command\n{\n protected $signature = 'activity:fix-opportunity {--from=} {--to=}';\n\n public function handle(EmailHelper $emailHelper): int\n {\n $from = $this->option('from');\n $to = $this->option('to');\n\n $validator = Validator::make(\n ['from' => $from, 'to' => $to],\n [\n 'from' => ['required', 'date'],\n 'to' => ['required', 'date'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return Command::FAILURE;\n }\n\n $this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);\n\n $activityIds = Activity::select('activities.id')\n ->whereBetween('activities.created_at', [$from, $to])\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')\n ->whereColumn('opportunities.team_id', '<>', 'users.team_id')\n ->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n\n foreach ($activityIds as $activityId) {\n $activity = Activity::where('id', $activityId)\n ->with(['user', 'participants'])\n ->first();\n\n $crmService = $this->getCrmService($activity->getTeam());\n if ($crmService === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $this->processParticipants($crmService, $emailHelper, $activity);\n }\n\n return Command::SUCCESS;\n }\n\n private function getCrmService(Team $team): ?ServiceInterface\n {\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n try {\n return $crmResolver->prepareCrmService();\n } catch (Throwable $e) {\n $this->error('Could not prepare CRM service: ' . $e->getMessage());\n\n return null;\n }\n }\n\n private function processParticipants(\n ServiceInterface $crmService,\n EmailHelper $emailHelper,\n Activity $activity\n ): void {\n $team = $activity->getTeam();\n $user = $activity->getUser();\n $participants = $activity->getParticipants();\n\n foreach ($participants as $participant) {\n if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {\n continue;\n }\n\n $emailAddress = $participant->getEmailAddress();\n if ($emailHelper->isCompanyEmail($team, $emailAddress)) {\n continue;\n }\n\n try {\n $opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());\n } catch (Throwable $e) {\n $this->error('Could not find opportunity: ' . $e->getMessage());\n\n $opportunity = null;\n }\n\n if ($opportunity === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $activity->update(['opportunity_id' => $opportunity->getId()]);\n\n $this->info('Opportunity updated for activity: ' . $activity->getId());\n }\n }\n\n private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity\n {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n $match = $decorator->matchExactlyByEmail($emailAddress, $userId);\n\n if (empty($match)) {\n $match = $decorator->matchByDomain($emailAddress, $userId);\n }\n\n if (empty($match)) {\n return null;\n }\n\n [, , $opportunity, ,] = $match;\n\n return $opportunity;\n }\n\n private function resetActivityOpportunity(Activity $activity): void\n {\n $this->info('Reset opportunity for activity: ' . $activity->getId());\n $activity->update(['opportunity_id' => null]);\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}]...
|
285020041200234445
|
-537472495523850137
|
visual_change
|
accessibility
|
NULL
|
1 file committed
JY-20903 revert changes in comman 1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
7
51
1
33
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Hubspot;
use Carbon\Carbon;
use Exception;
use Generator;
use GuzzleHttp\Exception\RequestException;
use HubSpot\Client\Crm\Owners\Model\PublicOwner;
use Illuminate\Support\Facades\Cache;
use InvalidArgumentException;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Contracts\Services\Crm\ClientInterface;
use Jiminny\Contracts\Services\Crm\FetchRelatedActivityInterface;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\HubspotInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SavePlaybackLinkToCrmInterface;
use Jiminny\Contracts\Services\Crm\SendSummaryToCrmInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Contracts\ActivityContract;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\Layout;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Participant;
use Jiminny\Models\Playbook;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Repositories\ParticipantRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Hubspot\Actions\SyncArchivedProfilesAction;
use Jiminny\Services\Crm\Hubspot\Fields\ValueNormalizer;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\OpportunitySyncTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncCrmEntitiesTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncFieldsTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\WriteCrmTrait;
use Jiminny\Services\Crm\MatchDomainByEmailInterface;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\ResolveCompanyNameByEmailTrait;
use Jiminny\Utils\PlaybackUrlBuilder;
use Sentry;
use SevenShores\Hubspot\Exceptions\BadRequest;
use Throwable;
use UnexpectedValueException;
/**
* @phpstan-type CrmFieldDefinition array{
* name: string,
* label: string,
* description: string,
* type: string,
* fieldType: string,
* hidden: bool,
* showCurrencySymbol: bool,
* options: array<array{
* id: string,
* label: string,
* value?: string,
* }
*/
class Service extends BaseService implements
HubspotInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
SendSummaryToCrmInterface,
MatchDomainByEmailInterface,
SavePlaybackLinkToCrmInterface,
RemoteEntityManipulationInterface,
FetchRelatedActivityInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use ResolveCompanyNameByEmailTrait;
use SyncCrmEntitiesTrait;
use WriteCrmTrait;
use SyncFieldsTrait;
use OpportunitySyncTrait;
private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;
private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';
private const int BATCH_UPDATE_LIMIT = 100;
private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';
private const int TEN_SECONDLY_ROLLING_LIMIT = 10;
private const string CALLS_SEARCH_ENDPOINT = '[URL_WITH_CREDENTIALS] ClientInterface|Client
*/
protected $client;
protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;
protected CrmEntityRepository $crmEntityRepository;
protected ProspectPhotoPathService $prospectPhotoPathService;
private SyncFieldAction $syncFieldAction;
private PayloadBuilder $payloadBuilder;
private SyncRelatedActivityManager $syncRelatedActivityManager;
private SyncArchivedProfilesAction $syncArchivedProfilesAction;
private WebhookSyncBatchProcessor $batchProcessor;
public function __construct(
Client $client,
SyncFieldAction $syncFieldAction,
PayloadBuilder $payloadBuilder,
ProspectPhotoPathService $prospectPhotoPathService,
SyncArchivedProfilesAction $syncArchivedProfilesAction,
WebhookSyncBatchProcessor $batchProcessor,
) {
parent::__construct();
$this->client = $client;
$this->syncFieldAction = $syncFieldAction;
$this->prospectPhotoPathService = $prospectPhotoPathService;
$this->payloadBuilder = $payloadBuilder;
$this->syncArchivedProfilesAction = $syncArchivedProfilesAction;
$this->batchProcessor = $batchProcessor;
$this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->client,
]);
$this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [
'client' => $this->client,
'payloadBuilder' => $this->payloadBuilder,
'logger' => $this->logger,
]);
$this->crmEntityRepository = app(CrmEntityRepository::class);
$this->dealFieldsService = app(DealFieldsService::class);
}
public function getDisplayName(): string
{
return 'HubSpot';
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
$owner = $user->team->owner;
return $owner->getSocialAccount(SocialAccount::PROVIDER_HUBSPOT);
}
public function getClient(): Client
{
/** @var Client */
return $this->client;
}
/**
* Convert raw field data into a format compatible with CRM APIs.
*
* @param bool $internal Direction of the conversion.
* True is pulling from CRM, false normalize before sending to CRM.
*/
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return ValueNormalizer::normalize(
fieldType: $fieldType,
fieldValue: $fieldValue,
isInbound: $internal,
);
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
/** @var Field $activityField */
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'activityType',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
/**
* @inheritdoc
*/
public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
// Outcome should always be provided calls/meetings.
$fieldData = [
[
'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',
'object_type' => Field::OBJECT_TASK,
],
];
foreach ($fieldData as $data) {
$field = $this->config->fields()->where($data)->first();
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
}
return $fields;
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldData = FieldDefinitions::followupFieldsFilter();
foreach ($fieldData as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function syncField(Field $field): void
{
switch ($field->object_type) {
case Field::OBJECT_ACCOUNT:
$crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_CONTACT:
$crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_OPPORTUNITY:
$crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_TASK:
$this->syncSingleTaskField($field);
return;
default:
return;
}
$this->syncFieldAction->execute($field, $crmField->toArray());
}
/**
* @param array<array{
* id:string,
* label:string,
* value?:string
* }> $options
*
* @throws CrmException
*
* @return FieldData[]
*
*/
public function importPicklistValues(
Field $field,
array $options = [['id' => '', 'label' => '', 'value' => '']],
): array {
if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {
// We already have the options, no need to fetch them again
return $this->importOptions($field, $options);
}
$options = [];
switch ($field->getObjectType()) {
case Field::OBJECT_ACCOUNT:
$options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());
break;
case Field::OBJECT_CONTACT:
$options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());
break;
case Field::OBJECT_OPPORTUNITY:
// Hubspot has different endpoint for stages
$options = $this->getClient()->fetchOpportunityFieldOptions($field);
break;
case Field::OBJECT_TASK:
if ($field->getCrmProviderId() === 'disposition') {
$options = $this->getClient()->fetchDispositionFieldOptions();
} elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {
$options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);
}
break;
default:
$this->logger->warning('Invalid object type', [
'object_type' => $field->getObjectType(),
'field_id' => $field->getId(),
]);
throw new CrmException('Invalid object type');
}
return $this->importOptions($field, $options);
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
$missingStage = null;
try {
// Use the HubSpot API client instead of the SDK crmPipelines() method
$endpoint = self::getDealsPipelinesEndpoint();
$pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);
$pipelines = $pipelinesResponse->data->results;
} catch (RequestException|BadRequest $exception) {
throw $exception;
}
foreach ($pipelines as $pipeline) {
$stages = [];
// We create a business process to contain the pipeline, and store all stages against it.
$p = ResponseNormalize::normalizePipeline($pipeline);
// Create/update business process for this pipeline
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => $p['active'],
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
// Create/update record type clone
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'is_selectable' => $p['active'],
'business_process_id' => $businessProcess->id ?? null,
]);
// Stages - fetch all existing stages upfront to avoid N+1 queries
$existingStages = $this->config->stages()
->withTrashed()
->where('type', Stage::TYPE_OPPORTUNITY)
->get()
->keyBy('crm_provider_id');
foreach ($p['stages'] as $dealStage) {
$s = ResponseNormalize::normalizeDealStage($dealStage);
/** @var ?Stage $existingStage */
$existingStage = $existingStages->get($s['id']);
// Restore soft-deleted stages that are now active in HubSpot
if ($existingStage?->trashed() && $s['active']) {
$existingStage->restore();
}
// Upsert stage (updates soft-deleted records without restoring them)
$stage = $this->config->stages()->withTrashed()->updateOrCreate([
'crm_provider_id' => $s['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($s['label'], 0, 50),
'label' => mb_strimwidth($s['label'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $s['displayOrder'],
'is_selectable' => $s['active'],
'probability' => $s['probability'] * 100,
]);
if ($missingStageName === $s['id']) {
$missingStage = $stage;
}
$stages[] = $stage->id;
}
$businessProcess->stages()->sync($stages);
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
try {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
/** @var array<int, array<string, mixed>> */
return Cache::remember(
key: $this->team->getId() . $name . $count . $offset,
ttl: 300,
callback: function () use ($name, $offset, $count): array {
$data = [];
// Use the new V3 API to find contacts based on additional fields.
foreach (['companies', 'contacts'] as $objectType) {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
if ($crmAccountId === null) {
return $data;
}
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
$closedStages = $this->getClosedDealStages();
$payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(
$this->config,
$crmAccountId,
$closedStages,
);
$results = $this->client->getPaginatedData($payload, 'deals');
foreach ($results['results'] as $object) {
$properties = $object['properties'];
$amount = null;
if (empty($properties['amount']) === false) {
$currency = $properties['deal_currency_code'] ?? $this->config->default_currency;
// Values can contain commas and any junk so strip them.
$value = (float) preg_replace('/[^\d.]/', '', $properties['amount']);
$amount = formatCurrency($value, $currency);
}
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
if ($businessProcess === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
} else {
$stage = $businessProcess
->stages()
->where('crm_provider_id', $properties['dealstage'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages(null, $properties['dealstage']);
}
}
$recordType = null;
if ($businessProcess) {
$recordType = $businessProcess->recordTypes()->first();
}
$isWon = in_array($properties['dealstage'], $closedStages['won']);
$isLost = in_array($properties['dealstage'], $closedStages['lost']);
$record = [
'crmId' => $object['id'],
'name' => $properties['dealname'] ?? 'Unknown Deal',
'value' => $amount,
'won' => $isWon,
'closed' => $isWon || $isLost,
'stage' => [
'id' => $stage?->getUuid() ?? '',
'name' => $stage?->getName() ?? '',
],
];
if ($recordType) {
$record += [
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
}
if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
if (! empty($ownerData)) {
return $ownerData;
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(?string $objectType, string $objectId, ?string $opportunityId): array
{
$data = [];
switch ($objectType) {
case 'contact':
$hsObject = 'contact';
break;
case 'account':
$hsObject = 'company';
break;
default:
// This is a hack to prioritise and override a contact/company with a deal.
if ($opportunityId) {
$hsObject = 'deal';
$objectId = $opportunityId;
} else {
throw new InvalidArgumentException('Object type not supported.');
}
}
$engagementTypes = ['meetings', 'tasks'];
foreach ($engagementTypes as $engagementType) {
$payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);
$this->logger->info('[HubSpot] CRM Search requested', [
'request' => $payload,
]);
$engagements = $this->client->getPaginatedData($payload, $engagementType);
foreach ($engagements['results'] as $engagement) {
if ($engagementType == 'meetings') {
$title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';
} elseif ($engagementType == 'tasks') {
$title = $engagement['properties']['hs_task_subject'];
} else {
$title = 'Scheduled meeting';
}
$data[] = [
'crmId' => $engagement['id'],
'subject' => $title,
'due' => $engagement['properties']['hs_timestamp'],
'type' => $engagement['properties']['hs_activity_type'] ?? null,
];
}
}
usort($data, function ($item1, $item2) {
return $item2['due'] <=> $item1['due'];
});
return $data;
}
/**
* Try to find CRM Objects using email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$contactProperties = [
'email',
'firstname',
'lastname',
'country',
'phone',
'mobilephone',
'jobtitle',
'hubspot_owner_id',
'associatedcompanyid',
'photo',
];
$contact = null;
$account = null;
try {
$hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);
if ($hsContact) {
$contact = $this->importContact($hsContact);
$account = $contact->account;
}
$data = $this->convertCrmData($contact, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
} catch (BadRequest $e) {
$this->logger->warning('[HubSpot] Search failed', [
'team_id' => $this->team->getId(),
'search_identifier' => $email,
'reason' => $e->getMessage(),
]);
}
return null;
}
public function getDomain(string $email): ?string
{
return $this->getDomainFromEmail($email);
}
/**
* Try to find CRM objects using domain name of the email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByDomain(string $domain, ?int $userId = null): ?array
{
$companyName = $domain;
// Try to find a company matching their email domain.
$companyProperties = [
'country',
'phone',
'name',
'hs_avatar_filemanager_key',
'industry',
'hubspot_owner_id',
'domain',
];
try {
$hsAccounts = $this->client
->getInstance()
->companies()
->searchByDomain($companyName, $companyProperties);
} catch (Throwable $e) {
$this->logger->info('[HubSpot] Search failed', [
'error' => $e->getMessage(),
'domain' => $domain,
]);
return null;
}
$account = null;
// If there are multiple accounts, don't guess, we'll ask later.
if (\count($hsAccounts->data->results) === 1) {
// Persist this remote object.
$account = $this->syncAccount($hsAccounts->data->results[0]->companyId);
}
$data = $this->convertCrmData(null, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
}
/**
* @return array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array
{
$countryCode = null;
if ($contact && $contact->country_code) {
$countryCode = $contact->country_code;
} elseif ($account && $account->country_code) {
$countryCode = $account->country_code;
}
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
// If there are multiple opportunities, don't guess, we'll ask later.
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
protected function getCacheKey(string $object, ?int $userId = null): ?string
{
$key = $this->team->getId() . $object;
$keySuffix = $this->getOwnerKeySuffix($userId);
return $key . $keySuffix;
}
private function getOwnerKeySuffix(?int $userId = null): string
{
return $userId === null ? '' : (string) $userId;
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array
{
if (str_contains($phone, '**')) {
return null;
}
// trim all whitespaces if present so the lookup doesn't fail
$phone = str_replace(' ', '', $phone);
// Check if the user is internal.
if ($this->isPhoneNumberOfTeamMember($phone)) {
return null;
}
$response = $this->searchForPhoneNumber($phone);
if (empty($response)) {
return null;
}
// This would ideally importContact instead but the response type differs.
$contact = $this->findAndSyncContact($response['results'][0]['id']);
if (! $contact instanceof Contact) {
return null;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account?->crm_provider_id,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
try {
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
} catch (Exception $e) {
$this->logger->debug('[HubSpot] Opportunity failed to sync.', [
'reason' => $e->getMessage(),
]);
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
private function isPhoneNumberOfTeamMember(string $phone): bool
{
$teamRepository = app(TeamRepository::class);
$user = $teamRepository->findTeamMemberByPhone($this->team, $phone);
if ($user instanceof User) {
return true;
}
return false;
}
private function findAndSyncContact(string $crmId): ?Contact
{
try {
return $this->syncContact($crmId);
} catch (Exception $exception) {
$this->logger->info('[HubSpot] Phone match failed', [
'reason' => $exception->getMessage(),
]);
return null;
}
}
private function hasResults(array $response): bool
{
return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;
}
private function searchForPhoneNumber(string $phone): array
{
// Normalizes the provided phone number for the API search.
$normalizedPhone = $this->normalizePhoneNumber($phone);
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);
$this->logger->info('[HubSpot] Phone match search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);
if (! $this->hasResults($response)) {
$nationalPhone = preg_replace('/\D/', '', phone_national(null, $phone));
$payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);
$this->logger->info('[HubSpot] Phone match national number search triggered', [
'phone' => $phone,
'nationalPhone' => $nationalPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
if (! $this->hasResults($response)) {
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);
$this->logger->info('[HubSpot] Phone match alternative search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
return $this->hasResults($response) ? $response : [];
}
private function handlePhoneSearchRequest(string $phone, array $payload): array
{
$endpoint = '[URL_WITH_CREDENTIALS] null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByName(string $name, ?int $userId = null): ?array
{
// Don't waste time searching for single character strings.
if (\strlen($name) <= 1) {
return null;
}
$cacheKey = $this->getCacheKey($name, $userId);
$result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {
$payload = $this->payloadBuilder->generateSearchContactsByNamePayload(
$name,
$this->getContactFields()
);
$hsContacts = $this->client->getPaginatedData($payload, 'contact');
if (empty($hsContacts['results'])) {
return false;
}
$contact = $this->importContact($hsContacts['results'][0]);
if ($contact === null) {
return false;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
});
return is_array($result) ? $result : null;
}
private function convertActivityAssociations(Activity $activity): array
{
return [
'contactIds' => $this->getParticipantsIds($activity),
'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],
'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],
'ownerIds' => [],
];
}
private function getParticipantsIds(Activity $activity): array
{
$attendees = [];
$participantRepository = app(ParticipantRepository::class);
$participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);
foreach ($participants as $participant) {
if ($participant->user_id || $participant->isCoach()) {
continue;
}
$contact = $participant->contact()->first();
if ($contact && $contact->crm_provider_id) {
$attendees[] = $contact->crm_provider_id;
} else {
if (! empty($participant->name)) {
$attendeeData = $this->fetchMissingAttendeeInfo($participant);
}
if (! empty($attendeeData['id'])) {
$attendees[] = $attendeeData['id'];
}
}
}
if ($activity->hasContact()) {
$attendees[] = $activity->contact->crm_provider_id;
}
return array_unique($attendees);
}
private function fetchMissingAttendeeInfo(Participant $participant): array
{
// Check if we need to look inside an account context.
$activity = $participant->getActivity();
$companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;
// First check the local data.
/** @var Contact[] $contacts */
$contacts = $this->team->contacts()
->with('account')
->where('name', $participant->name)
->whereNotNull('email')
->get();
foreach ($contacts as $contact) {
// If we have a company in scope, check the contact is associated to it.
if (
$companyId !== null
&& ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)
) {
continue;
}
return [
'id' => $contact->crm_provider_id,
'email' => $contact->email,
];
}
$payload = $this->generateNameSearchPayload($participant->name, 0, 20);
try {
$response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);
// TODO add some logic to choose the most suitable contact if multiple
foreach ($response['results'] as $object) {
$properties = $object['properties'];
if (empty($object['properties']) === false) {
// Check the company matches the contact.
// Todo: Move this check inside the API search.
if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {
continue;
}
return [
'id' => $object['id'],
'email' => $properties['email'],
];
}
}
} catch (Exception $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [
'teamId' => $this->team->id_string,
'request' => $payload,
'reason' => $e->getMessage(),
]);
}
return [];
}
/**
* Store transcripts as note engagement.
*
* @throws Exception
*/
public function createTranscriptNotes(Activity $activity): void
{
// For HS no need to check if Crm profile - Log Notes field is enabled
// We only check if store_transcript toggle is enabled on crm profile.
$engagement = [
'active' => true,
'ownerId' => $this->profile->crm_provider_i...
|
43632
|
NULL
|
NULL
|
NULL
|
|
43634
|
1591
|
6
|
2026-05-14T13:03:11.739862+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763791739_m1.jpg...
|
PhpStorm
|
faVsco.js – Service.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
1 file committed
JY-20903 revert changes in comman 1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
7
51
1
33
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Hubspot;
use Carbon\Carbon;
use Exception;
use Generator;
use GuzzleHttp\Exception\RequestException;
use HubSpot\Client\Crm\Owners\Model\PublicOwner;
use Illuminate\Support\Facades\Cache;
use InvalidArgumentException;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Contracts\Services\Crm\ClientInterface;
use Jiminny\Contracts\Services\Crm\FetchRelatedActivityInterface;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\HubspotInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SavePlaybackLinkToCrmInterface;
use Jiminny\Contracts\Services\Crm\SendSummaryToCrmInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Contracts\ActivityContract;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\Layout;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Participant;
use Jiminny\Models\Playbook;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Repositories\ParticipantRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Hubspot\Actions\SyncArchivedProfilesAction;
use Jiminny\Services\Crm\Hubspot\Fields\ValueNormalizer;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\OpportunitySyncTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncCrmEntitiesTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncFieldsTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\WriteCrmTrait;
use Jiminny\Services\Crm\MatchDomainByEmailInterface;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\ResolveCompanyNameByEmailTrait;
use Jiminny\Utils\PlaybackUrlBuilder;
use Sentry;
use SevenShores\Hubspot\Exceptions\BadRequest;
use Throwable;
use UnexpectedValueException;
/**
* @phpstan-type CrmFieldDefinition array{
* name: string,
* label: string,
* description: string,
* type: string,
* fieldType: string,
* hidden: bool,
* showCurrencySymbol: bool,
* options: array<array{
* id: string,
* label: string,
* value?: string,
* }
*/
class Service extends BaseService implements
HubspotInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
SendSummaryToCrmInterface,
MatchDomainByEmailInterface,
SavePlaybackLinkToCrmInterface,
RemoteEntityManipulationInterface,
FetchRelatedActivityInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use ResolveCompanyNameByEmailTrait;
use SyncCrmEntitiesTrait;
use WriteCrmTrait;
use SyncFieldsTrait;
use OpportunitySyncTrait;
private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;
private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';
private const int BATCH_UPDATE_LIMIT = 100;
private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';
private const int TEN_SECONDLY_ROLLING_LIMIT = 10;
private const string CALLS_SEARCH_ENDPOINT = '[URL_WITH_CREDENTIALS] ClientInterface|Client
*/
protected $client;
protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;
protected CrmEntityRepository $crmEntityRepository;
protected ProspectPhotoPathService $prospectPhotoPathService;
private SyncFieldAction $syncFieldAction;
private PayloadBuilder $payloadBuilder;
private SyncRelatedActivityManager $syncRelatedActivityManager;
private SyncArchivedProfilesAction $syncArchivedProfilesAction;
private WebhookSyncBatchProcessor $batchProcessor;
public function __construct(
Client $client,
SyncFieldAction $syncFieldAction,
PayloadBuilder $payloadBuilder,
ProspectPhotoPathService $prospectPhotoPathService,
SyncArchivedProfilesAction $syncArchivedProfilesAction,
WebhookSyncBatchProcessor $batchProcessor,
) {
parent::__construct();
$this->client = $client;
$this->syncFieldAction = $syncFieldAction;
$this->prospectPhotoPathService = $prospectPhotoPathService;
$this->payloadBuilder = $payloadBuilder;
$this->syncArchivedProfilesAction = $syncArchivedProfilesAction;
$this->batchProcessor = $batchProcessor;
$this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->client,
]);
$this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [
'client' => $this->client,
'payloadBuilder' => $this->payloadBuilder,
'logger' => $this->logger,
]);
$this->crmEntityRepository = app(CrmEntityRepository::class);
$this->dealFieldsService = app(DealFieldsService::class);
}
public function getDisplayName(): string
{
return 'HubSpot';
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
$owner = $user->team->owner;
return $owner->getSocialAccount(SocialAccount::PROVIDER_HUBSPOT);
}
public function getClient(): Client
{
/** @var Client */
return $this->client;
}
/**
* Convert raw field data into a format compatible with CRM APIs.
*
* @param bool $internal Direction of the conversion.
* True is pulling from CRM, false normalize before sending to CRM.
*/
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return ValueNormalizer::normalize(
fieldType: $fieldType,
fieldValue: $fieldValue,
isInbound: $internal,
);
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
/** @var Field $activityField */
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'activityType',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
/**
* @inheritdoc
*/
public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
// Outcome should always be provided calls/meetings.
$fieldData = [
[
'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',
'object_type' => Field::OBJECT_TASK,
],
];
foreach ($fieldData as $data) {
$field = $this->config->fields()->where($data)->first();
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
}
return $fields;
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldData = FieldDefinitions::followupFieldsFilter();
foreach ($fieldData as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function syncField(Field $field): void
{
switch ($field->object_type) {
case Field::OBJECT_ACCOUNT:
$crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_CONTACT:
$crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_OPPORTUNITY:
$crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_TASK:
$this->syncSingleTaskField($field);
return;
default:
return;
}
$this->syncFieldAction->execute($field, $crmField->toArray());
}
/**
* @param array<array{
* id:string,
* label:string,
* value?:string
* }> $options
*
* @throws CrmException
*
* @return FieldData[]
*
*/
public function importPicklistValues(
Field $field,
array $options = [['id' => '', 'label' => '', 'value' => '']],
): array {
if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {
// We already have the options, no need to fetch them again
return $this->importOptions($field, $options);
}
$options = [];
switch ($field->getObjectType()) {
case Field::OBJECT_ACCOUNT:
$options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());
break;
case Field::OBJECT_CONTACT:
$options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());
break;
case Field::OBJECT_OPPORTUNITY:
// Hubspot has different endpoint for stages
$options = $this->getClient()->fetchOpportunityFieldOptions($field);
break;
case Field::OBJECT_TASK:
if ($field->getCrmProviderId() === 'disposition') {
$options = $this->getClient()->fetchDispositionFieldOptions();
} elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {
$options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);
}
break;
default:
$this->logger->warning('Invalid object type', [
'object_type' => $field->getObjectType(),
'field_id' => $field->getId(),
]);
throw new CrmException('Invalid object type');
}
return $this->importOptions($field, $options);
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
$missingStage = null;
try {
// Use the HubSpot API client instead of the SDK crmPipelines() method
$endpoint = self::getDealsPipelinesEndpoint();
$pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);
$pipelines = $pipelinesResponse->data->results;
} catch (RequestException|BadRequest $exception) {
throw $exception;
}
foreach ($pipelines as $pipeline) {
$stages = [];
// We create a business process to contain the pipeline, and store all stages against it.
$p = ResponseNormalize::normalizePipeline($pipeline);
// Create/update business process for this pipeline
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => $p['active'],
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
// Create/update record type clone
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'is_selectable' => $p['active'],
'business_process_id' => $businessProcess->id ?? null,
]);
// Stages - fetch all existing stages upfront to avoid N+1 queries
$existingStages = $this->config->stages()
->withTrashed()
->where('type', Stage::TYPE_OPPORTUNITY)
->get()
->keyBy('crm_provider_id');
foreach ($p['stages'] as $dealStage) {
$s = ResponseNormalize::normalizeDealStage($dealStage);
/** @var ?Stage $existingStage */
$existingStage = $existingStages->get($s['id']);
// Restore soft-deleted stages that are now active in HubSpot
if ($existingStage?->trashed() && $s['active']) {
$existingStage->restore();
}
// Upsert stage (updates soft-deleted records without restoring them)
$stage = $this->config->stages()->withTrashed()->updateOrCreate([
'crm_provider_id' => $s['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($s['label'], 0, 50),
'label' => mb_strimwidth($s['label'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $s['displayOrder'],
'is_selectable' => $s['active'],
'probability' => $s['probability'] * 100,
]);
if ($missingStageName === $s['id']) {
$missingStage = $stage;
}
$stages[] = $stage->id;
}
$businessProcess->stages()->sync($stages);
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
try {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
/** @var array<int, array<string, mixed>> */
return Cache::remember(
key: $this->team->getId() . $name . $count . $offset,
ttl: 300,
callback: function () use ($name, $offset, $count): array {
$data = [];
// Use the new V3 API to find contacts based on additional fields.
foreach (['companies', 'contacts'] as $objectType) {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
if ($crmAccountId === null) {
return $data;
}
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
$closedStages = $this->getClosedDealStages();
$payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(
$this->config,
$crmAccountId,
$closedStages,
);
$results = $this->client->getPaginatedData($payload, 'deals');
foreach ($results['results'] as $object) {
$properties = $object['properties'];
$amount = null;
if (empty($properties['amount']) === false) {
$currency = $properties['deal_currency_code'] ?? $this->config->default_currency;
// Values can contain commas and any junk so strip them.
$value = (float) preg_replace('/[^\d.]/', '', $properties['amount']);
$amount = formatCurrency($value, $currency);
}
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
if ($businessProcess === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
} else {
$stage = $businessProcess
->stages()
->where('crm_provider_id', $properties['dealstage'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages(null, $properties['dealstage']);
}
}
$recordType = null;
if ($businessProcess) {
$recordType = $businessProcess->recordTypes()->first();
}
$isWon = in_array($properties['dealstage'], $closedStages['won']);
$isLost = in_array($properties['dealstage'], $closedStages['lost']);
$record = [
'crmId' => $object['id'],
'name' => $properties['dealname'] ?? 'Unknown Deal',
'value' => $amount,
'won' => $isWon,
'closed' => $isWon || $isLost,
'stage' => [
'id' => $stage?->getUuid() ?? '',
'name' => $stage?->getName() ?? '',
],
];
if ($recordType) {
$record += [
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
}
if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
if (! empty($ownerData)) {
return $ownerData;
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(?string $objectType, string $objectId, ?string $opportunityId): array
{
$data = [];
switch ($objectType) {
case 'contact':
$hsObject = 'contact';
break;
case 'account':
$hsObject = 'company';
break;
default:
// This is a hack to prioritise and override a contact/company with a deal.
if ($opportunityId) {
$hsObject = 'deal';
$objectId = $opportunityId;
} else {
throw new InvalidArgumentException('Object type not supported.');
}
}
$engagementTypes = ['meetings', 'tasks'];
foreach ($engagementTypes as $engagementType) {
$payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);
$this->logger->info('[HubSpot] CRM Search requested', [
'request' => $payload,
]);
$engagements = $this->client->getPaginatedData($payload, $engagementType);
foreach ($engagements['results'] as $engagement) {
if ($engagementType == 'meetings') {
$title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';
} elseif ($engagementType == 'tasks') {
$title = $engagement['properties']['hs_task_subject'];
} else {
$title = 'Scheduled meeting';
}
$data[] = [
'crmId' => $engagement['id'],
'subject' => $title,
'due' => $engagement['properties']['hs_timestamp'],
'type' => $engagement['properties']['hs_activity_type'] ?? null,
];
}
}
usort($data, function ($item1, $item2) {
return $item2['due'] <=> $item1['due'];
});
return $data;
}
/**
* Try to find CRM Objects using email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$contactProperties = [
'email',
'firstname',
'lastname',
'country',
'phone',
'mobilephone',
'jobtitle',
'hubspot_owner_id',
'associatedcompanyid',
'photo',
];
$contact = null;
$account = null;
try {
$hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);
if ($hsContact) {
$contact = $this->importContact($hsContact);
$account = $contact->account;
}
$data = $this->convertCrmData($contact, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
} catch (BadRequest $e) {
$this->logger->warning('[HubSpot] Search failed', [
'team_id' => $this->team->getId(),
'search_identifier' => $email,
'reason' => $e->getMessage(),
]);
}
return null;
}
public function getDomain(string $email): ?string
{
return $this->getDomainFromEmail($email);
}
/**
* Try to find CRM objects using domain name of the email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByDomain(string $domain, ?int $userId = null): ?array
{
$companyName = $domain;
// Try to find a company matching their email domain.
$companyProperties = [
'country',
'phone',
'name',
'hs_avatar_filemanager_key',
'industry',
'hubspot_owner_id',
'domain',
];
try {
$hsAccounts = $this->client
->getInstance()
->companies()
->searchByDomain($companyName, $companyProperties);
} catch (Throwable $e) {
$this->logger->info('[HubSpot] Search failed', [
'error' => $e->getMessage(),
'domain' => $domain,
]);
return null;
}
$account = null;
// If there are multiple accounts, don't guess, we'll ask later.
if (\count($hsAccounts->data->results) === 1) {
// Persist this remote object.
$account = $this->syncAccount($hsAccounts->data->results[0]->companyId);
}
$data = $this->convertCrmData(null, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
}
/**
* @return array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array
{
$countryCode = null;
if ($contact && $contact->country_code) {
$countryCode = $contact->country_code;
} elseif ($account && $account->country_code) {
$countryCode = $account->country_code;
}
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
// If there are multiple opportunities, don't guess, we'll ask later.
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
protected function getCacheKey(string $object, ?int $userId = null): ?string
{
$key = $this->team->getId() . $object;
$keySuffix = $this->getOwnerKeySuffix($userId);
return $key . $keySuffix;
}
private function getOwnerKeySuffix(?int $userId = null): string
{
return $userId === null ? '' : (string) $userId;
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array
{
if (str_contains($phone, '**')) {
return null;
}
// trim all whitespaces if present so the lookup doesn't fail
$phone = str_replace(' ', '', $phone);
// Check if the user is internal.
if ($this->isPhoneNumberOfTeamMember($phone)) {
return null;
}
$response = $this->searchForPhoneNumber($phone);
if (empty($response)) {
return null;
}
// This would ideally importContact instead but the response type differs.
$contact = $this->findAndSyncContact($response['results'][0]['id']);
if (! $contact instanceof Contact) {
return null;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account?->crm_provider_id,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
try {
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
} catch (Exception $e) {
$this->logger->debug('[HubSpot] Opportunity failed to sync.', [
'reason' => $e->getMessage(),
]);
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
private function isPhoneNumberOfTeamMember(string $phone): bool
{
$teamRepository = app(TeamRepository::class);
$user = $teamRepository->findTeamMemberByPhone($this->team, $phone);
if ($user instanceof User) {
return true;
}
return false;
}
private function findAndSyncContact(string $crmId): ?Contact
{
try {
return $this->syncContact($crmId);
} catch (Exception $exception) {
$this->logger->info('[HubSpot] Phone match failed', [
'reason' => $exception->getMessage(),
]);
return null;
}
}
private function hasResults(array $response): bool
{
return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;
}
private function searchForPhoneNumber(string $phone): array
{
// Normalizes the provided phone number for the API search.
$normalizedPhone = $this->normalizePhoneNumber($phone);
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);
$this->logger->info('[HubSpot] Phone match search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);
if (! $this->hasResults($response)) {
$nationalPhone = preg_replace('/\D/', '', phone_national(null, $phone));
$payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);
$this->logger->info('[HubSpot] Phone match national number search triggered', [
'phone' => $phone,
'nationalPhone' => $nationalPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
if (! $this->hasResults($response)) {
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);
$this->logger->info('[HubSpot] Phone match alternative search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
return $this->hasResults($response) ? $response : [];
}
private function handlePhoneSearchRequest(string $phone, array $payload): array
{
$endpoint = '[URL_WITH_CREDENTIALS] null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByName(string $name, ?int $userId = null): ?array
{
// Don't waste time searching for single character strings.
if (\strlen($name) <= 1) {
return null;
}
$cacheKey = $this->getCacheKey($name, $userId);
$result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {
$payload = $this->payloadBuilder->generateSearchContactsByNamePayload(
$name,
$this->getContactFields()
);
$hsContacts = $this->client->getPaginatedData($payload, 'contact');
if (empty($hsContacts['results'])) {
return false;
}
$contact = $this->importContact($hsContacts['results'][0]);
if ($contact === null) {
return false;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
});
return is_array($result) ? $result : null;
}
private function convertActivityAssociations(Activity $activity): array
{
return [
'contactIds' => $this->getParticipantsIds($activity),
'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],
'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],
'ownerIds' => [],
];
}
private function getParticipantsIds(Activity $activity): array
{
$attendees = [];
$participantRepository = app(ParticipantRepository::class);
$participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);
foreach ($participants as $participant) {
if ($participant->user_id || $participant->isCoach()) {
continue;
}
$contact = $participant->contact()->first();
if ($contact && $contact->crm_provider_id) {
$attendees[] = $contact->crm_provider_id;
} else {
if (! empty($participant->name)) {
$attendeeData = $this->fetchMissingAttendeeInfo($participant);
}
if (! empty($attendeeData['id'])) {
$attendees[] = $attendeeData['id'];
}
}
}
if ($activity->hasContact()) {
$attendees[] = $activity->contact->crm_provider_id;
}
return array_unique($attendees);
}
private function fetchMissingAttendeeInfo(Participant $participant): array
{
// Check if we need to look inside an account context.
$activity = $participant->getActivity();
$companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;
// First check the local data.
/** @var Contact[] $contacts */
$contacts = $this->team->contacts()
->with('account')
->where('name', $participant->name)
->whereNotNull('email')
->get();
foreach ($contacts as $contact) {
// If we have a company in scope, check the contact is associated to it.
if (
$companyId !== null
&& ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)
) {
continue;
}
return [
'id' => $contact->crm_provider_id,
'email' => $contact->email,
];
}
$payload = $this->generateNameSearchPayload($participant->name, 0, 20);
try {
$response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);
// TODO add some logic to choose the most suitable contact if multiple
foreach ($response['results'] as $object) {
$properties = $object['properties'];
if (empty($object['properties']) === false) {
// Check the company matches the contact.
// Todo: Move this check inside the API search.
if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {
continue;
}
return [
'id' => $object['id'],
'email' => $properties['email'],
];
}
}
} catch (Exception $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [
'teamId' => $this->team->id_string,
'request' => $payload,
'reason' => $e->getMessage(),
]);
}
return [];
}
/**
* Store transcripts as note engagement.
*
* @throws Exception
*/
public function createTranscriptNotes(Activity $activity): void
{
// For HS no need to check if Crm profile - Log Notes field is enabled
// We only check if store_transcript toggle is enabled on crm profile.
$engagement = [
'active' => true,
'ownerId' => $this->profile->crm_provider_i...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"1 file committed","depth":2,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20903 revert changes in command","depth":3,"on_screen":true,"value":"JY-20903 revert changes in command","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"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":"#12077 on JY-20903-update_activity-stage-on…hange, menu","depth":5,"on_screen":true,"help_text":"Pull request #12077 exists for current branch JY-20903-update__activity-stage-on…hange","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":"7","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"51","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"33","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\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse Generator;\nuse GuzzleHttp\\Exception\\RequestException;\nuse HubSpot\\Client\\Crm\\Owners\\Model\\PublicOwner;\nuse Illuminate\\Support\\Facades\\Cache;\nuse InvalidArgumentException;\nuse Jiminny\\Contracts\\Repositories\\TeamRepository;\nuse Jiminny\\Contracts\\Services\\Crm\\ClientInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\FetchRelatedActivityInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\HubspotInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SavePlaybackLinkToCrmInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SendSummaryToCrmInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Contracts\\ActivityContract;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\Layout;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Participant;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Repositories\\ParticipantRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Hubspot\\Actions\\SyncArchivedProfilesAction;\nuse Jiminny\\Services\\Crm\\Hubspot\\Fields\\ValueNormalizer;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\OpportunitySyncTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\SyncCrmEntitiesTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\SyncFieldsTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\WriteCrmTrait;\nuse Jiminny\\Services\\Crm\\MatchDomainByEmailInterface;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Services\\Crm\\ResolveCompanyNameByEmailTrait;\nuse Jiminny\\Utils\\PlaybackUrlBuilder;\nuse Sentry;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse Throwable;\nuse UnexpectedValueException;\n\n/**\n * @phpstan-type CrmFieldDefinition array{\n * name: string,\n * label: string,\n * description: string,\n * type: string,\n * fieldType: string,\n * hidden: bool,\n * showCurrencySymbol: bool,\n * options: array<array{\n * id: string,\n * label: string,\n * value?: string,\n * }\n */\nclass Service extends BaseService implements\n HubspotInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n SendSummaryToCrmInterface,\n MatchDomainByEmailInterface,\n SavePlaybackLinkToCrmInterface,\n RemoteEntityManipulationInterface,\n FetchRelatedActivityInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n VerifyTaskExistsInterface\n{\n use ResolveCompanyNameByEmailTrait;\n use SyncCrmEntitiesTrait;\n use WriteCrmTrait;\n use SyncFieldsTrait;\n use OpportunitySyncTrait;\n\n private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;\n\n private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';\n private const int BATCH_UPDATE_LIMIT = 100;\n private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';\n private const int TEN_SECONDLY_ROLLING_LIMIT = 10;\n private const string CALLS_SEARCH_ENDPOINT = 'https://api.hubapi.com/crm/v3/objects/calls/search';\n\n private const string TYPE_NOTE = 'NOTE';\n\n private const string TYPE_MEETING = 'MEETING';\n\n private const string TYPE_CALL = 'CALL';\n\n private const string API_URL = 'https://api.hubapi.com';\n\n // NB: v1 is legacy - v3 is the newest\n private const string ENDPOINT_PIPELINES = '/crm-pipelines/v1/pipelines/';\n private const string PIPELINE_OBJECT_TYPE_DEALS = 'deals';\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n /**\n * @var ClientInterface|Client\n */\n protected $client;\n protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;\n protected CrmEntityRepository $crmEntityRepository;\n protected ProspectPhotoPathService $prospectPhotoPathService;\n\n private SyncFieldAction $syncFieldAction;\n private PayloadBuilder $payloadBuilder;\n private SyncRelatedActivityManager $syncRelatedActivityManager;\n private SyncArchivedProfilesAction $syncArchivedProfilesAction;\n private WebhookSyncBatchProcessor $batchProcessor;\n\n public function __construct(\n Client $client,\n SyncFieldAction $syncFieldAction,\n PayloadBuilder $payloadBuilder,\n ProspectPhotoPathService $prospectPhotoPathService,\n SyncArchivedProfilesAction $syncArchivedProfilesAction,\n WebhookSyncBatchProcessor $batchProcessor,\n ) {\n parent::__construct();\n\n $this->client = $client;\n $this->syncFieldAction = $syncFieldAction;\n $this->prospectPhotoPathService = $prospectPhotoPathService;\n $this->payloadBuilder = $payloadBuilder;\n $this->syncArchivedProfilesAction = $syncArchivedProfilesAction;\n $this->batchProcessor = $batchProcessor;\n $this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->client,\n ]);\n $this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [\n 'client' => $this->client,\n 'payloadBuilder' => $this->payloadBuilder,\n 'logger' => $this->logger,\n ]);\n $this->crmEntityRepository = app(CrmEntityRepository::class);\n $this->dealFieldsService = app(DealFieldsService::class);\n }\n\n public function getDisplayName(): string\n {\n return 'HubSpot';\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n $owner = $user->team->owner;\n\n return $owner->getSocialAccount(SocialAccount::PROVIDER_HUBSPOT);\n }\n\n public function getClient(): Client\n {\n /** @var Client */\n return $this->client;\n }\n\n /**\n * Convert raw field data into a format compatible with CRM APIs.\n *\n * @param bool $internal Direction of the conversion.\n * True is pulling from CRM, false normalize before sending to CRM.\n */\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return ValueNormalizer::normalize(\n fieldType: $fieldType,\n fieldValue: $fieldValue,\n isInbound: $internal,\n );\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n /** @var Field $activityField */\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'activityType',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n // Outcome should always be provided calls/meetings.\n $fieldData = [\n [\n 'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',\n 'object_type' => Field::OBJECT_TASK,\n ],\n ];\n\n foreach ($fieldData as $data) {\n $field = $this->config->fields()->where($data)->first();\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n }\n\n return $fields;\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n $fieldData = FieldDefinitions::followupFieldsFilter();\n\n foreach ($fieldData as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function syncField(Field $field): void\n {\n switch ($field->object_type) {\n case Field::OBJECT_ACCOUNT:\n $crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_CONTACT:\n $crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_OPPORTUNITY:\n $crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_TASK:\n $this->syncSingleTaskField($field);\n\n return;\n default:\n return;\n }\n\n $this->syncFieldAction->execute($field, $crmField->toArray());\n }\n\n /**\n * @param array<array{\n * id:string,\n * label:string,\n * value?:string\n * }> $options\n *\n * @throws CrmException\n *\n * @return FieldData[]\n *\n */\n public function importPicklistValues(\n Field $field,\n array $options = [['id' => '', 'label' => '', 'value' => '']],\n ): array {\n if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {\n // We already have the options, no need to fetch them again\n return $this->importOptions($field, $options);\n }\n\n $options = [];\n\n switch ($field->getObjectType()) {\n case Field::OBJECT_ACCOUNT:\n $options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());\n\n break;\n\n case Field::OBJECT_CONTACT:\n $options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());\n\n break;\n\n case Field::OBJECT_OPPORTUNITY:\n // Hubspot has different endpoint for stages\n $options = $this->getClient()->fetchOpportunityFieldOptions($field);\n\n break;\n\n case Field::OBJECT_TASK:\n if ($field->getCrmProviderId() === 'disposition') {\n $options = $this->getClient()->fetchDispositionFieldOptions();\n } elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {\n $options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);\n }\n\n break;\n\n default:\n $this->logger->warning('Invalid object type', [\n 'object_type' => $field->getObjectType(),\n 'field_id' => $field->getId(),\n ]);\n\n throw new CrmException('Invalid object type');\n }\n\n return $this->importOptions($field, $options);\n }\n\n /**\n * @inheritdoc\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n $missingStage = null;\n\n try {\n // Use the HubSpot API client instead of the SDK crmPipelines() method\n $endpoint = self::getDealsPipelinesEndpoint();\n $pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);\n $pipelines = $pipelinesResponse->data->results;\n } catch (RequestException|BadRequest $exception) {\n throw $exception;\n }\n\n foreach ($pipelines as $pipeline) {\n $stages = [];\n\n // We create a business process to contain the pipeline, and store all stages against it.\n $p = ResponseNormalize::normalizePipeline($pipeline);\n\n // Create/update business process for this pipeline\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => $p['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($p['label'], 0, 150),\n 'type' => BusinessProcess::TYPE_OPPORTUNITY,\n 'is_selectable' => $p['active'],\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n // Create/update record type clone\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => $p['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($p['label'], 0, 150),\n 'is_selectable' => $p['active'],\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n // Stages - fetch all existing stages upfront to avoid N+1 queries\n $existingStages = $this->config->stages()\n ->withTrashed()\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->get()\n ->keyBy('crm_provider_id');\n\n foreach ($p['stages'] as $dealStage) {\n $s = ResponseNormalize::normalizeDealStage($dealStage);\n\n /** @var ?Stage $existingStage */\n $existingStage = $existingStages->get($s['id']);\n\n // Restore soft-deleted stages that are now active in HubSpot\n if ($existingStage?->trashed() && $s['active']) {\n $existingStage->restore();\n }\n\n // Upsert stage (updates soft-deleted records without restoring them)\n $stage = $this->config->stages()->withTrashed()->updateOrCreate([\n 'crm_provider_id' => $s['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($s['label'], 0, 50),\n 'label' => mb_strimwidth($s['label'], 0, 191),\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'sequence' => $s['displayOrder'],\n 'is_selectable' => $s['active'],\n 'probability' => $s['probability'] * 100,\n ]);\n\n if ($missingStageName === $s['id']) {\n $missingStage = $stage;\n }\n\n $stages[] = $stage->id;\n }\n\n $businessProcess->stages()->sync($stages);\n }\n\n return $missingStage;\n }\n\n /**\n * @inheritdoc\n */\n public function syncOrganization(): void\n {\n try {\n $endpoint = 'https://api.hubapi.com/integrations/v1/me';\n $response = $this->client->getInstance()->getClient()->request('get', $endpoint);\n\n $accountData = $response->data;\n $this->config->update(['default_currency' => $accountData->currency]);\n } catch (BadRequest $e) {\n throw new CrmException('Could not sync the organization.', $e->getCode(), $e);\n }\n }\n\n /**\n * @inheritdoc\n *\n * @throws CrmException\n */\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n $this->syncArchivedProfilesAction->execute($this->team, $this->client, $this->config);\n\n try {\n $owners = $this->client->getOwners();\n } catch (\\HubSpot\\Client\\Crm\\Owners\\ApiException $e) {\n $this->handleOwnersApiException($e);\n }\n\n $profileRepository = app(ProfileRepository::class);\n $teamRepository = app(TeamRepository::class);\n\n foreach ($owners as $owner) {\n $profile = $this->processOwner($owner, $teamRepository, $profileRepository);\n\n if ($profile && $userToSearch && $userToSearch->getId() === $profile->getUserId()) {\n return $profile;\n }\n }\n\n return null;\n }\n\n private function handleOwnersApiException(\\HubSpot\\Client\\Crm\\Owners\\ApiException $e): never\n {\n $statusCode = $e->getCode();\n $errorMessage = $e->getMessage();\n $responseBody = $this->parseResponseBody($e->getResponseBody());\n\n $isPermissionError = $this->isPermissionError($statusCode, $errorMessage, $responseBody);\n\n $logContext = [\n 'team_id' => $this->team->getId(),\n 'team_uuid' => $this->team->getUuid(),\n 'config_id' => $this->config->getId(),\n 'status_code' => $statusCode,\n 'error_message' => $errorMessage,\n 'response_body' => $responseBody,\n ];\n\n if ($isPermissionError) {\n $this->logPermissionError($logContext);\n } else {\n $this->logger->error('[HubSpot] Could not sync the profiles.', $logContext);\n }\n\n throw new CrmException('Could not sync the profiles.', $e->getCode(), $e);\n }\n\n private function parseResponseBody(?string $rawBody): ?array\n {\n if ($rawBody === null || $rawBody === '') {\n return null;\n }\n\n try {\n return json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR);\n } catch (\\JsonException) {\n return null;\n }\n }\n\n private function logPermissionError(array $logContext): void\n {\n $this->logger->critical(\n '[HubSpot] ⚠️ PERMISSION ERROR: Cannot sync profiles - Missing OAuth scopes',\n array_merge($logContext, [\n 'action_required' => 'Request additional HubSpot OAuth scopes',\n 'required_scope' => 'crm.objects.owners.read',\n 'impact' => 'Opportunities will have owner_id but NO user_id - AI automation and reporting will fail',\n 'resolution' => 'Manually request scope from HubSpot account admin or re-authenticate',\n ])\n );\n }\n\n private function processOwner(\n PublicOwner $owner,\n TeamRepository $teamRepository,\n ProfileRepository $profileRepository\n ): ?Profile {\n if ($owner->getArchived()) {\n $this->logger->warning('[HubSpot] Found archived owner', [\n 'crm_provider_id' => $owner->getId(),\n 'email' => $owner->getEmail(),\n ]);\n\n return null;\n }\n\n $email = $owner->getEmail();\n if ($email === null) {\n return null;\n }\n\n $user = $teamRepository->findActiveTeamMemberByEmail($this->team, $email);\n if (! $user instanceof User) {\n return null;\n }\n\n return $profileRepository->updateOrCreateProfile($user, [\n 'crm_configuration_id' => $this->config->getId(),\n 'crm_provider_id' => $owner->getId(),\n ]);\n }\n\n private function isPermissionError(int $statusCode, string $errorMessage, ?array $responseBody): bool\n {\n // Check HTTP 403 Forbidden\n if ($statusCode === 403) {\n return true;\n }\n\n // Check for scope-related keywords in error message\n $scopeKeywords = ['scope', 'permission', 'forbidden', 'unauthorized', 'access denied', 'oauth'];\n $lowerErrorMessage = strtolower($errorMessage);\n\n foreach ($scopeKeywords as $keyword) {\n if (str_contains($lowerErrorMessage, $keyword)) {\n return true;\n }\n }\n\n // Check response body for scope errors\n if ($responseBody !== null) {\n return $this->arrayContainsKeyword($responseBody, $scopeKeywords);\n }\n\n return false;\n }\n\n /**\n * Recursively search array for keywords in values\n */\n private function arrayContainsKeyword(array $data, array $keywords): bool\n {\n foreach ($data as $value) {\n if (is_array($value)) {\n if ($this->arrayContainsKeyword($value, $keywords)) {\n return true;\n }\n } elseif (is_string($value)) {\n $lowerValue = strtolower($value);\n foreach ($keywords as $keyword) {\n if (str_contains($lowerValue, $keyword)) {\n return true;\n }\n }\n }\n }\n\n return false;\n }\n\n private function generateNameSearchPayload(string $name, int $offset, int $limit): array\n {\n $payload = [\n 'query' => $name,\n 'sorts' => [\n [\n 'propertyName' => 'modifieddate',\n 'direction' => 'DESCENDING',\n ],\n ],\n 'properties' => [\n 'email',\n 'firstname',\n 'lastname',\n 'country',\n 'phone',\n 'mobilephone',\n 'jobtitle',\n 'hubspot_owner_id',\n 'associatedcompanyid',\n 'photo',\n 'industry',\n 'name',\n 'company',\n ],\n 'limit' => $limit,\n 'after' => $offset,\n ];\n\n $this->logger->debug('[HubSpot] CRM Search requested', [\n 'request' => $payload,\n ]);\n\n return $payload;\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n /** @var array<int, array<string, mixed>> */\n return Cache::remember(\n key: $this->team->getId() . $name . $count . $offset,\n ttl: 300,\n callback: function () use ($name, $offset, $count): array {\n $data = [];\n\n // Use the new V3 API to find contacts based on additional fields.\n foreach (['companies', 'contacts'] as $objectType) {\n $endpoint = 'https://api.hubapi.com/crm/v3/objects/' . $objectType . '/search';\n $payload = $this->generateNameSearchPayload($name, $offset, $count);\n $type = $objectType === 'companies' ? 'account' : 'contact';\n\n try {\n $response = $this->client->getInstance()->getClient()->request('POST', $endpoint, [\n 'json' => $payload,\n ]);\n\n // Build mapped list.\n foreach ($response['results'] as $object) {\n $properties = $object['properties'];\n\n $objectName = $this->buildContactName($properties);\n\n $record = [\n 'crmId' => $object['id'],\n // Pass crmUrl to the FE, needed for success message in the extension when you log activity.\n 'crmUrl' => $this->generateProviderUrl($object['id'], $type),\n 'name' => $objectName,\n 'prospectType' => $type,\n 'phoneNumbers' => [],\n ];\n\n if ($type === 'account') {\n $record['industry'] = $properties['industry'] ?? null;\n } else {\n $record['title'] = $properties['jobtitle'] ?? null;\n $record['organization'] = $properties['company'] ?? null;\n }\n\n $countryCode = $this->buildContactCountry($properties);\n $parsedNumber = $this->buildContactPhone($countryCode, $properties);\n\n // Add phone number to record.\n if (! empty($parsedNumber['phone'])) {\n $record['phoneNumbers'][] = [\n 'number' => $parsedNumber['phone'],\n 'nationalFormat' => phone_national($countryCode, $parsedNumber['phone']),\n 'type' => 'phone',\n ];\n }\n\n // Add mobile phone number to record.\n if (! empty($properties['mobilephone'])) {\n $mobileNumber = phone_e164($countryCode, $properties['mobilephone']);\n if ($mobileNumber !== null) {\n $record['phoneNumbers'][] = [\n 'number' => $mobileNumber,\n 'nationalFormat' => phone_national($countryCode, $mobileNumber),\n 'type' => 'mobile',\n ];\n }\n }\n\n $data[] = $record;\n }\n } catch (BadRequest $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [\n 'teamId' => $this->team->getUuid(),\n 'request' => $payload,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n }\n\n return $data;\n },\n );\n }\n\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n\n if ($crmAccountId === null) {\n return $data;\n }\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n $closedStages = $this->getClosedDealStages();\n $payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(\n $this->config,\n $crmAccountId,\n $closedStages,\n );\n\n $results = $this->client->getPaginatedData($payload, 'deals');\n\n foreach ($results['results'] as $object) {\n $properties = $object['properties'];\n\n $amount = null;\n if (empty($properties['amount']) === false) {\n $currency = $properties['deal_currency_code'] ?? $this->config->default_currency;\n\n // Values can contain commas and any junk so strip them.\n $value = (float) preg_replace('/[^\\d.]/', '', $properties['amount']);\n $amount = formatCurrency($value, $currency);\n }\n\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', $properties['pipeline'])\n ->first();\n\n if ($businessProcess === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', $properties['pipeline'])\n ->first();\n } else {\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', $properties['dealstage'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages(null, $properties['dealstage']);\n }\n }\n\n $recordType = null;\n if ($businessProcess) {\n $recordType = $businessProcess->recordTypes()->first();\n }\n\n $isWon = in_array($properties['dealstage'], $closedStages['won']);\n $isLost = in_array($properties['dealstage'], $closedStages['lost']);\n\n $record = [\n 'crmId' => $object['id'],\n 'name' => $properties['dealname'] ?? 'Unknown Deal',\n 'value' => $amount,\n 'won' => $isWon,\n 'closed' => $isWon || $isLost,\n 'stage' => [\n 'id' => $stage?->getUuid() ?? '',\n 'name' => $stage?->getName() ?? '',\n ],\n ];\n\n if ($recordType) {\n $record += [\n 'recordType' => [\n 'id' => $recordType->id_string,\n 'name' => $recordType->name,\n ],\n ];\n }\n\n if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(?string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = [];\n switch ($objectType) {\n case 'contact':\n $hsObject = 'contact';\n\n break;\n case 'account':\n $hsObject = 'company';\n\n break;\n default:\n // This is a hack to prioritise and override a contact/company with a deal.\n if ($opportunityId) {\n $hsObject = 'deal';\n $objectId = $opportunityId;\n } else {\n throw new InvalidArgumentException('Object type not supported.');\n }\n }\n\n $engagementTypes = ['meetings', 'tasks'];\n\n foreach ($engagementTypes as $engagementType) {\n $payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);\n\n $this->logger->info('[HubSpot] CRM Search requested', [\n 'request' => $payload,\n ]);\n\n $engagements = $this->client->getPaginatedData($payload, $engagementType);\n\n foreach ($engagements['results'] as $engagement) {\n if ($engagementType == 'meetings') {\n $title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';\n } elseif ($engagementType == 'tasks') {\n $title = $engagement['properties']['hs_task_subject'];\n } else {\n $title = 'Scheduled meeting';\n }\n\n $data[] = [\n 'crmId' => $engagement['id'],\n 'subject' => $title,\n 'due' => $engagement['properties']['hs_timestamp'],\n 'type' => $engagement['properties']['hs_activity_type'] ?? null,\n ];\n }\n }\n\n usort($data, function ($item1, $item2) {\n return $item2['due'] <=> $item1['due'];\n });\n\n return $data;\n }\n\n /**\n * Try to find CRM Objects using email address\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $contactProperties = [\n 'email',\n 'firstname',\n 'lastname',\n 'country',\n 'phone',\n 'mobilephone',\n 'jobtitle',\n 'hubspot_owner_id',\n 'associatedcompanyid',\n 'photo',\n ];\n $contact = null;\n $account = null;\n\n try {\n $hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);\n\n if ($hsContact) {\n $contact = $this->importContact($hsContact);\n $account = $contact->account;\n }\n\n $data = $this->convertCrmData($contact, $account, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n } catch (BadRequest $e) {\n $this->logger->warning('[HubSpot] Search failed', [\n 'team_id' => $this->team->getId(),\n 'search_identifier' => $email,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return null;\n }\n\n public function getDomain(string $email): ?string\n {\n return $this->getDomainFromEmail($email);\n }\n\n /**\n * Try to find CRM objects using domain name of the email address\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByDomain(string $domain, ?int $userId = null): ?array\n {\n $companyName = $domain;\n\n // Try to find a company matching their email domain.\n $companyProperties = [\n 'country',\n 'phone',\n 'name',\n 'hs_avatar_filemanager_key',\n 'industry',\n 'hubspot_owner_id',\n 'domain',\n ];\n\n try {\n $hsAccounts = $this->client\n ->getInstance()\n ->companies()\n ->searchByDomain($companyName, $companyProperties);\n } catch (Throwable $e) {\n $this->logger->info('[HubSpot] Search failed', [\n 'error' => $e->getMessage(),\n 'domain' => $domain,\n ]);\n\n return null;\n }\n\n $account = null;\n // If there are multiple accounts, don't guess, we'll ask later.\n if (\\count($hsAccounts->data->results) === 1) {\n // Persist this remote object.\n $account = $this->syncAccount($hsAccounts->data->results[0]->companyId);\n }\n\n $data = $this->convertCrmData(null, $account, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n /**\n * @return array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array\n {\n $countryCode = null;\n if ($contact && $contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account && $account->country_code) {\n $countryCode = $account->country_code;\n }\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n // If there are multiple opportunities, don't guess, we'll ask later.\n $opportunity = null;\n $stage = null;\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n protected function getCacheKey(string $object, ?int $userId = null): ?string\n {\n $key = $this->team->getId() . $object;\n $keySuffix = $this->getOwnerKeySuffix($userId);\n\n return $key . $keySuffix;\n }\n\n private function getOwnerKeySuffix(?int $userId = null): string\n {\n return $userId === null ? '' : (string) $userId;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n if (str_contains($phone, '**')) {\n return null;\n }\n\n // trim all whitespaces if present so the lookup doesn't fail\n $phone = str_replace(' ', '', $phone);\n\n // Check if the user is internal.\n if ($this->isPhoneNumberOfTeamMember($phone)) {\n return null;\n }\n\n $response = $this->searchForPhoneNumber($phone);\n if (empty($response)) {\n return null;\n }\n\n // This would ideally importContact instead but the response type differs.\n $contact = $this->findAndSyncContact($response['results'][0]['id']);\n if (! $contact instanceof Contact) {\n return null;\n }\n\n $account = $contact->account;\n $countryCode = $contact->country_code ?? $account->country_code ?? null;\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n $opportunity = null;\n $stage = null;\n\n try {\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (Exception $e) {\n $this->logger->debug('[HubSpot] Opportunity failed to sync.', [\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n private function isPhoneNumberOfTeamMember(string $phone): bool\n {\n $teamRepository = app(TeamRepository::class);\n $user = $teamRepository->findTeamMemberByPhone($this->team, $phone);\n\n if ($user instanceof User) {\n return true;\n }\n\n return false;\n }\n\n private function findAndSyncContact(string $crmId): ?Contact\n {\n try {\n return $this->syncContact($crmId);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Phone match failed', [\n 'reason' => $exception->getMessage(),\n ]);\n\n return null;\n }\n }\n\n private function hasResults(array $response): bool\n {\n return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;\n }\n\n private function searchForPhoneNumber(string $phone): array\n {\n // Normalizes the provided phone number for the API search.\n $normalizedPhone = $this->normalizePhoneNumber($phone);\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);\n\n $this->logger->info('[HubSpot] Phone match search triggered', [\n 'phone' => $phone,\n 'normalizedPhone' => $normalizedPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);\n\n if (! $this->hasResults($response)) {\n $nationalPhone = preg_replace('/\\D/', '', phone_national(null, $phone));\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);\n\n $this->logger->info('[HubSpot] Phone match national number search triggered', [\n 'phone' => $phone,\n 'nationalPhone' => $nationalPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($phone, $payload);\n }\n\n if (! $this->hasResults($response)) {\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);\n\n $this->logger->info('[HubSpot] Phone match alternative search triggered', [\n 'phone' => $phone,\n 'normalizedPhone' => $normalizedPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($phone, $payload);\n }\n\n return $this->hasResults($response) ? $response : [];\n }\n\n private function handlePhoneSearchRequest(string $phone, array $payload): array\n {\n $endpoint = 'https://api.hubapi.com/crm/v3/objects/contacts/search';\n\n try {\n $response = $this->client->getInstance()->getClient()->request(\n 'POST',\n $endpoint,\n ['json' => ($payload)],\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Phone match failed', [\n 'phone' => $phone,\n 'reason' => $exception->getMessage(),\n ]);\n\n return [];\n }\n\n $this->logger->info('[HubSpot] Phone match completed', [\n 'phone' => $phone,\n 'response' => $response,\n ]);\n\n return $response->toArray();\n }\n\n private function normalizePhoneNumber(string $phone): string\n {\n return ltrim(phone_e164(null, $phone), '+0');\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $cacheKey = $this->getCacheKey($name, $userId);\n\n $result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {\n $payload = $this->payloadBuilder->generateSearchContactsByNamePayload(\n $name,\n $this->getContactFields()\n );\n\n $hsContacts = $this->client->getPaginatedData($payload, 'contact');\n if (empty($hsContacts['results'])) {\n return false;\n }\n\n $contact = $this->importContact($hsContacts['results'][0]);\n if ($contact === null) {\n return false;\n }\n\n $account = $contact->account;\n $countryCode = $contact->country_code ?? $account->country_code ?? null;\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact->crm_provider_id,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n $opportunity = null;\n $stage = null;\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n });\n\n return is_array($result) ? $result : null;\n }\n\n\n private function convertActivityAssociations(Activity $activity): array\n {\n return [\n 'contactIds' => $this->getParticipantsIds($activity),\n 'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],\n 'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],\n 'ownerIds' => [],\n ];\n }\n\n private function getParticipantsIds(Activity $activity): array\n {\n $attendees = [];\n\n $participantRepository = app(ParticipantRepository::class);\n $participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);\n foreach ($participants as $participant) {\n if ($participant->user_id || $participant->isCoach()) {\n continue;\n }\n\n $contact = $participant->contact()->first();\n if ($contact && $contact->crm_provider_id) {\n $attendees[] = $contact->crm_provider_id;\n } else {\n if (! empty($participant->name)) {\n $attendeeData = $this->fetchMissingAttendeeInfo($participant);\n }\n if (! empty($attendeeData['id'])) {\n $attendees[] = $attendeeData['id'];\n }\n }\n }\n\n if ($activity->hasContact()) {\n $attendees[] = $activity->contact->crm_provider_id;\n }\n\n return array_unique($attendees);\n }\n\n private function fetchMissingAttendeeInfo(Participant $participant): array\n {\n // Check if we need to look inside an account context.\n $activity = $participant->getActivity();\n $companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;\n\n // First check the local data.\n /** @var Contact[] $contacts */\n $contacts = $this->team->contacts()\n ->with('account')\n ->where('name', $participant->name)\n ->whereNotNull('email')\n ->get();\n\n foreach ($contacts as $contact) {\n // If we have a company in scope, check the contact is associated to it.\n if (\n $companyId !== null\n && ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)\n ) {\n continue;\n }\n\n return [\n 'id' => $contact->crm_provider_id,\n 'email' => $contact->email,\n ];\n }\n\n $payload = $this->generateNameSearchPayload($participant->name, 0, 20);\n\n try {\n $response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);\n\n // TODO add some logic to choose the most suitable contact if multiple\n foreach ($response['results'] as $object) {\n $properties = $object['properties'];\n if (empty($object['properties']) === false) {\n // Check the company matches the contact.\n // Todo: Move this check inside the API search.\n if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {\n continue;\n }\n\n return [\n 'id' => $object['id'],\n 'email' => $properties['email'],\n ];\n }\n }\n } catch (Exception $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [\n 'teamId' => $this->team->id_string,\n 'request' => $payload,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return [];\n }\n\n /**\n * Store transcripts as note engagement.\n *\n * @throws Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n // For HS no need to check if Crm profile - Log Notes field is enabled\n // We only check if store_transcript toggle is enabled on crm profile.\n $engagement = [\n 'active' => true,\n 'ownerId' => $this->profile->crm_provider_id,\n 'timestamp' => $activity->created_at->tz($activity->user->timezone)->getTimestamp() * 1000,\n 'type' => 'NOTE',\n ];\n\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, static::ENGAGEMENT_BODY_MAX_LENGTH);\n\n $metadata = [\n 'body' => $transcripts,\n ];\n\n $associations = $this->convertActivityAssociations($activity);\n\n try {\n $hsEngagement = $this->client\n ->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n\n $this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);\n\n $noteId = $hsEngagement->data->engagement->id;\n\n // Store crm logged id in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $noteId;\n $transcription->save();\n } catch (Exception $e) {\n Sentry::captureException($e);\n }\n }\n\n /*\n * @inheritdoc\n */\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $payload = [\n 'properties' => $data,\n ];\n\n try {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n $this->client->getNewInstance()->crm()->deals()->basicApi()->update($objectId, $payload);\n\n break;\n case FieldData::OBJECT_CONTACT:\n $this->client->getNewInstance()->crm()->contacts()->basicApi()->update($objectId, $payload);\n\n break;\n\n case FieldData::OBJECT_ACCOUNT:\n $this->client->getNewInstance()->crm()->companies()->basicApi()->update($objectId, $payload);\n\n break;\n\n case FieldData::OBJECT_TASK:\n // Endpoint for Engagements not ready\n $engagements = [\n 'type' => 'TASK',\n ];\n $metadata = $data;\n $this->client->getInstance()->engagements()->update($objectId, $engagements, $metadata);\n\n $this->logCrmEngagementManipulation(\n self::ACTION_UPDATE,\n ['crmId' => $objectId],\n $metadata,\n );\n\n break;\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n } catch (\\HubSpot\\Client\\Crm\\Deals\\ApiException $apiException) {\n $errorMessage = $apiException->getMessage();\n if ($apiException->getResponseBody()) {\n $responseBody = json_decode($apiException->getResponseBody(), true, 512, JSON_THROW_ON_ERROR);\n $errorMessage = $responseBody['message'] ?? $apiException->getMessage();\n }\n\n $this->logger->error(\n '[HubSpot] Update record failed',\n [\n 'objectType' => $objectType,\n 'objectId' => $objectId,\n 'payload' => $payload,\n 'reason' => $errorMessage,\n 'team' => $this->team->getUuid(),\n ]\n );\n\n throw new CrmException($errorMessage);\n }\n }\n\n /*\n * @inheritdoc\n */\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n return $this->client->getInstance()->deals()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_CONTACT:\n return $this->client->getInstance()->contacts()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_ACCOUNT:\n return $this->client->getInstance()->companies()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_TASK:\n return $this->client->getInstance()->engagements()->get($objectId)->toArray();\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n }\n\n /**\n * @throws BadRequest\n * @throws CrmException\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n $payload = [\n 'properties' => [\n [\n 'name' => 'dealstage',\n 'value' => $stage->crm_provider_id,\n ],\n ],\n ];\n\n try {\n $this->client->getInstance()->deals()->update($crmObject->crm_provider_id, $payload);\n } catch (BadRequest $badRequest) {\n if ($badRequest->getCode() === 403) {\n throw new CrmException(\n \"Sorry, you don't have permission to update this stage.\",\n $badRequest->getCode(),\n $badRequest,\n );\n }\n\n $this->logger->warning('[HubSpot] Stage update failed', [\n 'dealId' => $crmObject->crm_provider_id,\n 'payload' => $payload,\n 'message' => $badRequest->getMessage(),\n ]);\n\n throw $badRequest;\n }\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $url = null;\n $baseUrl = 'https://app.hubspot.com/contacts/' . $this->config->crm_provider_id . '/';\n\n switch ($objectType) {\n case 'account':\n $url = $baseUrl . 'company/' . $providerId;\n\n break;\n\n case 'contact':\n $url = $baseUrl . 'contact/' . $providerId;\n\n break;\n\n case 'opportunity':\n $url = $baseUrl . 'deal/' . $providerId;\n\n break;\n\n case 'task':\n case 'activity':\n return null;\n\n // This should not be deep-linked as per JMNY-3934.\n //$url = $baseUrl.'tasks/list/view/all/?taskId='.$providerId;\n break;\n }\n\n return $url;\n }\n\n public function searchCalls(Carbon $from, Carbon $to, string $activityProvider): array\n {\n $this->logger->info('[HubSpot] Search calls', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n ]);\n\n $calls = [];\n $page = 1;\n\n do {\n try {\n $payload = $this->payloadBuilder->generateGetCallsPayload($from, $to, $activityProvider, $page);\n $response = $this->client->getInstance()->getClient()->request(\n 'POST',\n self::CALLS_SEARCH_ENDPOINT,\n ['json' => ($payload)],\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search calls failed', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n 'reason' => $exception->getMessage(),\n ]);\n $response = null;\n }\n\n $responseResults = empty($response['results']) ? [] : $response['results'];\n $calls = array_merge($calls, $responseResults);\n $page++;\n } while (! empty($responseResults));\n\n return $calls;\n }\n\n public function searchCallsForPeriodByPage(Carbon $from, Carbon $to, int $page, bool $retry = true)\n {\n try {\n $payload = $this->payloadBuilder->generateSearchCallsByPeriodPayload($from, $to, $page);\n $response = $this->client->getInstance()->getClient()->request(\n 'POST',\n self::CALLS_SEARCH_ENDPOINT,\n ['json' => ($payload)],\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search calls for period failed', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n 'reason' => $exception->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep(1);\n\n return $this->searchCallsForPeriodByPage($from, $to, $page, false);\n }\n $response = null;\n }\n\n return $response;\n }\n\n public function searchCallsForPeriod(Carbon $from, Carbon $to): Generator\n {\n $this->logger->info('[HubSpot] Search calls for period', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n ]);\n\n $page = 1;\n\n do {\n $response = $this->searchCallsForPeriodByPage($from, $to, $page);\n\n $responseResults = empty($response['results']) ? [] : $response['results'];\n\n $associationContacts = $this->getAssociationDataForCollection($responseResults, 'calls', 'contacts');\n $associationCompanies = $this->getAssociationDataForCollection($responseResults, 'calls', 'companies');\n $associationDeals = $this->getAssociationDataForCollection($responseResults, 'calls', 'deals');\n\n foreach ($responseResults as $call) {\n $call['associations'] = [\n 'contacts' => $this->importAssociationData($call, $associationContacts),\n 'companies' => $this->importAssociationData($call, $associationCompanies),\n 'deals' => $this->importAssociationData($call, $associationDeals),\n ];\n\n yield $call;\n }\n $page++;\n } while (! empty($responseResults));\n }\n\n public function getCall(string $callId): array\n {\n $this->logger->info('[HubSpot] Get call', [\n 'call_id' => $callId,\n ]);\n\n $searchAttributes = $this->payloadBuilder->getSearchCallAttributes();\n $endpoint = sprintf(\n 'https://api.hubapi.com/crm/v3/objects/calls/%s',\n $callId,\n );\n\n try {\n $response = $this->client->getInstance()->getClient()->request(\n 'GET',\n $endpoint,\n [],\n sprintf(\n 'properties=%s&associations=contacts,companies,deals',\n implode(',', $searchAttributes),\n ),\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Get call failed', [\n 'call_id' => $callId,\n 'reason' => $exception->getMessage(),\n ]);\n $response = null;\n }\n\n return empty($response) ? [] : $response->toArray();\n }\n\n public function bulkAddPlaybackURLToDescription(array $crmUpdateData): array\n {\n $crmUpdateBatches = array_chunk($crmUpdateData, self::BATCH_UPDATE_LIMIT);\n\n $updatedCrmIds = [];\n\n foreach ($crmUpdateBatches as $crmBatch) {\n $payload = $this->payloadBuilder->generatePlaybackAddUrlBatchPayload($crmBatch);\n $updateSuccess = $this->bulkAddPlaybackURLToDescriptionRequest($payload);\n if ($updateSuccess) {\n $updatedCrmIds = array_merge($updatedCrmIds, array_column($crmBatch, 'crm_id'));\n }\n }\n\n return $updatedCrmIds;\n }\n\n private function bulkAddPlaybackURLToDescriptionRequest(array $payload, bool $retry = true): bool\n {\n try {\n $this->client->getNewInstance()->crm()->objects()->batchApi()->update('calls', $payload);\n\n return true;\n } catch (\\HubSpot\\Client\\Crm\\Objects\\ApiException $e) {\n $response = json_decode($e->getResponseBody(), true);\n $retryAfter =\n isset($response['policyName'])\n && $response['policyName'] == self::TEN_SECONDLY_ROLLING_POLICY\n ? self::TEN_SECONDLY_ROLLING_LIMIT\n : 1;\n } catch (Exception $e) {\n $retryAfter = 1;\n }\n\n $this->logger->warning('[HubSpot] Bulk add playback url to CRM failed', [\n 'reason' => $e->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep($retryAfter);\n\n return $this->bulkAddPlaybackURLToDescriptionRequest($payload, false);\n }\n\n return false;\n }\n\n /**\n * Sometimes we have secondly rate limit error, then retry request after 1 second\n */\n public function searchCallByRecordingURLToken(string $playbackURLToken, bool $retry = true): array\n {\n $endpoint = 'https://api.hubapi.com/crm/v3/objects/calls/search';\n $payload = $this->payloadBuilder->generateSearchCallByTokenPayload($playbackURLToken);\n\n $this->logger->info('[HubSpot] CRM Search by playback URL token requested', [\n 'request' => $payload,\n ]);\n\n try {\n $response = $this->client->getInstance()->getClient()->request('POST', $endpoint, ['json' => ($payload)]);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search by playback URL token failed', [\n 'playbackURLToken' => $playbackURLToken,\n 'reason' => $exception->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep(1);\n\n return $this->searchCallByRecordingURLToken($playbackURLToken, false);\n }\n\n return [];\n }\n\n return empty($response['results']) ? [] : $response['results'][0];\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! $this->config->store_transcript) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n $transcriptionSegments = $this->transcriptionService->findTranscriptionByActivity($activity);\n\n if ($transcriptionSegments->isEmpty()) {\n return '';\n }\n\n $transcription = sprintf(\n '<p><strong>Transcript for %s</strong></p><p></p>',\n $activity->title ?? $activity->activity_title,\n );\n\n $roomOwnerParticipant = $activity->findParticipantRoomOwner();\n $roomOwnerParticipantId = $roomOwnerParticipant !== null\n ? $roomOwnerParticipant->getId()\n : null;\n\n\n $transcription .= $transcriptionSegments\n ->map(static function (array $transcriptionSegment) use ($roomOwnerParticipantId): string {\n $isOrganiser = $roomOwnerParticipantId === $transcriptionSegment['participantId']\n && $roomOwnerParticipantId !== null;\n $transcriptColor = $isOrganiser ? '#000000' : '#f0415a';\n\n return sprintf(\n '<span style=\"color: %s;\">%s | </span>%s',\n $transcriptColor,\n $transcriptionSegment['formattedStartsAt'],\n $transcriptionSegment['transcript'],\n );\n })\n ->implode('<br />');\n\n return $transcription;\n }\n\n /**\n * @param array<array{\n * id: string,\n * label: string,\n * value?: string,\n * }> $options\n *\n * @return FieldData[]\n */\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $values = [];\n $sequence = 0;\n\n foreach ($options as $option) {\n $values[] = [\n 'value' => $option['value'] ?? $option['id'],\n 'label' => substr($option['label'], 0, 255),\n 'sequence' => $sequence++,\n ];\n }\n\n $fieldsToPurge = $field->values()->get()->pluck('value')->toArray();\n\n foreach ($values as $value) {\n $value['value'] = substr($value['value'], 0, 255);\n $fieldValues[] = $field->values()->updateOrCreate([\n 'value' => $value['value'],\n ], $value);\n\n // Remove this value from the ones we are going to purge.\n if (($key = array_search($value['value'], $fieldsToPurge, false)) !== false) {\n unset($fieldsToPurge[$key]);\n }\n }\n\n // Delete the old values that are no longer used.\n $field->values()->whereIn('value', $fieldsToPurge)->delete();\n\n return $fieldValues;\n }\n\n public function saveTranscriptionSummaryAsNote(\n ActivityContract $activity,\n string $title,\n string $body,\n ?string $objectId,\n ?NoteObject $noteObject = null,\n ): ?string {\n if ($noteObject === null || $objectId === null) {\n return null;\n }\n\n /** @var User $user */\n $user = $activity->getUser();\n\n $profile = $this->assignCrmOwner($user, $activity);\n if (! $profile instanceof Profile) {\n return null;\n }\n\n $timestamp = Carbon::now($user->getTimezone())->getTimestamp() * 1000;\n $engagement = [\n 'active' => true,\n 'ownerId' => $profile->getAttribute('crm_provider_id'),\n 'timestamp' => $timestamp,\n 'type' => 'NOTE',\n ];\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $body = mb_strimwidth($body, 0, self::ENGAGEMENT_BODY_MAX_LENGTH);\n $metadata = [\n 'body' => $body,\n ];\n\n $associations = $this->convertActivityAssociations($activity);\n\n try {\n $hsActivityId = $this->client->createNote(\n body: $body,\n ownerId: $profile->getCrmProviderId(),\n timestamp: $timestamp,\n objectId: $objectId,\n noteObject: $noteObject,\n );\n\n $this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);\n\n $this->logger->info('[HubSpot] Saving Transcription Summary as Note', [\n 'activity' => $activity->getUuid(),\n 'crmActivity' => $hsActivityId,\n ]);\n\n return $hsActivityId;\n } catch (Exception $e) {\n Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function attachSummaryToActivity(ActivityContract $activity, string $summaryTitle, string $summaryContents): bool\n {\n $this->logger->info('[HubSpot] Attaching summary to activity', [\n 'activity' => $activity->getUuid(),\n 'summary_content' => $summaryContents,\n ]);\n\n if (! $activity instanceof Activity) {\n throw new InvalidArgumentException('Expected instance of Activity');\n }\n\n $summary = '<p><strong>' . $summaryTitle . '</strong></p>';\n $summary .= '<p>' . $summaryContents . '</p>';\n $metadata = $this->buildMetadataForSummaryUpdate($activity, $summary);\n\n try {\n $type = $this->matchActivityEngagementType($activity);\n $engagement = ['type' => $type];\n\n $this->client->updateEngagement($activity->getCrmProviderId(), $engagement, $metadata);\n } catch (Exception $e) {\n $this->logger->warning('[HubSpot] Update summary failed', [\n 'activity' => $activity->getUuid(),\n 'reason' => $e->getMessage(),\n ]);\n\n return false;\n }\n\n $this->logCrmEngagementManipulation(\n self::ACTION_UPDATE,\n ['crmId' => $activity->getCrmProviderId()],\n $metadata,\n );\n\n return true;\n }\n\n private function buildMetadataForSummaryUpdate(Activity $activity, string $summary): array\n {\n $descriptionField = $activity->getType() === Activity::TYPE_CONFERENCE ? 'internalMeetingNotes' : 'body';\n $engagement = $this->client->getEngagementData($activity->getCrmProviderId());\n // Meeting without internalMeetingNotes might mean it just does not have any notes;\n $description = $engagement['metadata'][$descriptionField] ?? null;\n\n if (empty($description)) {\n $data = $summary;\n } else {\n // avoid playbook url link to Jiminny being sent twice in the activity description\n $targetUrl = PlaybackUrlBuilder::build($activity);\n\n if (str_contains($description, $targetUrl)) {\n $jiminnyUrl = '<p><a href=\"' . $targetUrl . '\" title=\"Play at Jiminny\">Play at Jiminny</a></p>';\n $summary = str_replace($jiminnyUrl, '', $summary);\n\n $this->logger->info('[HubSpot] Summary modified', [\n 'activity' => $activity->getUuid(),\n 'target_url' => $jiminnyUrl,\n 'modified_summary_content' => $summary,\n ]);\n }\n\n $data = $description . '<p></p>' . $summary;\n }\n\n return [\n $descriptionField => $data,\n ];\n }\n\n public function fetchAndAssociateRelatedActivity(Activity $activity): ?Activity\n {\n return $this->syncRelatedActivityManager->fetchAndAssociateRelatedActivity($activity);\n }\n\n public function fetchRelatedActivity(Activity $activity): array\n {\n return [];\n }\n\n public function getDealsInBulk(array $dealIds): array\n {\n $payload = $this->payloadBuilder->getDealsInBulkPayload($dealIds);\n\n return $this->client->getPaginatedData($payload, 'deals');\n }\n\n /**\n * Extract deal IDs from HubSpot search response.\n *\n * @param array $hubspotResponse The raw HubSpot search API response.\n * @param bool $includeArchived Whether to include archived deals (default: false).\n *\n * @return string[] Array of deal IDs as strings.\n */\n public function extractDealIds(array $hubspotResponse, bool $includeArchived = false): array\n {\n if (empty($hubspotResponse['results'])) {\n return [];\n }\n\n return array_values(\n array_map(\n fn ($deal) => $deal['id'],\n array_filter(\n $hubspotResponse['results'],\n fn ($deal) => $includeArchived || empty($deal['archived'])\n )\n )\n );\n }\n\n public function matchActivityEngagementType(Activity $activity): string\n {\n return match ($activity->getType()) {\n Activity::TYPE_CONFERENCE => self::TYPE_MEETING,\n Activity::TYPE_SOFTPHONE, Activity::TYPE_SOFTPHONE_INBOUND => self::TYPE_CALL,\n default => self::TYPE_NOTE,\n };\n }\n\n private function assignCrmOwner(User $user, ActivityContract $activity): ?Profile\n {\n $profile = $user->getProfile();\n if ($profile instanceof Profile) {\n return $profile;\n }\n\n $this->logger->info('[HubSpot] Unable to save summary. No profile', [\n 'activity' => $activity->getUuid(),\n ]);\n\n return null;\n }\n\n private static function getDealsPipelinesEndpoint(): string\n {\n return self::API_URL . self::ENDPOINT_PIPELINES . self::PIPELINE_OBJECT_TYPE_DEALS;\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n $engagement = $this->client->getEngagementData($crmProviderId);\n\n return ! empty($engagement);\n } catch (HttpNotFoundException|BadRequest) {\n // Engagement not found in CRM - this is expected and permanent\n $this->logger->info('[Hubspot] Engagement not found during verification', [\n 'engagement_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\n });\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse Generator;\nuse GuzzleHttp\\Exception\\RequestException;\nuse HubSpot\\Client\\Crm\\Owners\\Model\\PublicOwner;\nuse Illuminate\\Support\\Facades\\Cache;\nuse InvalidArgumentException;\nuse Jiminny\\Contracts\\Repositories\\TeamRepository;\nuse Jiminny\\Contracts\\Services\\Crm\\ClientInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\FetchRelatedActivityInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\HubspotInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SavePlaybackLinkToCrmInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SendSummaryToCrmInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Contracts\\ActivityContract;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\Layout;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Participant;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Repositories\\ParticipantRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Hubspot\\Actions\\SyncArchivedProfilesAction;\nuse Jiminny\\Services\\Crm\\Hubspot\\Fields\\ValueNormalizer;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\OpportunitySyncTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\SyncCrmEntitiesTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\SyncFieldsTrait;\nuse Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits\\WriteCrmTrait;\nuse Jiminny\\Services\\Crm\\MatchDomainByEmailInterface;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Services\\Crm\\ResolveCompanyNameByEmailTrait;\nuse Jiminny\\Utils\\PlaybackUrlBuilder;\nuse Sentry;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse Throwable;\nuse UnexpectedValueException;\n\n/**\n * @phpstan-type CrmFieldDefinition array{\n * name: string,\n * label: string,\n * description: string,\n * type: string,\n * fieldType: string,\n * hidden: bool,\n * showCurrencySymbol: bool,\n * options: array<array{\n * id: string,\n * label: string,\n * value?: string,\n * }\n */\nclass Service extends BaseService implements\n HubspotInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n SendSummaryToCrmInterface,\n MatchDomainByEmailInterface,\n SavePlaybackLinkToCrmInterface,\n RemoteEntityManipulationInterface,\n FetchRelatedActivityInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n VerifyTaskExistsInterface\n{\n use ResolveCompanyNameByEmailTrait;\n use SyncCrmEntitiesTrait;\n use WriteCrmTrait;\n use SyncFieldsTrait;\n use OpportunitySyncTrait;\n\n private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;\n\n private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';\n private const int BATCH_UPDATE_LIMIT = 100;\n private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';\n private const int TEN_SECONDLY_ROLLING_LIMIT = 10;\n private const string CALLS_SEARCH_ENDPOINT = 'https://api.hubapi.com/crm/v3/objects/calls/search';\n\n private const string TYPE_NOTE = 'NOTE';\n\n private const string TYPE_MEETING = 'MEETING';\n\n private const string TYPE_CALL = 'CALL';\n\n private const string API_URL = 'https://api.hubapi.com';\n\n // NB: v1 is legacy - v3 is the newest\n private const string ENDPOINT_PIPELINES = '/crm-pipelines/v1/pipelines/';\n private const string PIPELINE_OBJECT_TYPE_DEALS = 'deals';\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n /**\n * @var ClientInterface|Client\n */\n protected $client;\n protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;\n protected CrmEntityRepository $crmEntityRepository;\n protected ProspectPhotoPathService $prospectPhotoPathService;\n\n private SyncFieldAction $syncFieldAction;\n private PayloadBuilder $payloadBuilder;\n private SyncRelatedActivityManager $syncRelatedActivityManager;\n private SyncArchivedProfilesAction $syncArchivedProfilesAction;\n private WebhookSyncBatchProcessor $batchProcessor;\n\n public function __construct(\n Client $client,\n SyncFieldAction $syncFieldAction,\n PayloadBuilder $payloadBuilder,\n ProspectPhotoPathService $prospectPhotoPathService,\n SyncArchivedProfilesAction $syncArchivedProfilesAction,\n WebhookSyncBatchProcessor $batchProcessor,\n ) {\n parent::__construct();\n\n $this->client = $client;\n $this->syncFieldAction = $syncFieldAction;\n $this->prospectPhotoPathService = $prospectPhotoPathService;\n $this->payloadBuilder = $payloadBuilder;\n $this->syncArchivedProfilesAction = $syncArchivedProfilesAction;\n $this->batchProcessor = $batchProcessor;\n $this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->client,\n ]);\n $this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [\n 'client' => $this->client,\n 'payloadBuilder' => $this->payloadBuilder,\n 'logger' => $this->logger,\n ]);\n $this->crmEntityRepository = app(CrmEntityRepository::class);\n $this->dealFieldsService = app(DealFieldsService::class);\n }\n\n public function getDisplayName(): string\n {\n return 'HubSpot';\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n $owner = $user->team->owner;\n\n return $owner->getSocialAccount(SocialAccount::PROVIDER_HUBSPOT);\n }\n\n public function getClient(): Client\n {\n /** @var Client */\n return $this->client;\n }\n\n /**\n * Convert raw field data into a format compatible with CRM APIs.\n *\n * @param bool $internal Direction of the conversion.\n * True is pulling from CRM, false normalize before sending to CRM.\n */\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return ValueNormalizer::normalize(\n fieldType: $fieldType,\n fieldValue: $fieldValue,\n isInbound: $internal,\n );\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n /** @var Field $activityField */\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'activityType',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n // Outcome should always be provided calls/meetings.\n $fieldData = [\n [\n 'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',\n 'object_type' => Field::OBJECT_TASK,\n ],\n ];\n\n foreach ($fieldData as $data) {\n $field = $this->config->fields()->where($data)->first();\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n }\n\n return $fields;\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n $fieldData = FieldDefinitions::followupFieldsFilter();\n\n foreach ($fieldData as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function syncField(Field $field): void\n {\n switch ($field->object_type) {\n case Field::OBJECT_ACCOUNT:\n $crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_CONTACT:\n $crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_OPPORTUNITY:\n $crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);\n\n break;\n case Field::OBJECT_TASK:\n $this->syncSingleTaskField($field);\n\n return;\n default:\n return;\n }\n\n $this->syncFieldAction->execute($field, $crmField->toArray());\n }\n\n /**\n * @param array<array{\n * id:string,\n * label:string,\n * value?:string\n * }> $options\n *\n * @throws CrmException\n *\n * @return FieldData[]\n *\n */\n public function importPicklistValues(\n Field $field,\n array $options = [['id' => '', 'label' => '', 'value' => '']],\n ): array {\n if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {\n // We already have the options, no need to fetch them again\n return $this->importOptions($field, $options);\n }\n\n $options = [];\n\n switch ($field->getObjectType()) {\n case Field::OBJECT_ACCOUNT:\n $options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());\n\n break;\n\n case Field::OBJECT_CONTACT:\n $options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());\n\n break;\n\n case Field::OBJECT_OPPORTUNITY:\n // Hubspot has different endpoint for stages\n $options = $this->getClient()->fetchOpportunityFieldOptions($field);\n\n break;\n\n case Field::OBJECT_TASK:\n if ($field->getCrmProviderId() === 'disposition') {\n $options = $this->getClient()->fetchDispositionFieldOptions();\n } elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {\n $options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);\n }\n\n break;\n\n default:\n $this->logger->warning('Invalid object type', [\n 'object_type' => $field->getObjectType(),\n 'field_id' => $field->getId(),\n ]);\n\n throw new CrmException('Invalid object type');\n }\n\n return $this->importOptions($field, $options);\n }\n\n /**\n * @inheritdoc\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n $missingStage = null;\n\n try {\n // Use the HubSpot API client instead of the SDK crmPipelines() method\n $endpoint = self::getDealsPipelinesEndpoint();\n $pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);\n $pipelines = $pipelinesResponse->data->results;\n } catch (RequestException|BadRequest $exception) {\n throw $exception;\n }\n\n foreach ($pipelines as $pipeline) {\n $stages = [];\n\n // We create a business process to contain the pipeline, and store all stages against it.\n $p = ResponseNormalize::normalizePipeline($pipeline);\n\n // Create/update business process for this pipeline\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => $p['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($p['label'], 0, 150),\n 'type' => BusinessProcess::TYPE_OPPORTUNITY,\n 'is_selectable' => $p['active'],\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n // Create/update record type clone\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => $p['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($p['label'], 0, 150),\n 'is_selectable' => $p['active'],\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n // Stages - fetch all existing stages upfront to avoid N+1 queries\n $existingStages = $this->config->stages()\n ->withTrashed()\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->get()\n ->keyBy('crm_provider_id');\n\n foreach ($p['stages'] as $dealStage) {\n $s = ResponseNormalize::normalizeDealStage($dealStage);\n\n /** @var ?Stage $existingStage */\n $existingStage = $existingStages->get($s['id']);\n\n // Restore soft-deleted stages that are now active in HubSpot\n if ($existingStage?->trashed() && $s['active']) {\n $existingStage->restore();\n }\n\n // Upsert stage (updates soft-deleted records without restoring them)\n $stage = $this->config->stages()->withTrashed()->updateOrCreate([\n 'crm_provider_id' => $s['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($s['label'], 0, 50),\n 'label' => mb_strimwidth($s['label'], 0, 191),\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'sequence' => $s['displayOrder'],\n 'is_selectable' => $s['active'],\n 'probability' => $s['probability'] * 100,\n ]);\n\n if ($missingStageName === $s['id']) {\n $missingStage = $stage;\n }\n\n $stages[] = $stage->id;\n }\n\n $businessProcess->stages()->sync($stages);\n }\n\n return $missingStage;\n }\n\n /**\n * @inheritdoc\n */\n public function syncOrganization(): void\n {\n try {\n $endpoint = 'https://api.hubapi.com/integrations/v1/me';\n $response = $this->client->getInstance()->getClient()->request('get', $endpoint);\n\n $accountData = $response->data;\n $this->config->update(['default_currency' => $accountData->currency]);\n } catch (BadRequest $e) {\n throw new CrmException('Could not sync the organization.', $e->getCode(), $e);\n }\n }\n\n /**\n * @inheritdoc\n *\n * @throws CrmException\n */\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n $this->syncArchivedProfilesAction->execute($this->team, $this->client, $this->config);\n\n try {\n $owners = $this->client->getOwners();\n } catch (\\HubSpot\\Client\\Crm\\Owners\\ApiException $e) {\n $this->handleOwnersApiException($e);\n }\n\n $profileRepository = app(ProfileRepository::class);\n $teamRepository = app(TeamRepository::class);\n\n foreach ($owners as $owner) {\n $profile = $this->processOwner($owner, $teamRepository, $profileRepository);\n\n if ($profile && $userToSearch && $userToSearch->getId() === $profile->getUserId()) {\n return $profile;\n }\n }\n\n return null;\n }\n\n private function handleOwnersApiException(\\HubSpot\\Client\\Crm\\Owners\\ApiException $e): never\n {\n $statusCode = $e->getCode();\n $errorMessage = $e->getMessage();\n $responseBody = $this->parseResponseBody($e->getResponseBody());\n\n $isPermissionError = $this->isPermissionError($statusCode, $errorMessage, $responseBody);\n\n $logContext = [\n 'team_id' => $this->team->getId(),\n 'team_uuid' => $this->team->getUuid(),\n 'config_id' => $this->config->getId(),\n 'status_code' => $statusCode,\n 'error_message' => $errorMessage,\n 'response_body' => $responseBody,\n ];\n\n if ($isPermissionError) {\n $this->logPermissionError($logContext);\n } else {\n $this->logger->error('[HubSpot] Could not sync the profiles.', $logContext);\n }\n\n throw new CrmException('Could not sync the profiles.', $e->getCode(), $e);\n }\n\n private function parseResponseBody(?string $rawBody): ?array\n {\n if ($rawBody === null || $rawBody === '') {\n return null;\n }\n\n try {\n return json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR);\n } catch (\\JsonException) {\n return null;\n }\n }\n\n private function logPermissionError(array $logContext): void\n {\n $this->logger->critical(\n '[HubSpot] ⚠️ PERMISSION ERROR: Cannot sync profiles - Missing OAuth scopes',\n array_merge($logContext, [\n 'action_required' => 'Request additional HubSpot OAuth scopes',\n 'required_scope' => 'crm.objects.owners.read',\n 'impact' => 'Opportunities will have owner_id but NO user_id - AI automation and reporting will fail',\n 'resolution' => 'Manually request scope from HubSpot account admin or re-authenticate',\n ])\n );\n }\n\n private function processOwner(\n PublicOwner $owner,\n TeamRepository $teamRepository,\n ProfileRepository $profileRepository\n ): ?Profile {\n if ($owner->getArchived()) {\n $this->logger->warning('[HubSpot] Found archived owner', [\n 'crm_provider_id' => $owner->getId(),\n 'email' => $owner->getEmail(),\n ]);\n\n return null;\n }\n\n $email = $owner->getEmail();\n if ($email === null) {\n return null;\n }\n\n $user = $teamRepository->findActiveTeamMemberByEmail($this->team, $email);\n if (! $user instanceof User) {\n return null;\n }\n\n return $profileRepository->updateOrCreateProfile($user, [\n 'crm_configuration_id' => $this->config->getId(),\n 'crm_provider_id' => $owner->getId(),\n ]);\n }\n\n private function isPermissionError(int $statusCode, string $errorMessage, ?array $responseBody): bool\n {\n // Check HTTP 403 Forbidden\n if ($statusCode === 403) {\n return true;\n }\n\n // Check for scope-related keywords in error message\n $scopeKeywords = ['scope', 'permission', 'forbidden', 'unauthorized', 'access denied', 'oauth'];\n $lowerErrorMessage = strtolower($errorMessage);\n\n foreach ($scopeKeywords as $keyword) {\n if (str_contains($lowerErrorMessage, $keyword)) {\n return true;\n }\n }\n\n // Check response body for scope errors\n if ($responseBody !== null) {\n return $this->arrayContainsKeyword($responseBody, $scopeKeywords);\n }\n\n return false;\n }\n\n /**\n * Recursively search array for keywords in values\n */\n private function arrayContainsKeyword(array $data, array $keywords): bool\n {\n foreach ($data as $value) {\n if (is_array($value)) {\n if ($this->arrayContainsKeyword($value, $keywords)) {\n return true;\n }\n } elseif (is_string($value)) {\n $lowerValue = strtolower($value);\n foreach ($keywords as $keyword) {\n if (str_contains($lowerValue, $keyword)) {\n return true;\n }\n }\n }\n }\n\n return false;\n }\n\n private function generateNameSearchPayload(string $name, int $offset, int $limit): array\n {\n $payload = [\n 'query' => $name,\n 'sorts' => [\n [\n 'propertyName' => 'modifieddate',\n 'direction' => 'DESCENDING',\n ],\n ],\n 'properties' => [\n 'email',\n 'firstname',\n 'lastname',\n 'country',\n 'phone',\n 'mobilephone',\n 'jobtitle',\n 'hubspot_owner_id',\n 'associatedcompanyid',\n 'photo',\n 'industry',\n 'name',\n 'company',\n ],\n 'limit' => $limit,\n 'after' => $offset,\n ];\n\n $this->logger->debug('[HubSpot] CRM Search requested', [\n 'request' => $payload,\n ]);\n\n return $payload;\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n /** @var array<int, array<string, mixed>> */\n return Cache::remember(\n key: $this->team->getId() . $name . $count . $offset,\n ttl: 300,\n callback: function () use ($name, $offset, $count): array {\n $data = [];\n\n // Use the new V3 API to find contacts based on additional fields.\n foreach (['companies', 'contacts'] as $objectType) {\n $endpoint = 'https://api.hubapi.com/crm/v3/objects/' . $objectType . '/search';\n $payload = $this->generateNameSearchPayload($name, $offset, $count);\n $type = $objectType === 'companies' ? 'account' : 'contact';\n\n try {\n $response = $this->client->getInstance()->getClient()->request('POST', $endpoint, [\n 'json' => $payload,\n ]);\n\n // Build mapped list.\n foreach ($response['results'] as $object) {\n $properties = $object['properties'];\n\n $objectName = $this->buildContactName($properties);\n\n $record = [\n 'crmId' => $object['id'],\n // Pass crmUrl to the FE, needed for success message in the extension when you log activity.\n 'crmUrl' => $this->generateProviderUrl($object['id'], $type),\n 'name' => $objectName,\n 'prospectType' => $type,\n 'phoneNumbers' => [],\n ];\n\n if ($type === 'account') {\n $record['industry'] = $properties['industry'] ?? null;\n } else {\n $record['title'] = $properties['jobtitle'] ?? null;\n $record['organization'] = $properties['company'] ?? null;\n }\n\n $countryCode = $this->buildContactCountry($properties);\n $parsedNumber = $this->buildContactPhone($countryCode, $properties);\n\n // Add phone number to record.\n if (! empty($parsedNumber['phone'])) {\n $record['phoneNumbers'][] = [\n 'number' => $parsedNumber['phone'],\n 'nationalFormat' => phone_national($countryCode, $parsedNumber['phone']),\n 'type' => 'phone',\n ];\n }\n\n // Add mobile phone number to record.\n if (! empty($properties['mobilephone'])) {\n $mobileNumber = phone_e164($countryCode, $properties['mobilephone']);\n if ($mobileNumber !== null) {\n $record['phoneNumbers'][] = [\n 'number' => $mobileNumber,\n 'nationalFormat' => phone_national($countryCode, $mobileNumber),\n 'type' => 'mobile',\n ];\n }\n }\n\n $data[] = $record;\n }\n } catch (BadRequest $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [\n 'teamId' => $this->team->getUuid(),\n 'request' => $payload,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n }\n\n return $data;\n },\n );\n }\n\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n\n if ($crmAccountId === null) {\n return $data;\n }\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n $closedStages = $this->getClosedDealStages();\n $payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(\n $this->config,\n $crmAccountId,\n $closedStages,\n );\n\n $results = $this->client->getPaginatedData($payload, 'deals');\n\n foreach ($results['results'] as $object) {\n $properties = $object['properties'];\n\n $amount = null;\n if (empty($properties['amount']) === false) {\n $currency = $properties['deal_currency_code'] ?? $this->config->default_currency;\n\n // Values can contain commas and any junk so strip them.\n $value = (float) preg_replace('/[^\\d.]/', '', $properties['amount']);\n $amount = formatCurrency($value, $currency);\n }\n\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', $properties['pipeline'])\n ->first();\n\n if ($businessProcess === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', $properties['pipeline'])\n ->first();\n } else {\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', $properties['dealstage'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages(null, $properties['dealstage']);\n }\n }\n\n $recordType = null;\n if ($businessProcess) {\n $recordType = $businessProcess->recordTypes()->first();\n }\n\n $isWon = in_array($properties['dealstage'], $closedStages['won']);\n $isLost = in_array($properties['dealstage'], $closedStages['lost']);\n\n $record = [\n 'crmId' => $object['id'],\n 'name' => $properties['dealname'] ?? 'Unknown Deal',\n 'value' => $amount,\n 'won' => $isWon,\n 'closed' => $isWon || $isLost,\n 'stage' => [\n 'id' => $stage?->getUuid() ?? '',\n 'name' => $stage?->getName() ?? '',\n ],\n ];\n\n if ($recordType) {\n $record += [\n 'recordType' => [\n 'id' => $recordType->id_string,\n 'name' => $recordType->name,\n ],\n ];\n }\n\n if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(?string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = [];\n switch ($objectType) {\n case 'contact':\n $hsObject = 'contact';\n\n break;\n case 'account':\n $hsObject = 'company';\n\n break;\n default:\n // This is a hack to prioritise and override a contact/company with a deal.\n if ($opportunityId) {\n $hsObject = 'deal';\n $objectId = $opportunityId;\n } else {\n throw new InvalidArgumentException('Object type not supported.');\n }\n }\n\n $engagementTypes = ['meetings', 'tasks'];\n\n foreach ($engagementTypes as $engagementType) {\n $payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);\n\n $this->logger->info('[HubSpot] CRM Search requested', [\n 'request' => $payload,\n ]);\n\n $engagements = $this->client->getPaginatedData($payload, $engagementType);\n\n foreach ($engagements['results'] as $engagement) {\n if ($engagementType == 'meetings') {\n $title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';\n } elseif ($engagementType == 'tasks') {\n $title = $engagement['properties']['hs_task_subject'];\n } else {\n $title = 'Scheduled meeting';\n }\n\n $data[] = [\n 'crmId' => $engagement['id'],\n 'subject' => $title,\n 'due' => $engagement['properties']['hs_timestamp'],\n 'type' => $engagement['properties']['hs_activity_type'] ?? null,\n ];\n }\n }\n\n usort($data, function ($item1, $item2) {\n return $item2['due'] <=> $item1['due'];\n });\n\n return $data;\n }\n\n /**\n * Try to find CRM Objects using email address\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $contactProperties = [\n 'email',\n 'firstname',\n 'lastname',\n 'country',\n 'phone',\n 'mobilephone',\n 'jobtitle',\n 'hubspot_owner_id',\n 'associatedcompanyid',\n 'photo',\n ];\n $contact = null;\n $account = null;\n\n try {\n $hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);\n\n if ($hsContact) {\n $contact = $this->importContact($hsContact);\n $account = $contact->account;\n }\n\n $data = $this->convertCrmData($contact, $account, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n } catch (BadRequest $e) {\n $this->logger->warning('[HubSpot] Search failed', [\n 'team_id' => $this->team->getId(),\n 'search_identifier' => $email,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return null;\n }\n\n public function getDomain(string $email): ?string\n {\n return $this->getDomainFromEmail($email);\n }\n\n /**\n * Try to find CRM objects using domain name of the email address\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByDomain(string $domain, ?int $userId = null): ?array\n {\n $companyName = $domain;\n\n // Try to find a company matching their email domain.\n $companyProperties = [\n 'country',\n 'phone',\n 'name',\n 'hs_avatar_filemanager_key',\n 'industry',\n 'hubspot_owner_id',\n 'domain',\n ];\n\n try {\n $hsAccounts = $this->client\n ->getInstance()\n ->companies()\n ->searchByDomain($companyName, $companyProperties);\n } catch (Throwable $e) {\n $this->logger->info('[HubSpot] Search failed', [\n 'error' => $e->getMessage(),\n 'domain' => $domain,\n ]);\n\n return null;\n }\n\n $account = null;\n // If there are multiple accounts, don't guess, we'll ask later.\n if (\\count($hsAccounts->data->results) === 1) {\n // Persist this remote object.\n $account = $this->syncAccount($hsAccounts->data->results[0]->companyId);\n }\n\n $data = $this->convertCrmData(null, $account, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n /**\n * @return array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array\n {\n $countryCode = null;\n if ($contact && $contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account && $account->country_code) {\n $countryCode = $account->country_code;\n }\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact ? $contact->crm_provider_id : null,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n // If there are multiple opportunities, don't guess, we'll ask later.\n $opportunity = null;\n $stage = null;\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n protected function getCacheKey(string $object, ?int $userId = null): ?string\n {\n $key = $this->team->getId() . $object;\n $keySuffix = $this->getOwnerKeySuffix($userId);\n\n return $key . $keySuffix;\n }\n\n private function getOwnerKeySuffix(?int $userId = null): string\n {\n return $userId === null ? '' : (string) $userId;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n if (str_contains($phone, '**')) {\n return null;\n }\n\n // trim all whitespaces if present so the lookup doesn't fail\n $phone = str_replace(' ', '', $phone);\n\n // Check if the user is internal.\n if ($this->isPhoneNumberOfTeamMember($phone)) {\n return null;\n }\n\n $response = $this->searchForPhoneNumber($phone);\n if (empty($response)) {\n return null;\n }\n\n // This would ideally importContact instead but the response type differs.\n $contact = $this->findAndSyncContact($response['results'][0]['id']);\n if (! $contact instanceof Contact) {\n return null;\n }\n\n $account = $contact->account;\n $countryCode = $contact->country_code ?? $account->country_code ?? null;\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n $opportunity = null;\n $stage = null;\n\n try {\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (Exception $e) {\n $this->logger->debug('[HubSpot] Opportunity failed to sync.', [\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n private function isPhoneNumberOfTeamMember(string $phone): bool\n {\n $teamRepository = app(TeamRepository::class);\n $user = $teamRepository->findTeamMemberByPhone($this->team, $phone);\n\n if ($user instanceof User) {\n return true;\n }\n\n return false;\n }\n\n private function findAndSyncContact(string $crmId): ?Contact\n {\n try {\n return $this->syncContact($crmId);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Phone match failed', [\n 'reason' => $exception->getMessage(),\n ]);\n\n return null;\n }\n }\n\n private function hasResults(array $response): bool\n {\n return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;\n }\n\n private function searchForPhoneNumber(string $phone): array\n {\n // Normalizes the provided phone number for the API search.\n $normalizedPhone = $this->normalizePhoneNumber($phone);\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);\n\n $this->logger->info('[HubSpot] Phone match search triggered', [\n 'phone' => $phone,\n 'normalizedPhone' => $normalizedPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);\n\n if (! $this->hasResults($response)) {\n $nationalPhone = preg_replace('/\\D/', '', phone_national(null, $phone));\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);\n\n $this->logger->info('[HubSpot] Phone match national number search triggered', [\n 'phone' => $phone,\n 'nationalPhone' => $nationalPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($phone, $payload);\n }\n\n if (! $this->hasResults($response)) {\n $payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);\n\n $this->logger->info('[HubSpot] Phone match alternative search triggered', [\n 'phone' => $phone,\n 'normalizedPhone' => $normalizedPhone,\n 'payload' => $payload,\n ]);\n\n $response = $this->handlePhoneSearchRequest($phone, $payload);\n }\n\n return $this->hasResults($response) ? $response : [];\n }\n\n private function handlePhoneSearchRequest(string $phone, array $payload): array\n {\n $endpoint = 'https://api.hubapi.com/crm/v3/objects/contacts/search';\n\n try {\n $response = $this->client->getInstance()->getClient()->request(\n 'POST',\n $endpoint,\n ['json' => ($payload)],\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Phone match failed', [\n 'phone' => $phone,\n 'reason' => $exception->getMessage(),\n ]);\n\n return [];\n }\n\n $this->logger->info('[HubSpot] Phone match completed', [\n 'phone' => $phone,\n 'response' => $response,\n ]);\n\n return $response->toArray();\n }\n\n private function normalizePhoneNumber(string $phone): string\n {\n return ltrim(phone_e164(null, $phone), '+0');\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $cacheKey = $this->getCacheKey($name, $userId);\n\n $result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {\n $payload = $this->payloadBuilder->generateSearchContactsByNamePayload(\n $name,\n $this->getContactFields()\n );\n\n $hsContacts = $this->client->getPaginatedData($payload, 'contact');\n if (empty($hsContacts['results'])) {\n return false;\n }\n\n $contact = $this->importContact($hsContacts['results'][0]);\n if ($contact === null) {\n return false;\n }\n\n $account = $contact->account;\n $countryCode = $contact->country_code ?? $account->country_code ?? null;\n\n try {\n $hsOpportunities = $this->findOpportunities(\n $account ? $account->crm_provider_id : null,\n $contact->crm_provider_id,\n $userId\n );\n } catch (Exception $e) {\n $hsOpportunities = [];\n }\n\n $opportunity = null;\n $stage = null;\n if (! empty($hsOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n\n return [\n null,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n });\n\n return is_array($result) ? $result : null;\n }\n\n\n private function convertActivityAssociations(Activity $activity): array\n {\n return [\n 'contactIds' => $this->getParticipantsIds($activity),\n 'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],\n 'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],\n 'ownerIds' => [],\n ];\n }\n\n private function getParticipantsIds(Activity $activity): array\n {\n $attendees = [];\n\n $participantRepository = app(ParticipantRepository::class);\n $participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);\n foreach ($participants as $participant) {\n if ($participant->user_id || $participant->isCoach()) {\n continue;\n }\n\n $contact = $participant->contact()->first();\n if ($contact && $contact->crm_provider_id) {\n $attendees[] = $contact->crm_provider_id;\n } else {\n if (! empty($participant->name)) {\n $attendeeData = $this->fetchMissingAttendeeInfo($participant);\n }\n if (! empty($attendeeData['id'])) {\n $attendees[] = $attendeeData['id'];\n }\n }\n }\n\n if ($activity->hasContact()) {\n $attendees[] = $activity->contact->crm_provider_id;\n }\n\n return array_unique($attendees);\n }\n\n private function fetchMissingAttendeeInfo(Participant $participant): array\n {\n // Check if we need to look inside an account context.\n $activity = $participant->getActivity();\n $companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;\n\n // First check the local data.\n /** @var Contact[] $contacts */\n $contacts = $this->team->contacts()\n ->with('account')\n ->where('name', $participant->name)\n ->whereNotNull('email')\n ->get();\n\n foreach ($contacts as $contact) {\n // If we have a company in scope, check the contact is associated to it.\n if (\n $companyId !== null\n && ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)\n ) {\n continue;\n }\n\n return [\n 'id' => $contact->crm_provider_id,\n 'email' => $contact->email,\n ];\n }\n\n $payload = $this->generateNameSearchPayload($participant->name, 0, 20);\n\n try {\n $response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);\n\n // TODO add some logic to choose the most suitable contact if multiple\n foreach ($response['results'] as $object) {\n $properties = $object['properties'];\n if (empty($object['properties']) === false) {\n // Check the company matches the contact.\n // Todo: Move this check inside the API search.\n if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {\n continue;\n }\n\n return [\n 'id' => $object['id'],\n 'email' => $properties['email'],\n ];\n }\n }\n } catch (Exception $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [\n 'teamId' => $this->team->id_string,\n 'request' => $payload,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n return [];\n }\n\n /**\n * Store transcripts as note engagement.\n *\n * @throws Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n // For HS no need to check if Crm profile - Log Notes field is enabled\n // We only check if store_transcript toggle is enabled on crm profile.\n $engagement = [\n 'active' => true,\n 'ownerId' => $this->profile->crm_provider_id,\n 'timestamp' => $activity->created_at->tz($activity->user->timezone)->getTimestamp() * 1000,\n 'type' => 'NOTE',\n ];\n\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, static::ENGAGEMENT_BODY_MAX_LENGTH);\n\n $metadata = [\n 'body' => $transcripts,\n ];\n\n $associations = $this->convertActivityAssociations($activity);\n\n try {\n $hsEngagement = $this->client\n ->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n\n $this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);\n\n $noteId = $hsEngagement->data->engagement->id;\n\n // Store crm logged id in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $noteId;\n $transcription->save();\n } catch (Exception $e) {\n Sentry::captureException($e);\n }\n }\n\n /*\n * @inheritdoc\n */\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $payload = [\n 'properties' => $data,\n ];\n\n try {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n $this->client->getNewInstance()->crm()->deals()->basicApi()->update($objectId, $payload);\n\n break;\n case FieldData::OBJECT_CONTACT:\n $this->client->getNewInstance()->crm()->contacts()->basicApi()->update($objectId, $payload);\n\n break;\n\n case FieldData::OBJECT_ACCOUNT:\n $this->client->getNewInstance()->crm()->companies()->basicApi()->update($objectId, $payload);\n\n break;\n\n case FieldData::OBJECT_TASK:\n // Endpoint for Engagements not ready\n $engagements = [\n 'type' => 'TASK',\n ];\n $metadata = $data;\n $this->client->getInstance()->engagements()->update($objectId, $engagements, $metadata);\n\n $this->logCrmEngagementManipulation(\n self::ACTION_UPDATE,\n ['crmId' => $objectId],\n $metadata,\n );\n\n break;\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n } catch (\\HubSpot\\Client\\Crm\\Deals\\ApiException $apiException) {\n $errorMessage = $apiException->getMessage();\n if ($apiException->getResponseBody()) {\n $responseBody = json_decode($apiException->getResponseBody(), true, 512, JSON_THROW_ON_ERROR);\n $errorMessage = $responseBody['message'] ?? $apiException->getMessage();\n }\n\n $this->logger->error(\n '[HubSpot] Update record failed',\n [\n 'objectType' => $objectType,\n 'objectId' => $objectId,\n 'payload' => $payload,\n 'reason' => $errorMessage,\n 'team' => $this->team->getUuid(),\n ]\n );\n\n throw new CrmException($errorMessage);\n }\n }\n\n /*\n * @inheritdoc\n */\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n return $this->client->getInstance()->deals()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_CONTACT:\n return $this->client->getInstance()->contacts()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_ACCOUNT:\n return $this->client->getInstance()->companies()->getById($objectId)->toArray();\n\n case FieldData::OBJECT_TASK:\n return $this->client->getInstance()->engagements()->get($objectId)->toArray();\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n }\n\n /**\n * @throws BadRequest\n * @throws CrmException\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n $payload = [\n 'properties' => [\n [\n 'name' => 'dealstage',\n 'value' => $stage->crm_provider_id,\n ],\n ],\n ];\n\n try {\n $this->client->getInstance()->deals()->update($crmObject->crm_provider_id, $payload);\n } catch (BadRequest $badRequest) {\n if ($badRequest->getCode() === 403) {\n throw new CrmException(\n \"Sorry, you don't have permission to update this stage.\",\n $badRequest->getCode(),\n $badRequest,\n );\n }\n\n $this->logger->warning('[HubSpot] Stage update failed', [\n 'dealId' => $crmObject->crm_provider_id,\n 'payload' => $payload,\n 'message' => $badRequest->getMessage(),\n ]);\n\n throw $badRequest;\n }\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $url = null;\n $baseUrl = 'https://app.hubspot.com/contacts/' . $this->config->crm_provider_id . '/';\n\n switch ($objectType) {\n case 'account':\n $url = $baseUrl . 'company/' . $providerId;\n\n break;\n\n case 'contact':\n $url = $baseUrl . 'contact/' . $providerId;\n\n break;\n\n case 'opportunity':\n $url = $baseUrl . 'deal/' . $providerId;\n\n break;\n\n case 'task':\n case 'activity':\n return null;\n\n // This should not be deep-linked as per JMNY-3934.\n //$url = $baseUrl.'tasks/list/view/all/?taskId='.$providerId;\n break;\n }\n\n return $url;\n }\n\n public function searchCalls(Carbon $from, Carbon $to, string $activityProvider): array\n {\n $this->logger->info('[HubSpot] Search calls', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n ]);\n\n $calls = [];\n $page = 1;\n\n do {\n try {\n $payload = $this->payloadBuilder->generateGetCallsPayload($from, $to, $activityProvider, $page);\n $response = $this->client->getInstance()->getClient()->request(\n 'POST',\n self::CALLS_SEARCH_ENDPOINT,\n ['json' => ($payload)],\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search calls failed', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n 'reason' => $exception->getMessage(),\n ]);\n $response = null;\n }\n\n $responseResults = empty($response['results']) ? [] : $response['results'];\n $calls = array_merge($calls, $responseResults);\n $page++;\n } while (! empty($responseResults));\n\n return $calls;\n }\n\n public function searchCallsForPeriodByPage(Carbon $from, Carbon $to, int $page, bool $retry = true)\n {\n try {\n $payload = $this->payloadBuilder->generateSearchCallsByPeriodPayload($from, $to, $page);\n $response = $this->client->getInstance()->getClient()->request(\n 'POST',\n self::CALLS_SEARCH_ENDPOINT,\n ['json' => ($payload)],\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search calls for period failed', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n 'reason' => $exception->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep(1);\n\n return $this->searchCallsForPeriodByPage($from, $to, $page, false);\n }\n $response = null;\n }\n\n return $response;\n }\n\n public function searchCallsForPeriod(Carbon $from, Carbon $to): Generator\n {\n $this->logger->info('[HubSpot] Search calls for period', [\n 'from' => $from->format(self::LOG_DATE_FORMAT),\n 'to' => $to->format(self::LOG_DATE_FORMAT),\n ]);\n\n $page = 1;\n\n do {\n $response = $this->searchCallsForPeriodByPage($from, $to, $page);\n\n $responseResults = empty($response['results']) ? [] : $response['results'];\n\n $associationContacts = $this->getAssociationDataForCollection($responseResults, 'calls', 'contacts');\n $associationCompanies = $this->getAssociationDataForCollection($responseResults, 'calls', 'companies');\n $associationDeals = $this->getAssociationDataForCollection($responseResults, 'calls', 'deals');\n\n foreach ($responseResults as $call) {\n $call['associations'] = [\n 'contacts' => $this->importAssociationData($call, $associationContacts),\n 'companies' => $this->importAssociationData($call, $associationCompanies),\n 'deals' => $this->importAssociationData($call, $associationDeals),\n ];\n\n yield $call;\n }\n $page++;\n } while (! empty($responseResults));\n }\n\n public function getCall(string $callId): array\n {\n $this->logger->info('[HubSpot] Get call', [\n 'call_id' => $callId,\n ]);\n\n $searchAttributes = $this->payloadBuilder->getSearchCallAttributes();\n $endpoint = sprintf(\n 'https://api.hubapi.com/crm/v3/objects/calls/%s',\n $callId,\n );\n\n try {\n $response = $this->client->getInstance()->getClient()->request(\n 'GET',\n $endpoint,\n [],\n sprintf(\n 'properties=%s&associations=contacts,companies,deals',\n implode(',', $searchAttributes),\n ),\n );\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Get call failed', [\n 'call_id' => $callId,\n 'reason' => $exception->getMessage(),\n ]);\n $response = null;\n }\n\n return empty($response) ? [] : $response->toArray();\n }\n\n public function bulkAddPlaybackURLToDescription(array $crmUpdateData): array\n {\n $crmUpdateBatches = array_chunk($crmUpdateData, self::BATCH_UPDATE_LIMIT);\n\n $updatedCrmIds = [];\n\n foreach ($crmUpdateBatches as $crmBatch) {\n $payload = $this->payloadBuilder->generatePlaybackAddUrlBatchPayload($crmBatch);\n $updateSuccess = $this->bulkAddPlaybackURLToDescriptionRequest($payload);\n if ($updateSuccess) {\n $updatedCrmIds = array_merge($updatedCrmIds, array_column($crmBatch, 'crm_id'));\n }\n }\n\n return $updatedCrmIds;\n }\n\n private function bulkAddPlaybackURLToDescriptionRequest(array $payload, bool $retry = true): bool\n {\n try {\n $this->client->getNewInstance()->crm()->objects()->batchApi()->update('calls', $payload);\n\n return true;\n } catch (\\HubSpot\\Client\\Crm\\Objects\\ApiException $e) {\n $response = json_decode($e->getResponseBody(), true);\n $retryAfter =\n isset($response['policyName'])\n && $response['policyName'] == self::TEN_SECONDLY_ROLLING_POLICY\n ? self::TEN_SECONDLY_ROLLING_LIMIT\n : 1;\n } catch (Exception $e) {\n $retryAfter = 1;\n }\n\n $this->logger->warning('[HubSpot] Bulk add playback url to CRM failed', [\n 'reason' => $e->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep($retryAfter);\n\n return $this->bulkAddPlaybackURLToDescriptionRequest($payload, false);\n }\n\n return false;\n }\n\n /**\n * Sometimes we have secondly rate limit error, then retry request after 1 second\n */\n public function searchCallByRecordingURLToken(string $playbackURLToken, bool $retry = true): array\n {\n $endpoint = 'https://api.hubapi.com/crm/v3/objects/calls/search';\n $payload = $this->payloadBuilder->generateSearchCallByTokenPayload($playbackURLToken);\n\n $this->logger->info('[HubSpot] CRM Search by playback URL token requested', [\n 'request' => $payload,\n ]);\n\n try {\n $response = $this->client->getInstance()->getClient()->request('POST', $endpoint, ['json' => ($payload)]);\n } catch (Exception $exception) {\n $this->logger->info('[HubSpot] Search by playback URL token failed', [\n 'playbackURLToken' => $playbackURLToken,\n 'reason' => $exception->getMessage(),\n 'retry' => $retry,\n ]);\n\n if ($retry) {\n sleep(1);\n\n return $this->searchCallByRecordingURLToken($playbackURLToken, false);\n }\n\n return [];\n }\n\n return empty($response['results']) ? [] : $response['results'][0];\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! $this->config->store_transcript) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n $transcriptionSegments = $this->transcriptionService->findTranscriptionByActivity($activity);\n\n if ($transcriptionSegments->isEmpty()) {\n return '';\n }\n\n $transcription = sprintf(\n '<p><strong>Transcript for %s</strong></p><p></p>',\n $activity->title ?? $activity->activity_title,\n );\n\n $roomOwnerParticipant = $activity->findParticipantRoomOwner();\n $roomOwnerParticipantId = $roomOwnerParticipant !== null\n ? $roomOwnerParticipant->getId()\n : null;\n\n\n $transcription .= $transcriptionSegments\n ->map(static function (array $transcriptionSegment) use ($roomOwnerParticipantId): string {\n $isOrganiser = $roomOwnerParticipantId === $transcriptionSegment['participantId']\n && $roomOwnerParticipantId !== null;\n $transcriptColor = $isOrganiser ? '#000000' : '#f0415a';\n\n return sprintf(\n '<span style=\"color: %s;\">%s | </span>%s',\n $transcriptColor,\n $transcriptionSegment['formattedStartsAt'],\n $transcriptionSegment['transcript'],\n );\n })\n ->implode('<br />');\n\n return $transcription;\n }\n\n /**\n * @param array<array{\n * id: string,\n * label: string,\n * value?: string,\n * }> $options\n *\n * @return FieldData[]\n */\n private function importOptions(Field $field, array $options): array\n {\n $fieldValues = [];\n $values = [];\n $sequence = 0;\n\n foreach ($options as $option) {\n $values[] = [\n 'value' => $option['value'] ?? $option['id'],\n 'label' => substr($option['label'], 0, 255),\n 'sequence' => $sequence++,\n ];\n }\n\n $fieldsToPurge = $field->values()->get()->pluck('value')->toArray();\n\n foreach ($values as $value) {\n $value['value'] = substr($value['value'], 0, 255);\n $fieldValues[] = $field->values()->updateOrCreate([\n 'value' => $value['value'],\n ], $value);\n\n // Remove this value from the ones we are going to purge.\n if (($key = array_search($value['value'], $fieldsToPurge, false)) !== false) {\n unset($fieldsToPurge[$key]);\n }\n }\n\n // Delete the old values that are no longer used.\n $field->values()->whereIn('value', $fieldsToPurge)->delete();\n\n return $fieldValues;\n }\n\n public function saveTranscriptionSummaryAsNote(\n ActivityContract $activity,\n string $title,\n string $body,\n ?string $objectId,\n ?NoteObject $noteObject = null,\n ): ?string {\n if ($noteObject === null || $objectId === null) {\n return null;\n }\n\n /** @var User $user */\n $user = $activity->getUser();\n\n $profile = $this->assignCrmOwner($user, $activity);\n if (! $profile instanceof Profile) {\n return null;\n }\n\n $timestamp = Carbon::now($user->getTimezone())->getTimestamp() * 1000;\n $engagement = [\n 'active' => true,\n 'ownerId' => $profile->getAttribute('crm_provider_id'),\n 'timestamp' => $timestamp,\n 'type' => 'NOTE',\n ];\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $body = mb_strimwidth($body, 0, self::ENGAGEMENT_BODY_MAX_LENGTH);\n $metadata = [\n 'body' => $body,\n ];\n\n $associations = $this->convertActivityAssociations($activity);\n\n try {\n $hsActivityId = $this->client->createNote(\n body: $body,\n ownerId: $profile->getCrmProviderId(),\n timestamp: $timestamp,\n objectId: $objectId,\n noteObject: $noteObject,\n );\n\n $this->logCrmEngagementManipulation(self::ACTION_CREATE, $engagement, $metadata, $associations);\n\n $this->logger->info('[HubSpot] Saving Transcription Summary as Note', [\n 'activity' => $activity->getUuid(),\n 'crmActivity' => $hsActivityId,\n ]);\n\n return $hsActivityId;\n } catch (Exception $e) {\n Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function attachSummaryToActivity(ActivityContract $activity, string $summaryTitle, string $summaryContents): bool\n {\n $this->logger->info('[HubSpot] Attaching summary to activity', [\n 'activity' => $activity->getUuid(),\n 'summary_content' => $summaryContents,\n ]);\n\n if (! $activity instanceof Activity) {\n throw new InvalidArgumentException('Expected instance of Activity');\n }\n\n $summary = '<p><strong>' . $summaryTitle . '</strong></p>';\n $summary .= '<p>' . $summaryContents . '</p>';\n $metadata = $this->buildMetadataForSummaryUpdate($activity, $summary);\n\n try {\n $type = $this->matchActivityEngagementType($activity);\n $engagement = ['type' => $type];\n\n $this->client->updateEngagement($activity->getCrmProviderId(), $engagement, $metadata);\n } catch (Exception $e) {\n $this->logger->warning('[HubSpot] Update summary failed', [\n 'activity' => $activity->getUuid(),\n 'reason' => $e->getMessage(),\n ]);\n\n return false;\n }\n\n $this->logCrmEngagementManipulation(\n self::ACTION_UPDATE,\n ['crmId' => $activity->getCrmProviderId()],\n $metadata,\n );\n\n return true;\n }\n\n private function buildMetadataForSummaryUpdate(Activity $activity, string $summary): array\n {\n $descriptionField = $activity->getType() === Activity::TYPE_CONFERENCE ? 'internalMeetingNotes' : 'body';\n $engagement = $this->client->getEngagementData($activity->getCrmProviderId());\n // Meeting without internalMeetingNotes might mean it just does not have any notes;\n $description = $engagement['metadata'][$descriptionField] ?? null;\n\n if (empty($description)) {\n $data = $summary;\n } else {\n // avoid playbook url link to Jiminny being sent twice in the activity description\n $targetUrl = PlaybackUrlBuilder::build($activity);\n\n if (str_contains($description, $targetUrl)) {\n $jiminnyUrl = '<p><a href=\"' . $targetUrl . '\" title=\"Play at Jiminny\">Play at Jiminny</a></p>';\n $summary = str_replace($jiminnyUrl, '', $summary);\n\n $this->logger->info('[HubSpot] Summary modified', [\n 'activity' => $activity->getUuid(),\n 'target_url' => $jiminnyUrl,\n 'modified_summary_content' => $summary,\n ]);\n }\n\n $data = $description . '<p></p>' . $summary;\n }\n\n return [\n $descriptionField => $data,\n ];\n }\n\n public function fetchAndAssociateRelatedActivity(Activity $activity): ?Activity\n {\n return $this->syncRelatedActivityManager->fetchAndAssociateRelatedActivity($activity);\n }\n\n public function fetchRelatedActivity(Activity $activity): array\n {\n return [];\n }\n\n public function getDealsInBulk(array $dealIds): array\n {\n $payload = $this->payloadBuilder->getDealsInBulkPayload($dealIds);\n\n return $this->client->getPaginatedData($payload, 'deals');\n }\n\n /**\n * Extract deal IDs from HubSpot search response.\n *\n * @param array $hubspotResponse The raw HubSpot search API response.\n * @param bool $includeArchived Whether to include archived deals (default: false).\n *\n * @return string[] Array of deal IDs as strings.\n */\n public function extractDealIds(array $hubspotResponse, bool $includeArchived = false): array\n {\n if (empty($hubspotResponse['results'])) {\n return [];\n }\n\n return array_values(\n array_map(\n fn ($deal) => $deal['id'],\n array_filter(\n $hubspotResponse['results'],\n fn ($deal) => $includeArchived || empty($deal['archived'])\n )\n )\n );\n }\n\n public function matchActivityEngagementType(Activity $activity): string\n {\n return match ($activity->getType()) {\n Activity::TYPE_CONFERENCE => self::TYPE_MEETING,\n Activity::TYPE_SOFTPHONE, Activity::TYPE_SOFTPHONE_INBOUND => self::TYPE_CALL,\n default => self::TYPE_NOTE,\n };\n }\n\n private function assignCrmOwner(User $user, ActivityContract $activity): ?Profile\n {\n $profile = $user->getProfile();\n if ($profile instanceof Profile) {\n return $profile;\n }\n\n $this->logger->info('[HubSpot] Unable to save summary. No profile', [\n 'activity' => $activity->getUuid(),\n ]);\n\n return null;\n }\n\n private static function getDealsPipelinesEndpoint(): string\n {\n return self::API_URL . self::ENDPOINT_PIPELINES . self::PIPELINE_OBJECT_TYPE_DEALS;\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n $engagement = $this->client->getEngagementData($crmProviderId);\n\n return ! empty($engagement);\n } catch (HttpNotFoundException|BadRequest) {\n // Engagement not found in CRM - this is expected and permanent\n $this->logger->info('[Hubspot] Engagement not found during verification', [\n 'engagement_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\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":"AXStaticText","text":"2","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\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\EmailHelper;\nuse Throwable;\n\nclass FixActivitiesOpportunity extends Command\n{\n protected $signature = 'activity:fix-opportunity {--from=} {--to=}';\n\n public function handle(EmailHelper $emailHelper): int\n {\n $from = $this->option('from');\n $to = $this->option('to');\n\n $validator = Validator::make(\n ['from' => $from, 'to' => $to],\n [\n 'from' => ['required', 'date'],\n 'to' => ['required', 'date'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return Command::FAILURE;\n }\n\n $this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);\n\n $activityIds = Activity::select('activities.id')\n ->whereBetween('activities.created_at', [$from, $to])\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')\n ->whereColumn('opportunities.team_id', '<>', 'users.team_id')\n ->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n\n foreach ($activityIds as $activityId) {\n $activity = Activity::where('id', $activityId)\n ->with(['user', 'participants'])\n ->first();\n\n $crmService = $this->getCrmService($activity->getTeam());\n if ($crmService === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $this->processParticipants($crmService, $emailHelper, $activity);\n }\n\n return Command::SUCCESS;\n }\n\n private function getCrmService(Team $team): ?ServiceInterface\n {\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n try {\n return $crmResolver->prepareCrmService();\n } catch (Throwable $e) {\n $this->error('Could not prepare CRM service: ' . $e->getMessage());\n\n return null;\n }\n }\n\n private function processParticipants(\n ServiceInterface $crmService,\n EmailHelper $emailHelper,\n Activity $activity\n ): void {\n $team = $activity->getTeam();\n $user = $activity->getUser();\n $participants = $activity->getParticipants();\n\n foreach ($participants as $participant) {\n if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {\n continue;\n }\n\n $emailAddress = $participant->getEmailAddress();\n if ($emailHelper->isCompanyEmail($team, $emailAddress)) {\n continue;\n }\n\n try {\n $opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());\n } catch (Throwable $e) {\n $this->error('Could not find opportunity: ' . $e->getMessage());\n\n $opportunity = null;\n }\n\n if ($opportunity === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $activity->update(['opportunity_id' => $opportunity->getId()]);\n\n $this->info('Opportunity updated for activity: ' . $activity->getId());\n }\n }\n\n private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity\n {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n $match = $decorator->matchExactlyByEmail($emailAddress, $userId);\n\n if (empty($match)) {\n $match = $decorator->matchByDomain($emailAddress, $userId);\n }\n\n if (empty($match)) {\n return null;\n }\n\n [, , $opportunity, ,] = $match;\n\n return $opportunity;\n }\n\n private function resetActivityOpportunity(Activity $activity): void\n {\n $this->info('Reset opportunity for activity: ' . $activity->getId());\n $activity->update(['opportunity_id' => null]);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\EmailHelper;\nuse Throwable;\n\nclass FixActivitiesOpportunity extends Command\n{\n protected $signature = 'activity:fix-opportunity {--from=} {--to=}';\n\n public function handle(EmailHelper $emailHelper): int\n {\n $from = $this->option('from');\n $to = $this->option('to');\n\n $validator = Validator::make(\n ['from' => $from, 'to' => $to],\n [\n 'from' => ['required', 'date'],\n 'to' => ['required', 'date'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return Command::FAILURE;\n }\n\n $this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);\n\n $activityIds = Activity::select('activities.id')\n ->whereBetween('activities.created_at', [$from, $to])\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')\n ->whereColumn('opportunities.team_id', '<>', 'users.team_id')\n ->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n\n foreach ($activityIds as $activityId) {\n $activity = Activity::where('id', $activityId)\n ->with(['user', 'participants'])\n ->first();\n\n $crmService = $this->getCrmService($activity->getTeam());\n if ($crmService === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $this->processParticipants($crmService, $emailHelper, $activity);\n }\n\n return Command::SUCCESS;\n }\n\n private function getCrmService(Team $team): ?ServiceInterface\n {\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n try {\n return $crmResolver->prepareCrmService();\n } catch (Throwable $e) {\n $this->error('Could not prepare CRM service: ' . $e->getMessage());\n\n return null;\n }\n }\n\n private function processParticipants(\n ServiceInterface $crmService,\n EmailHelper $emailHelper,\n Activity $activity\n ): void {\n $team = $activity->getTeam();\n $user = $activity->getUser();\n $participants = $activity->getParticipants();\n\n foreach ($participants as $participant) {\n if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {\n continue;\n }\n\n $emailAddress = $participant->getEmailAddress();\n if ($emailHelper->isCompanyEmail($team, $emailAddress)) {\n continue;\n }\n\n try {\n $opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());\n } catch (Throwable $e) {\n $this->error('Could not find opportunity: ' . $e->getMessage());\n\n $opportunity = null;\n }\n\n if ($opportunity === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $activity->update(['opportunity_id' => $opportunity->getId()]);\n\n $this->info('Opportunity updated for activity: ' . $activity->getId());\n }\n }\n\n private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity\n {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n $match = $decorator->matchExactlyByEmail($emailAddress, $userId);\n\n if (empty($match)) {\n $match = $decorator->matchByDomain($emailAddress, $userId);\n }\n\n if (empty($match)) {\n return null;\n }\n\n [, , $opportunity, ,] = $match;\n\n return $opportunity;\n }\n\n private function resetActivityOpportunity(Activity $activity): void\n {\n $this->info('Reset opportunity for activity: ' . $activity->getId());\n $activity->update(['opportunity_id' => null]);\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}]...
|
285020041200234445
|
-537472495523850137
|
click
|
accessibility
|
NULL
|
1 file committed
JY-20903 revert changes in comman 1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
7
51
1
33
1
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Hubspot;
use Carbon\Carbon;
use Exception;
use Generator;
use GuzzleHttp\Exception\RequestException;
use HubSpot\Client\Crm\Owners\Model\PublicOwner;
use Illuminate\Support\Facades\Cache;
use InvalidArgumentException;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Contracts\Services\Crm\ClientInterface;
use Jiminny\Contracts\Services\Crm\FetchRelatedActivityInterface;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\HubspotInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SavePlaybackLinkToCrmInterface;
use Jiminny\Contracts\Services\Crm\SendSummaryToCrmInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Contracts\ActivityContract;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\Layout;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Participant;
use Jiminny\Models\Playbook;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Repositories\ParticipantRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Hubspot\Actions\SyncArchivedProfilesAction;
use Jiminny\Services\Crm\Hubspot\Fields\ValueNormalizer;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\OpportunitySyncTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncCrmEntitiesTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\SyncFieldsTrait;
use Jiminny\Services\Crm\Hubspot\ServiceTraits\WriteCrmTrait;
use Jiminny\Services\Crm\MatchDomainByEmailInterface;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\ResolveCompanyNameByEmailTrait;
use Jiminny\Utils\PlaybackUrlBuilder;
use Sentry;
use SevenShores\Hubspot\Exceptions\BadRequest;
use Throwable;
use UnexpectedValueException;
/**
* @phpstan-type CrmFieldDefinition array{
* name: string,
* label: string,
* description: string,
* type: string,
* fieldType: string,
* hidden: bool,
* showCurrencySymbol: bool,
* options: array<array{
* id: string,
* label: string,
* value?: string,
* }
*/
class Service extends BaseService implements
HubspotInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
SendSummaryToCrmInterface,
MatchDomainByEmailInterface,
SavePlaybackLinkToCrmInterface,
RemoteEntityManipulationInterface,
FetchRelatedActivityInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use ResolveCompanyNameByEmailTrait;
use SyncCrmEntitiesTrait;
use WriteCrmTrait;
use SyncFieldsTrait;
use OpportunitySyncTrait;
private const int ENGAGEMENT_BODY_MAX_LENGTH = 65536;
private const string LOG_DATE_FORMAT = 'Y-m-d H:i:s';
private const int BATCH_UPDATE_LIMIT = 100;
private const string TEN_SECONDLY_ROLLING_POLICY = 'TEN_SECONDLY_ROLLING';
private const int TEN_SECONDLY_ROLLING_LIMIT = 10;
private const string CALLS_SEARCH_ENDPOINT = '[URL_WITH_CREDENTIALS] ClientInterface|Client
*/
protected $client;
protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;
protected CrmEntityRepository $crmEntityRepository;
protected ProspectPhotoPathService $prospectPhotoPathService;
private SyncFieldAction $syncFieldAction;
private PayloadBuilder $payloadBuilder;
private SyncRelatedActivityManager $syncRelatedActivityManager;
private SyncArchivedProfilesAction $syncArchivedProfilesAction;
private WebhookSyncBatchProcessor $batchProcessor;
public function __construct(
Client $client,
SyncFieldAction $syncFieldAction,
PayloadBuilder $payloadBuilder,
ProspectPhotoPathService $prospectPhotoPathService,
SyncArchivedProfilesAction $syncArchivedProfilesAction,
WebhookSyncBatchProcessor $batchProcessor,
) {
parent::__construct();
$this->client = $client;
$this->syncFieldAction = $syncFieldAction;
$this->prospectPhotoPathService = $prospectPhotoPathService;
$this->payloadBuilder = $payloadBuilder;
$this->syncArchivedProfilesAction = $syncArchivedProfilesAction;
$this->batchProcessor = $batchProcessor;
$this->opportunitySyncStrategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->client,
]);
$this->syncRelatedActivityManager = app(SyncRelatedActivityManager::class, [
'client' => $this->client,
'payloadBuilder' => $this->payloadBuilder,
'logger' => $this->logger,
]);
$this->crmEntityRepository = app(CrmEntityRepository::class);
$this->dealFieldsService = app(DealFieldsService::class);
}
public function getDisplayName(): string
{
return 'HubSpot';
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
$owner = $user->team->owner;
return $owner->getSocialAccount(SocialAccount::PROVIDER_HUBSPOT);
}
public function getClient(): Client
{
/** @var Client */
return $this->client;
}
/**
* Convert raw field data into a format compatible with CRM APIs.
*
* @param bool $internal Direction of the conversion.
* True is pulling from CRM, false normalize before sending to CRM.
*/
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return ValueNormalizer::normalize(
fieldType: $fieldType,
fieldValue: $fieldValue,
isInbound: $internal,
);
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
/** @var Field $activityField */
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'activityType',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
/**
* @inheritdoc
*/
public function getDefaultActivityLayoutFields(string $activityType, string $layoutType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
// Outcome should always be provided calls/meetings.
$fieldData = [
[
'crm_provider_id' => $layoutType === Layout::TYPE_SOFTPHONE_SUMMARY ? 'disposition' : 'meetingOutcome',
'object_type' => Field::OBJECT_TASK,
],
];
foreach ($fieldData as $data) {
$field = $this->config->fields()->where($data)->first();
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
}
return $fields;
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldData = FieldDefinitions::followupFieldsFilter();
foreach ($fieldData as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function syncField(Field $field): void
{
switch ($field->object_type) {
case Field::OBJECT_ACCOUNT:
$crmField = $this->client->getInstance()->companyProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_CONTACT:
$crmField = $this->client->getInstance()->contactProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_OPPORTUNITY:
$crmField = $this->client->getInstance()->dealProperties()->get($field->crm_provider_id);
break;
case Field::OBJECT_TASK:
$this->syncSingleTaskField($field);
return;
default:
return;
}
$this->syncFieldAction->execute($field, $crmField->toArray());
}
/**
* @param array<array{
* id:string,
* label:string,
* value?:string
* }> $options
*
* @throws CrmException
*
* @return FieldData[]
*
*/
public function importPicklistValues(
Field $field,
array $options = [['id' => '', 'label' => '', 'value' => '']],
): array {
if (! empty($options[0]['id']) || ! empty($options[0]['value'])) {
// We already have the options, no need to fetch them again
return $this->importOptions($field, $options);
}
$options = [];
switch ($field->getObjectType()) {
case Field::OBJECT_ACCOUNT:
$options = $this->getClient()->fetchPropertyOptions('company', $field->getCrmProviderId());
break;
case Field::OBJECT_CONTACT:
$options = $this->getClient()->fetchPropertyOptions('contact', $field->getCrmProviderId());
break;
case Field::OBJECT_OPPORTUNITY:
// Hubspot has different endpoint for stages
$options = $this->getClient()->fetchOpportunityFieldOptions($field);
break;
case Field::OBJECT_TASK:
if ($field->getCrmProviderId() === 'disposition') {
$options = $this->getClient()->fetchDispositionFieldOptions();
} elseif (in_array($field->getCrmProviderId(), ['meetingOutcome', 'activityType'])) {
$options = $this->getClient()->fetchMeetingOutcomeFieldOptions($field);
}
break;
default:
$this->logger->warning('Invalid object type', [
'object_type' => $field->getObjectType(),
'field_id' => $field->getId(),
]);
throw new CrmException('Invalid object type');
}
return $this->importOptions($field, $options);
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
$missingStage = null;
try {
// Use the HubSpot API client instead of the SDK crmPipelines() method
$endpoint = self::getDealsPipelinesEndpoint();
$pipelinesResponse = $this->client->getInstance()->getClient()->request('GET', $endpoint);
$pipelines = $pipelinesResponse->data->results;
} catch (RequestException|BadRequest $exception) {
throw $exception;
}
foreach ($pipelines as $pipeline) {
$stages = [];
// We create a business process to contain the pipeline, and store all stages against it.
$p = ResponseNormalize::normalizePipeline($pipeline);
// Create/update business process for this pipeline
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => $p['active'],
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
// Create/update record type clone
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $p['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($p['label'], 0, 150),
'is_selectable' => $p['active'],
'business_process_id' => $businessProcess->id ?? null,
]);
// Stages - fetch all existing stages upfront to avoid N+1 queries
$existingStages = $this->config->stages()
->withTrashed()
->where('type', Stage::TYPE_OPPORTUNITY)
->get()
->keyBy('crm_provider_id');
foreach ($p['stages'] as $dealStage) {
$s = ResponseNormalize::normalizeDealStage($dealStage);
/** @var ?Stage $existingStage */
$existingStage = $existingStages->get($s['id']);
// Restore soft-deleted stages that are now active in HubSpot
if ($existingStage?->trashed() && $s['active']) {
$existingStage->restore();
}
// Upsert stage (updates soft-deleted records without restoring them)
$stage = $this->config->stages()->withTrashed()->updateOrCreate([
'crm_provider_id' => $s['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($s['label'], 0, 50),
'label' => mb_strimwidth($s['label'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $s['displayOrder'],
'is_selectable' => $s['active'],
'probability' => $s['probability'] * 100,
]);
if ($missingStageName === $s['id']) {
$missingStage = $stage;
}
$stages[] = $stage->id;
}
$businessProcess->stages()->sync($stages);
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
try {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
/** @var array<int, array<string, mixed>> */
return Cache::remember(
key: $this->team->getId() . $name . $count . $offset,
ttl: 300,
callback: function () use ($name, $offset, $count): array {
$data = [];
// Use the new V3 API to find contacts based on additional fields.
foreach (['companies', 'contacts'] as $objectType) {
$endpoint = '[URL_WITH_CREDENTIALS]
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
if ($crmAccountId === null) {
return $data;
}
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
$closedStages = $this->getClosedDealStages();
$payload = $this->payloadBuilder->generateOpportunitiesSearchPayload(
$this->config,
$crmAccountId,
$closedStages,
);
$results = $this->client->getPaginatedData($payload, 'deals');
foreach ($results['results'] as $object) {
$properties = $object['properties'];
$amount = null;
if (empty($properties['amount']) === false) {
$currency = $properties['deal_currency_code'] ?? $this->config->default_currency;
// Values can contain commas and any junk so strip them.
$value = (float) preg_replace('/[^\d.]/', '', $properties['amount']);
$amount = formatCurrency($value, $currency);
}
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
if ($businessProcess === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $properties['dealstage']);
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', $properties['pipeline'])
->first();
} else {
$stage = $businessProcess
->stages()
->where('crm_provider_id', $properties['dealstage'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages(null, $properties['dealstage']);
}
}
$recordType = null;
if ($businessProcess) {
$recordType = $businessProcess->recordTypes()->first();
}
$isWon = in_array($properties['dealstage'], $closedStages['won']);
$isLost = in_array($properties['dealstage'], $closedStages['lost']);
$record = [
'crmId' => $object['id'],
'name' => $properties['dealname'] ?? 'Unknown Deal',
'value' => $amount,
'won' => $isWon,
'closed' => $isWon || $isLost,
'stage' => [
'id' => $stage?->getUuid() ?? '',
'name' => $stage?->getName() ?? '',
],
];
if ($recordType) {
$record += [
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
}
if ($ownerId && isset($properties['hubspot_owner_id']) && $properties['hubspot_owner_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
if (! empty($ownerData)) {
return $ownerData;
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(?string $objectType, string $objectId, ?string $opportunityId): array
{
$data = [];
switch ($objectType) {
case 'contact':
$hsObject = 'contact';
break;
case 'account':
$hsObject = 'company';
break;
default:
// This is a hack to prioritise and override a contact/company with a deal.
if ($opportunityId) {
$hsObject = 'deal';
$objectId = $opportunityId;
} else {
throw new InvalidArgumentException('Object type not supported.');
}
}
$engagementTypes = ['meetings', 'tasks'];
foreach ($engagementTypes as $engagementType) {
$payload = $this->payloadBuilder->getLinkToTaskPayload($hsObject, $objectId, $engagementType);
$this->logger->info('[HubSpot] CRM Search requested', [
'request' => $payload,
]);
$engagements = $this->client->getPaginatedData($payload, $engagementType);
foreach ($engagements['results'] as $engagement) {
if ($engagementType == 'meetings') {
$title = $engagement['properties']['hs_meeting_title'] ?? 'Scheduled meeting';
} elseif ($engagementType == 'tasks') {
$title = $engagement['properties']['hs_task_subject'];
} else {
$title = 'Scheduled meeting';
}
$data[] = [
'crmId' => $engagement['id'],
'subject' => $title,
'due' => $engagement['properties']['hs_timestamp'],
'type' => $engagement['properties']['hs_activity_type'] ?? null,
];
}
}
usort($data, function ($item1, $item2) {
return $item2['due'] <=> $item1['due'];
});
return $data;
}
/**
* Try to find CRM Objects using email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$contactProperties = [
'email',
'firstname',
'lastname',
'country',
'phone',
'mobilephone',
'jobtitle',
'hubspot_owner_id',
'associatedcompanyid',
'photo',
];
$contact = null;
$account = null;
try {
$hsContact = $this->getClient()->getContactByEmail($email, $contactProperties);
if ($hsContact) {
$contact = $this->importContact($hsContact);
$account = $contact->account;
}
$data = $this->convertCrmData($contact, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
} catch (BadRequest $e) {
$this->logger->warning('[HubSpot] Search failed', [
'team_id' => $this->team->getId(),
'search_identifier' => $email,
'reason' => $e->getMessage(),
]);
}
return null;
}
public function getDomain(string $email): ?string
{
return $this->getDomainFromEmail($email);
}
/**
* Try to find CRM objects using domain name of the email address
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByDomain(string $domain, ?int $userId = null): ?array
{
$companyName = $domain;
// Try to find a company matching their email domain.
$companyProperties = [
'country',
'phone',
'name',
'hs_avatar_filemanager_key',
'industry',
'hubspot_owner_id',
'domain',
];
try {
$hsAccounts = $this->client
->getInstance()
->companies()
->searchByDomain($companyName, $companyProperties);
} catch (Throwable $e) {
$this->logger->info('[HubSpot] Search failed', [
'error' => $e->getMessage(),
'domain' => $domain,
]);
return null;
}
$account = null;
// If there are multiple accounts, don't guess, we'll ask later.
if (\count($hsAccounts->data->results) === 1) {
// Persist this remote object.
$account = $this->syncAccount($hsAccounts->data->results[0]->companyId);
}
$data = $this->convertCrmData(null, $account, $userId);
return ! empty(array_filter($data)) ? $data : null;
}
/**
* @return array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
protected function convertCrmData(?Contact $contact, ?Account $account, ?int $userId = null): array
{
$countryCode = null;
if ($contact && $contact->country_code) {
$countryCode = $contact->country_code;
} elseif ($account && $account->country_code) {
$countryCode = $account->country_code;
}
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact ? $contact->crm_provider_id : null,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
// If there are multiple opportunities, don't guess, we'll ask later.
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
protected function getCacheKey(string $object, ?int $userId = null): ?string
{
$key = $this->team->getId() . $object;
$keySuffix = $this->getOwnerKeySuffix($userId);
return $key . $keySuffix;
}
private function getOwnerKeySuffix(?int $userId = null): string
{
return $userId === null ? '' : (string) $userId;
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array
{
if (str_contains($phone, '**')) {
return null;
}
// trim all whitespaces if present so the lookup doesn't fail
$phone = str_replace(' ', '', $phone);
// Check if the user is internal.
if ($this->isPhoneNumberOfTeamMember($phone)) {
return null;
}
$response = $this->searchForPhoneNumber($phone);
if (empty($response)) {
return null;
}
// This would ideally importContact instead but the response type differs.
$contact = $this->findAndSyncContact($response['results'][0]['id']);
if (! $contact instanceof Contact) {
return null;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account?->crm_provider_id,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
try {
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
} catch (Exception $e) {
$this->logger->debug('[HubSpot] Opportunity failed to sync.', [
'reason' => $e->getMessage(),
]);
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
private function isPhoneNumberOfTeamMember(string $phone): bool
{
$teamRepository = app(TeamRepository::class);
$user = $teamRepository->findTeamMemberByPhone($this->team, $phone);
if ($user instanceof User) {
return true;
}
return false;
}
private function findAndSyncContact(string $crmId): ?Contact
{
try {
return $this->syncContact($crmId);
} catch (Exception $exception) {
$this->logger->info('[HubSpot] Phone match failed', [
'reason' => $exception->getMessage(),
]);
return null;
}
}
private function hasResults(array $response): bool
{
return isset($response['total']) && is_numeric($response['total']) && $response['total'] > 0;
}
private function searchForPhoneNumber(string $phone): array
{
// Normalizes the provided phone number for the API search.
$normalizedPhone = $this->normalizePhoneNumber($phone);
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone);
$this->logger->info('[HubSpot] Phone match search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($normalizedPhone, $payload);
if (! $this->hasResults($response)) {
$nationalPhone = preg_replace('/\D/', '', phone_national(null, $phone));
$payload = $this->payloadBuilder->generatePhoneSearchPayload($nationalPhone);
$this->logger->info('[HubSpot] Phone match national number search triggered', [
'phone' => $phone,
'nationalPhone' => $nationalPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
if (! $this->hasResults($response)) {
$payload = $this->payloadBuilder->generatePhoneSearchPayload($normalizedPhone, true);
$this->logger->info('[HubSpot] Phone match alternative search triggered', [
'phone' => $phone,
'normalizedPhone' => $normalizedPhone,
'payload' => $payload,
]);
$response = $this->handlePhoneSearchRequest($phone, $payload);
}
return $this->hasResults($response) ? $response : [];
}
private function handlePhoneSearchRequest(string $phone, array $payload): array
{
$endpoint = '[URL_WITH_CREDENTIALS] null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByName(string $name, ?int $userId = null): ?array
{
// Don't waste time searching for single character strings.
if (\strlen($name) <= 1) {
return null;
}
$cacheKey = $this->getCacheKey($name, $userId);
$result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {
$payload = $this->payloadBuilder->generateSearchContactsByNamePayload(
$name,
$this->getContactFields()
);
$hsContacts = $this->client->getPaginatedData($payload, 'contact');
if (empty($hsContacts['results'])) {
return false;
}
$contact = $this->importContact($hsContacts['results'][0]);
if ($contact === null) {
return false;
}
$account = $contact->account;
$countryCode = $contact->country_code ?? $account->country_code ?? null;
try {
$hsOpportunities = $this->findOpportunities(
$account ? $account->crm_provider_id : null,
$contact->crm_provider_id,
$userId
);
} catch (Exception $e) {
$hsOpportunities = [];
}
$opportunity = null;
$stage = null;
if (! empty($hsOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($hsOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
return [
null,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
});
return is_array($result) ? $result : null;
}
private function convertActivityAssociations(Activity $activity): array
{
return [
'contactIds' => $this->getParticipantsIds($activity),
'companyIds' => $activity->hasAccount() ? [$activity->account->crm_provider_id] : [],
'dealIds' => $activity->hasOpportunity() ? [$activity->opportunity->crm_provider_id] : [],
'ownerIds' => [],
];
}
private function getParticipantsIds(Activity $activity): array
{
$attendees = [];
$participantRepository = app(ParticipantRepository::class);
$participants = $participantRepository->getParticipantsWhoEnteredMeeting($activity);
foreach ($participants as $participant) {
if ($participant->user_id || $participant->isCoach()) {
continue;
}
$contact = $participant->contact()->first();
if ($contact && $contact->crm_provider_id) {
$attendees[] = $contact->crm_provider_id;
} else {
if (! empty($participant->name)) {
$attendeeData = $this->fetchMissingAttendeeInfo($participant);
}
if (! empty($attendeeData['id'])) {
$attendees[] = $attendeeData['id'];
}
}
}
if ($activity->hasContact()) {
$attendees[] = $activity->contact->crm_provider_id;
}
return array_unique($attendees);
}
private function fetchMissingAttendeeInfo(Participant $participant): array
{
// Check if we need to look inside an account context.
$activity = $participant->getActivity();
$companyId = $activity->hasAccount() ? $activity->getAccount()->crm_provider_id : null;
// First check the local data.
/** @var Contact[] $contacts */
$contacts = $this->team->contacts()
->with('account')
->where('name', $participant->name)
->whereNotNull('email')
->get();
foreach ($contacts as $contact) {
// If we have a company in scope, check the contact is associated to it.
if (
$companyId !== null
&& ($contact->account_id === null || $companyId !== $contact->account->crm_provider_id)
) {
continue;
}
return [
'id' => $contact->crm_provider_id,
'email' => $contact->email,
];
}
$payload = $this->generateNameSearchPayload($participant->name, 0, 20);
try {
$response = $this->client->getNewInstance()->crm()->contacts()->searchApi()->doSearch($payload);
// TODO add some logic to choose the most suitable contact if multiple
foreach ($response['results'] as $object) {
$properties = $object['properties'];
if (empty($object['properties']) === false) {
// Check the company matches the contact.
// Todo: Move this check inside the API search.
if ($companyId !== null && $companyId !== $properties['associatedcompanyid']) {
continue;
}
return [
'id' => $object['id'],
'email' => $properties['email'],
];
}
}
} catch (Exception $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Search failed', [
'teamId' => $this->team->id_string,
'request' => $payload,
'reason' => $e->getMessage(),
]);
}
return [];
}
/**
* Store transcripts as note engagement.
*
* @throws Exception
*/
public function createTranscriptNotes(Activity $activity): void
{
// For HS no need to check if Crm profile - Log Notes field is enabled
// We only check if store_transcript toggle is enabled on crm profile.
$engagement = [
'active' => true,
'ownerId' => $this->profile->crm_provider_i...
|
43631
|
NULL
|
NULL
|
NULL
|
|
43635
|
1591
|
7
|
2026-05-14T13:03:16.450608+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763796450_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
1 file committed
JY-20903 revert changes in comman 1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"1 file committed","depth":2,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20903 revert changes in command","depth":3,"on_screen":true,"value":"JY-20903 revert changes in command","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"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":"#12077 on JY-20903-update_activity-stage-on…hange, menu","depth":5,"on_screen":true,"help_text":"Pull request #12077 exists for current branch JY-20903-update__activity-stage-on…hange","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}]...
|
5532237588571240767
|
-8861532472594987582
|
click
|
hybrid
|
NULL
|
1 file committed
JY-20903 revert changes in comman 1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
SlackFileEditViewGoHistoryWindowHelpDescribe what you are looking forAneliya AngelovaMessagesAdd canvas@ Files+lhl100% C8• Thu 14 May 16:03:16HomeDMsActivityFilesLaterMoreJiminny ...scnicrat# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Direct messagesP. Aneliya Angelova€. Vasil Vasilev E. Galya Dimitrova&. Stefka Stoyanova: Todor StamatovMario GeorgievNikolay IvanovLo James Graham2 Stoyan TanevSteliyan GeorgievPetko KashinskiLukas Kovalik y...AppsToastJira Cloud6 0Monday, May 11th ~Today ~Aneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук, нали?при останалите CRMi трябва ръчно да се въведатLukas Kovalik 2:47 PMздрастиами не знам по принцип се вика при всичкитрябва да се за всички, някъде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725Jira CloudX Bug IV-20725 in Jira Cloud[HubSpot] Optimise CRM rematching on delete hubspot ac...StatusReady for QAPriority= MediumAssigneeAA Aneliya AngelovaAs of today at 4:00 PMOpen in Jirait SummariseLukas Kovalik 4:02 PMдазвьни направоMessage Aneliya Angelova...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43636
|
1592
|
7
|
2026-05-14T13:03:16.455423+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763796455_m2.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
1 file committed
JY-20903 revert changes in comman 1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"1 file committed","depth":2,"bounds":{"left":0.8753325,"top":0.91300875,"width":0.100398935,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20903 revert changes in command","depth":3,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.11037234,"height":0.013567438},"on_screen":true,"value":"JY-20903 revert changes in command","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.0787899,"height":0.013567438},"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"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":"#12077 on JY-20903-update_activity-stage-on…hange, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12566489,"height":0.025538707},"on_screen":true,"help_text":"Pull request #12077 exists for current branch JY-20903-update__activity-stage-on…hange","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}]...
|
5532237588571240767
|
-8861532472594987582
|
click
|
hybrid
|
NULL
|
1 file committed
JY-20903 revert changes in comman 1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
PhostormProiectINavicarecodeLaravelKeractorWindowFV faVsco.js( #12077 on JY-20903-update_activity-stage-on...ha© UserinvitationDTO.php) CheckAndRetryRemoteMatch.php© Client.php x= laravel.logA SF jiminny@localhost]& ho_local Uiminny@localnost& console [PROD]>MUtilsCo kematchactviyoncrmoojectbetach.ong> D Webhook© MatchActivityCrmData.phpC) Service.pnp© MatchCrmObject.php© BatchSyncCollector.ph|© BatchSyncRedisService600r)class culent excenas baseullenc inolemencs nuospocuulencincertacepublic function getMinimumApiVersion: stringt...}42 ₴60 ^o ullentone© ClosedDealStagesServi65 C >public function getInstance: Factoryf...@ DealFieldsService.phpc DecorateAcuivity.onp74 0 >public function getNewInstance: Discoveryi...© FieldDefinitions.phpc rieldlypeconverter.ph* HubspotClientinterface* secondly and dazly Limits for Huospoc AP!c) Huospoul okenmanader© PavloadBuilder.php© RemoteCrmObiectMani@ ResponseNormalize.ph* Product lier: Free & starter I Professional & enterprise | APl add-on (any ther)* bursc:100/10 seconas 150/10 seconas200/10 seconds250,000I 500,0001,000,000C) Service.oho|101102103T104C) SvncFieldAction.phoC) SuncRe atedActivitvMail* Ufficial documentation states: Ine search endpoints are rate limited to five requests per second.* Since with 5 RPS were still hitting secondlu rate limits we lowered it to 4-10€107C) WebhookSvncBatchProv M intedrationAon89 Cpublic function getPaginatedData(array $payload, string $type, int $offset = 0): array• M Accessors)>MAoConfigMIDTGM filtersmalohsStotal = 01111Sastld e nulSrows =1foreach (Sthis->getPaginatedDataGenerator(Spayload, $type, $offset, &: $total,&lastRecordld: $lastId) as 114Srowsf = Srow.11311151D ProspectSearchStrateg• @ ServiceTraits© DataClient.phpreturn ['results' => $rows, 'total' => $total, 'last_record' => $lastId]:1117118C) DecorateActivity.pnp© LocalSearch.phpMLocalSearchintertace.o(c) RemoteSearch.onoc)service.ono* achrows HubspotExcention* @throws SocialAccountTokenInvalidException122v 0 Listeners© ConvertLeadActivities.f .oc© PurgeLookupCache.phr› 0 Metadata104 Gt> D Miaration•D Pioedrivev Salesforce> D Fields110> OpportunitvMatcher. M OpportunitySyncStrates 112> D ProspectSearchStrategpublic function getPaginatedDataGenerator(array spayloadstrina Stype.int Soffset = 0int &Stotal = 0?string &SlastRecordId = null): \Generator {Sthis.Spavload!Stype,Soffset.%: StotallooGlasthenandtDuched 1 commit to.oriain/IV.20902-undate activitv-ctaae-on-onnortunitvcchande /| View null requect (1 minutes aad- 1/2return Sthis->naginationService->getPaqinatedDataGenerator^• IM ServiceTraitsC) Client nhn@ DecorateActivitv nhnT DeleteObjectsTrait.phpC) SieldDefinitions nhnC) PavloadRuilder nhn111111A console (EU]tiò accounts [EU]fii stages (EU]tid teams [EU]ImporbotkecoraingJoo.onp© Activity.php© FixActivitiesOpportunity.php& console SlAGiNGclass rixacciviclesupoorcunlcy excenas commanaMA2^Ytunccion processrarclcloantsSteam = Sactivity->qetTeamosuser = sactivitv->qetuserossoarticioants=sactivitv->oetparticioantsorforeach (Sparticipants as Sparticipant) 1if ($participant->getUserId() |== null || $participant->getEmailAddress() === null) {continue:SemailAddness = Snanticinant->ae+FmailAddnecso•if (SemailHelper->isCompanyEmail(Steam, SemailAddress)) {continue.try fSopportunity = $this->find0pportunityInCrm($crmService, SemailAddress, Suser->getIdO):} catch (Throwable $e) {$this->error( string: 'Could not find opportunity: ' . $e->getMessage());Sopportunity = nullif (Sopportunity === null) {Sthis->resetActivity0pportunitv(Sactivitv):Sactivity->update(['opportunity id' => Sopportunitv->qetldol):Sthis->info( string: 'Opportunity updated for activity: ' • Sactivity->getidO):Tusageprivate function findOpportunityInCrm(ServiceInterface $crmService, string SemailAddress, int $userId): ?0pportuniprivate function resetActivity0pportunity(Activity Sactivity): void{...}cascade40 hl100% S2• Thu 14 May 16:03:16AskJiminnyReportActivityServiceTest vPipedrive SDK EvaluaActivity Stage DiscrerImport CRM Activity T+0 ..Cascade Code x .Kick off a new project. Make changesacross your entire codedase*, Activity Stage Discrepancy Analysis• Your included weekly usage quota is exhausted. Purchase extra usage to continue using premium models. Quota resets May 17, 11:00 x# 1 file committedwhere isJY-20903 revert changes in command÷ @Code SWF-1.6Edit Commit Messaae.WN Windsurf Toams 80-21UTF.8io 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43637
|
1592
|
8
|
2026-05-14T13:03:18.733493+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763798733_m2.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
1 file committed
JY-20903 revert changes in comman 1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
2
60
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Activities;
use Illuminate\Support\Facades\Validator;
use Jiminny\Console\Commands\Command;
use Jiminny\Contracts\Services\Crm\ServiceInterface;
use Jiminny\Models\Activity;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\EmailHelper;
use Throwable;
class FixActivitiesOpportunity extends Command
{
protected $signature = 'activity:fix-opportunity {--from=} {--to=}';
public function handle(EmailHelper $emailHelper): int
{
$from = $this->option('from');
$to = $this->option('to');
$validator = Validator::make(
['from' => $from, 'to' => $to],
[
'from' => ['required', 'date'],
'to' => ['required', 'date'],
]
);
if ($validator->fails()) {
$this->error('Validation failed:');
$this->output->block($validator->errors()->all());
return Command::FAILURE;
}
$this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);
$activityIds = Activity::select('activities.id')
->whereBetween('activities.created_at', [$from, $to])
->join('users', 'activities.user_id', '=', 'users.id')
->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')
->whereColumn('opportunities.team_id', '<>', 'users.team_id')
->pluck('id');
$this->info('Found activities: ' . $activityIds->count());
foreach ($activityIds as $activityId) {
$activity = Activity::where('id', $activityId)
->with(['user', 'participants'])
->first();
$crmService = $this->getCrmService($activity->getTeam());
if ($crmService === null) {
$this->resetActivityOpportunity($activity);
continue;
}
$this->processParticipants($crmService, $emailHelper, $activity);
}
return Command::SUCCESS;
}
private function getCrmService(Team $team): ?ServiceInterface
{
$config = $team->getCrmConfiguration();
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $team->getOwner(),
'providerSlug' => $config->getProviderName(),
]);
try {
return $crmResolver->prepareCrmService();
} catch (Throwable $e) {
$this->error('Could not prepare CRM service: ' . $e->getMessage());
return null;
}
}
private function processParticipants(
ServiceInterface $crmService,
EmailHelper $emailHelper,
Activity $activity
): void {
$team = $activity->getTeam();
$user = $activity->getUser();
$participants = $activity->getParticipants();
foreach ($participants as $participant) {
if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {
continue;
}
$emailAddress = $participant->getEmailAddress();
if ($emailHelper->isCompanyEmail($team, $emailAddress)) {
continue;
}
try {
$opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());
} catch (Throwable $e) {
$this->error('Could not find opportunity: ' . $e->getMessage());
$opportunity = null;
}
if ($opportunity === null) {
$this->resetActivityOpportunity($activity);
continue;
}
$activity->update(['opportunity_id' => $opportunity->getId()]);
$this->info('Opportunity updated for activity: ' . $activity->getId());
}
}
private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity
{
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
$match = $decorator->matchExactlyByEmail($emailAddress, $userId);
if (empty($match)) {
$match = $decorator->matchByDomain($emailAddress, $userId);
}
if (empty($match)) {
return null;
}
[, , $opportunity, ,] = $match;
return $opportunity;
}
private function resetActivityOpportunity(Activity $activity): void
{
$this->info('Reset opportunity for activity: ' . $activity->getId());
$activity->update(['opportunity_id' => null]);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"1 file committed","depth":2,"bounds":{"left":0.8753325,"top":0.91300875,"width":0.100398935,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20903 revert changes in command","depth":3,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.11037234,"height":0.013567438},"on_screen":true,"value":"JY-20903 revert changes in command","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.0787899,"height":0.013567438},"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"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":"#12077 on JY-20903-update_activity-stage-on…hange, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12566489,"height":0.025538707},"on_screen":true,"help_text":"Pull request #12077 exists for current branch JY-20903-update__activity-stage-on…hange","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":"2","depth":4,"bounds":{"left":0.37167552,"top":0.12529927,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"60","depth":4,"bounds":{"left":0.38164893,"top":0.12529927,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.39361703,"top":0.123703115,"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.40093085,"top":0.123703115,"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\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\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":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.7140958,"top":0.12529927,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7237367,"top":0.123703115,"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.73105055,"top":0.123703115,"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\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\EmailHelper;\nuse Throwable;\n\nclass FixActivitiesOpportunity extends Command\n{\n protected $signature = 'activity:fix-opportunity {--from=} {--to=}';\n\n public function handle(EmailHelper $emailHelper): int\n {\n $from = $this->option('from');\n $to = $this->option('to');\n\n $validator = Validator::make(\n ['from' => $from, 'to' => $to],\n [\n 'from' => ['required', 'date'],\n 'to' => ['required', 'date'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return Command::FAILURE;\n }\n\n $this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);\n\n $activityIds = Activity::select('activities.id')\n ->whereBetween('activities.created_at', [$from, $to])\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')\n ->whereColumn('opportunities.team_id', '<>', 'users.team_id')\n ->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n\n foreach ($activityIds as $activityId) {\n $activity = Activity::where('id', $activityId)\n ->with(['user', 'participants'])\n ->first();\n\n $crmService = $this->getCrmService($activity->getTeam());\n if ($crmService === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $this->processParticipants($crmService, $emailHelper, $activity);\n }\n\n return Command::SUCCESS;\n }\n\n private function getCrmService(Team $team): ?ServiceInterface\n {\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n try {\n return $crmResolver->prepareCrmService();\n } catch (Throwable $e) {\n $this->error('Could not prepare CRM service: ' . $e->getMessage());\n\n return null;\n }\n }\n\n private function processParticipants(\n ServiceInterface $crmService,\n EmailHelper $emailHelper,\n Activity $activity\n ): void {\n $team = $activity->getTeam();\n $user = $activity->getUser();\n $participants = $activity->getParticipants();\n\n foreach ($participants as $participant) {\n if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {\n continue;\n }\n\n $emailAddress = $participant->getEmailAddress();\n if ($emailHelper->isCompanyEmail($team, $emailAddress)) {\n continue;\n }\n\n try {\n $opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());\n } catch (Throwable $e) {\n $this->error('Could not find opportunity: ' . $e->getMessage());\n\n $opportunity = null;\n }\n\n if ($opportunity === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $activity->update(['opportunity_id' => $opportunity->getId()]);\n\n $this->info('Opportunity updated for activity: ' . $activity->getId());\n }\n }\n\n private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity\n {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n $match = $decorator->matchExactlyByEmail($emailAddress, $userId);\n\n if (empty($match)) {\n $match = $decorator->matchByDomain($emailAddress, $userId);\n }\n\n if (empty($match)) {\n return null;\n }\n\n [, , $opportunity, ,] = $match;\n\n return $opportunity;\n }\n\n private function resetActivityOpportunity(Activity $activity): void\n {\n $this->info('Reset opportunity for activity: ' . $activity->getId());\n $activity->update(['opportunity_id' => null]);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\EmailHelper;\nuse Throwable;\n\nclass FixActivitiesOpportunity extends Command\n{\n protected $signature = 'activity:fix-opportunity {--from=} {--to=}';\n\n public function handle(EmailHelper $emailHelper): int\n {\n $from = $this->option('from');\n $to = $this->option('to');\n\n $validator = Validator::make(\n ['from' => $from, 'to' => $to],\n [\n 'from' => ['required', 'date'],\n 'to' => ['required', 'date'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return Command::FAILURE;\n }\n\n $this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);\n\n $activityIds = Activity::select('activities.id')\n ->whereBetween('activities.created_at', [$from, $to])\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')\n ->whereColumn('opportunities.team_id', '<>', 'users.team_id')\n ->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n\n foreach ($activityIds as $activityId) {\n $activity = Activity::where('id', $activityId)\n ->with(['user', 'participants'])\n ->first();\n\n $crmService = $this->getCrmService($activity->getTeam());\n if ($crmService === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $this->processParticipants($crmService, $emailHelper, $activity);\n }\n\n return Command::SUCCESS;\n }\n\n private function getCrmService(Team $team): ?ServiceInterface\n {\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n try {\n return $crmResolver->prepareCrmService();\n } catch (Throwable $e) {\n $this->error('Could not prepare CRM service: ' . $e->getMessage());\n\n return null;\n }\n }\n\n private function processParticipants(\n ServiceInterface $crmService,\n EmailHelper $emailHelper,\n Activity $activity\n ): void {\n $team = $activity->getTeam();\n $user = $activity->getUser();\n $participants = $activity->getParticipants();\n\n foreach ($participants as $participant) {\n if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {\n continue;\n }\n\n $emailAddress = $participant->getEmailAddress();\n if ($emailHelper->isCompanyEmail($team, $emailAddress)) {\n continue;\n }\n\n try {\n $opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());\n } catch (Throwable $e) {\n $this->error('Could not find opportunity: ' . $e->getMessage());\n\n $opportunity = null;\n }\n\n if ($opportunity === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $activity->update(['opportunity_id' => $opportunity->getId()]);\n\n $this->info('Opportunity updated for activity: ' . $activity->getId());\n }\n }\n\n private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity\n {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n $match = $decorator->matchExactlyByEmail($emailAddress, $userId);\n\n if (empty($match)) {\n $match = $decorator->matchByDomain($emailAddress, $userId);\n }\n\n if (empty($match)) {\n return null;\n }\n\n [, , $opportunity, ,] = $match;\n\n return $opportunity;\n }\n\n private function resetActivityOpportunity(Activity $activity): void\n {\n $this->info('Reset opportunity for activity: ' . $activity->getId());\n $activity->update(['opportunity_id' => null]);\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}]...
|
7981347868553932337
|
5225837876532353124
|
visual_change
|
accessibility
|
NULL
|
1 file committed
JY-20903 revert changes in comman 1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
2
60
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Activities;
use Illuminate\Support\Facades\Validator;
use Jiminny\Console\Commands\Command;
use Jiminny\Contracts\Services\Crm\ServiceInterface;
use Jiminny\Models\Activity;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\EmailHelper;
use Throwable;
class FixActivitiesOpportunity extends Command
{
protected $signature = 'activity:fix-opportunity {--from=} {--to=}';
public function handle(EmailHelper $emailHelper): int
{
$from = $this->option('from');
$to = $this->option('to');
$validator = Validator::make(
['from' => $from, 'to' => $to],
[
'from' => ['required', 'date'],
'to' => ['required', 'date'],
]
);
if ($validator->fails()) {
$this->error('Validation failed:');
$this->output->block($validator->errors()->all());
return Command::FAILURE;
}
$this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);
$activityIds = Activity::select('activities.id')
->whereBetween('activities.created_at', [$from, $to])
->join('users', 'activities.user_id', '=', 'users.id')
->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')
->whereColumn('opportunities.team_id', '<>', 'users.team_id')
->pluck('id');
$this->info('Found activities: ' . $activityIds->count());
foreach ($activityIds as $activityId) {
$activity = Activity::where('id', $activityId)
->with(['user', 'participants'])
->first();
$crmService = $this->getCrmService($activity->getTeam());
if ($crmService === null) {
$this->resetActivityOpportunity($activity);
continue;
}
$this->processParticipants($crmService, $emailHelper, $activity);
}
return Command::SUCCESS;
}
private function getCrmService(Team $team): ?ServiceInterface
{
$config = $team->getCrmConfiguration();
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $team->getOwner(),
'providerSlug' => $config->getProviderName(),
]);
try {
return $crmResolver->prepareCrmService();
} catch (Throwable $e) {
$this->error('Could not prepare CRM service: ' . $e->getMessage());
return null;
}
}
private function processParticipants(
ServiceInterface $crmService,
EmailHelper $emailHelper,
Activity $activity
): void {
$team = $activity->getTeam();
$user = $activity->getUser();
$participants = $activity->getParticipants();
foreach ($participants as $participant) {
if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {
continue;
}
$emailAddress = $participant->getEmailAddress();
if ($emailHelper->isCompanyEmail($team, $emailAddress)) {
continue;
}
try {
$opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());
} catch (Throwable $e) {
$this->error('Could not find opportunity: ' . $e->getMessage());
$opportunity = null;
}
if ($opportunity === null) {
$this->resetActivityOpportunity($activity);
continue;
}
$activity->update(['opportunity_id' => $opportunity->getId()]);
$this->info('Opportunity updated for activity: ' . $activity->getId());
}
}
private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity
{
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
$match = $decorator->matchExactlyByEmail($emailAddress, $userId);
if (empty($match)) {
$match = $decorator->matchByDomain($emailAddress, $userId);
}
if (empty($match)) {
return null;
}
[, , $opportunity, ,] = $match;
return $opportunity;
}
private function resetActivityOpportunity(Activity $activity): void
{
$this->info('Reset opportunity for activity: ' . $activity->getId());
$activity->update(['opportunity_id' => null]);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
43636
|
NULL
|
NULL
|
NULL
|
|
43638
|
1591
|
8
|
2026-05-14T13:03:19.976900+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763799976_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
1 file committed
JY-20903 revert changes in comman 1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
2
60
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Activities;
use Illuminate\Support\Facades\Validator;
use Jiminny\Console\Commands\Command;
use Jiminny\Contracts\Services\Crm\ServiceInterface;
use Jiminny\Models\Activity;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\EmailHelper;
use Throwable;
class FixActivitiesOpportunity extends Command
{
protected $signature = 'activity:fix-opportunity {--from=} {--to=}';
public function handle(EmailHelper $emailHelper): int
{
$from = $this->option('from');
$to = $this->option('to');
$validator = Validator::make(
['from' => $from, 'to' => $to],
[
'from' => ['required', 'date'],
'to' => ['required', 'date'],
]
);
if ($validator->fails()) {
$this->error('Validation failed:');
$this->output->block($validator->errors()->all());
return Command::FAILURE;
}
$this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);
$activityIds = Activity::select('activities.id')
->whereBetween('activities.created_at', [$from, $to])
->join('users', 'activities.user_id', '=', 'users.id')
->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')
->whereColumn('opportunities.team_id', '<>', 'users.team_id')
->pluck('id');
$this->info('Found activities: ' . $activityIds->count());
foreach ($activityIds as $activityId) {
$activity = Activity::where('id', $activityId)
->with(['user', 'participants'])
->first();
$crmService = $this->getCrmService($activity->getTeam());
if ($crmService === null) {
$this->resetActivityOpportunity($activity);
continue;
}
$this->processParticipants($crmService, $emailHelper, $activity);
}
return Command::SUCCESS;
}
private function getCrmService(Team $team): ?ServiceInterface
{
$config = $team->getCrmConfiguration();
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $team->getOwner(),
'providerSlug' => $config->getProviderName(),
]);
try {
return $crmResolver->prepareCrmService();
} catch (Throwable $e) {
$this->error('Could not prepare CRM service: ' . $e->getMessage());
return null;
}
}
private function processParticipants(
ServiceInterface $crmService,
EmailHelper $emailHelper,
Activity $activity
): void {
$team = $activity->getTeam();
$user = $activity->getUser();
$participants = $activity->getParticipants();
foreach ($participants as $participant) {
if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {
continue;
}
$emailAddress = $participant->getEmailAddress();
if ($emailHelper->isCompanyEmail($team, $emailAddress)) {
continue;
}
try {
$opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());
} catch (Throwable $e) {
$this->error('Could not find opportunity: ' . $e->getMessage());
$opportunity = null;
}
if ($opportunity === null) {
$this->resetActivityOpportunity($activity);
continue;
}
$activity->update(['opportunity_id' => $opportunity->getId()]);
$this->info('Opportunity updated for activity: ' . $activity->getId());
}
}
private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity
{
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
$match = $decorator->matchExactlyByEmail($emailAddress, $userId);
if (empty($match)) {
$match = $decorator->matchByDomain($emailAddress, $userId);
}
if (empty($match)) {
return null;
}
[, , $opportunity, ,] = $match;
return $opportunity;
}
private function resetActivityOpportunity(Activity $activity): void
{
$this->info('Reset opportunity for activity: ' . $activity->getId());
$activity->update(['opportunity_id' => null]);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"1 file committed","depth":2,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20903 revert changes in command","depth":3,"on_screen":true,"value":"JY-20903 revert changes in command","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"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":"#12077 on JY-20903-update_activity-stage-on…hange, menu","depth":5,"on_screen":true,"help_text":"Pull request #12077 exists for current branch JY-20903-update__activity-stage-on…hange","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":"2","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"60","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\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\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":"AXStaticText","text":"2","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\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\EmailHelper;\nuse Throwable;\n\nclass FixActivitiesOpportunity extends Command\n{\n protected $signature = 'activity:fix-opportunity {--from=} {--to=}';\n\n public function handle(EmailHelper $emailHelper): int\n {\n $from = $this->option('from');\n $to = $this->option('to');\n\n $validator = Validator::make(\n ['from' => $from, 'to' => $to],\n [\n 'from' => ['required', 'date'],\n 'to' => ['required', 'date'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return Command::FAILURE;\n }\n\n $this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);\n\n $activityIds = Activity::select('activities.id')\n ->whereBetween('activities.created_at', [$from, $to])\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')\n ->whereColumn('opportunities.team_id', '<>', 'users.team_id')\n ->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n\n foreach ($activityIds as $activityId) {\n $activity = Activity::where('id', $activityId)\n ->with(['user', 'participants'])\n ->first();\n\n $crmService = $this->getCrmService($activity->getTeam());\n if ($crmService === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $this->processParticipants($crmService, $emailHelper, $activity);\n }\n\n return Command::SUCCESS;\n }\n\n private function getCrmService(Team $team): ?ServiceInterface\n {\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n try {\n return $crmResolver->prepareCrmService();\n } catch (Throwable $e) {\n $this->error('Could not prepare CRM service: ' . $e->getMessage());\n\n return null;\n }\n }\n\n private function processParticipants(\n ServiceInterface $crmService,\n EmailHelper $emailHelper,\n Activity $activity\n ): void {\n $team = $activity->getTeam();\n $user = $activity->getUser();\n $participants = $activity->getParticipants();\n\n foreach ($participants as $participant) {\n if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {\n continue;\n }\n\n $emailAddress = $participant->getEmailAddress();\n if ($emailHelper->isCompanyEmail($team, $emailAddress)) {\n continue;\n }\n\n try {\n $opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());\n } catch (Throwable $e) {\n $this->error('Could not find opportunity: ' . $e->getMessage());\n\n $opportunity = null;\n }\n\n if ($opportunity === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $activity->update(['opportunity_id' => $opportunity->getId()]);\n\n $this->info('Opportunity updated for activity: ' . $activity->getId());\n }\n }\n\n private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity\n {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n $match = $decorator->matchExactlyByEmail($emailAddress, $userId);\n\n if (empty($match)) {\n $match = $decorator->matchByDomain($emailAddress, $userId);\n }\n\n if (empty($match)) {\n return null;\n }\n\n [, , $opportunity, ,] = $match;\n\n return $opportunity;\n }\n\n private function resetActivityOpportunity(Activity $activity): void\n {\n $this->info('Reset opportunity for activity: ' . $activity->getId());\n $activity->update(['opportunity_id' => null]);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\EmailHelper;\nuse Throwable;\n\nclass FixActivitiesOpportunity extends Command\n{\n protected $signature = 'activity:fix-opportunity {--from=} {--to=}';\n\n public function handle(EmailHelper $emailHelper): int\n {\n $from = $this->option('from');\n $to = $this->option('to');\n\n $validator = Validator::make(\n ['from' => $from, 'to' => $to],\n [\n 'from' => ['required', 'date'],\n 'to' => ['required', 'date'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return Command::FAILURE;\n }\n\n $this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);\n\n $activityIds = Activity::select('activities.id')\n ->whereBetween('activities.created_at', [$from, $to])\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')\n ->whereColumn('opportunities.team_id', '<>', 'users.team_id')\n ->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n\n foreach ($activityIds as $activityId) {\n $activity = Activity::where('id', $activityId)\n ->with(['user', 'participants'])\n ->first();\n\n $crmService = $this->getCrmService($activity->getTeam());\n if ($crmService === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $this->processParticipants($crmService, $emailHelper, $activity);\n }\n\n return Command::SUCCESS;\n }\n\n private function getCrmService(Team $team): ?ServiceInterface\n {\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n try {\n return $crmResolver->prepareCrmService();\n } catch (Throwable $e) {\n $this->error('Could not prepare CRM service: ' . $e->getMessage());\n\n return null;\n }\n }\n\n private function processParticipants(\n ServiceInterface $crmService,\n EmailHelper $emailHelper,\n Activity $activity\n ): void {\n $team = $activity->getTeam();\n $user = $activity->getUser();\n $participants = $activity->getParticipants();\n\n foreach ($participants as $participant) {\n if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {\n continue;\n }\n\n $emailAddress = $participant->getEmailAddress();\n if ($emailHelper->isCompanyEmail($team, $emailAddress)) {\n continue;\n }\n\n try {\n $opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());\n } catch (Throwable $e) {\n $this->error('Could not find opportunity: ' . $e->getMessage());\n\n $opportunity = null;\n }\n\n if ($opportunity === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $activity->update(['opportunity_id' => $opportunity->getId()]);\n\n $this->info('Opportunity updated for activity: ' . $activity->getId());\n }\n }\n\n private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity\n {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n $match = $decorator->matchExactlyByEmail($emailAddress, $userId);\n\n if (empty($match)) {\n $match = $decorator->matchByDomain($emailAddress, $userId);\n }\n\n if (empty($match)) {\n return null;\n }\n\n [, , $opportunity, ,] = $match;\n\n return $opportunity;\n }\n\n private function resetActivityOpportunity(Activity $activity): void\n {\n $this->info('Reset opportunity for activity: ' . $activity->getId());\n $activity->update(['opportunity_id' => null]);\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}]...
|
7981347868553932337
|
5225837876532353124
|
click
|
accessibility
|
NULL
|
1 file committed
JY-20903 revert changes in comman 1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
2
60
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Activities;
use Illuminate\Support\Facades\Validator;
use Jiminny\Console\Commands\Command;
use Jiminny\Contracts\Services\Crm\ServiceInterface;
use Jiminny\Models\Activity;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\EmailHelper;
use Throwable;
class FixActivitiesOpportunity extends Command
{
protected $signature = 'activity:fix-opportunity {--from=} {--to=}';
public function handle(EmailHelper $emailHelper): int
{
$from = $this->option('from');
$to = $this->option('to');
$validator = Validator::make(
['from' => $from, 'to' => $to],
[
'from' => ['required', 'date'],
'to' => ['required', 'date'],
]
);
if ($validator->fails()) {
$this->error('Validation failed:');
$this->output->block($validator->errors()->all());
return Command::FAILURE;
}
$this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);
$activityIds = Activity::select('activities.id')
->whereBetween('activities.created_at', [$from, $to])
->join('users', 'activities.user_id', '=', 'users.id')
->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')
->whereColumn('opportunities.team_id', '<>', 'users.team_id')
->pluck('id');
$this->info('Found activities: ' . $activityIds->count());
foreach ($activityIds as $activityId) {
$activity = Activity::where('id', $activityId)
->with(['user', 'participants'])
->first();
$crmService = $this->getCrmService($activity->getTeam());
if ($crmService === null) {
$this->resetActivityOpportunity($activity);
continue;
}
$this->processParticipants($crmService, $emailHelper, $activity);
}
return Command::SUCCESS;
}
private function getCrmService(Team $team): ?ServiceInterface
{
$config = $team->getCrmConfiguration();
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $team->getOwner(),
'providerSlug' => $config->getProviderName(),
]);
try {
return $crmResolver->prepareCrmService();
} catch (Throwable $e) {
$this->error('Could not prepare CRM service: ' . $e->getMessage());
return null;
}
}
private function processParticipants(
ServiceInterface $crmService,
EmailHelper $emailHelper,
Activity $activity
): void {
$team = $activity->getTeam();
$user = $activity->getUser();
$participants = $activity->getParticipants();
foreach ($participants as $participant) {
if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {
continue;
}
$emailAddress = $participant->getEmailAddress();
if ($emailHelper->isCompanyEmail($team, $emailAddress)) {
continue;
}
try {
$opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());
} catch (Throwable $e) {
$this->error('Could not find opportunity: ' . $e->getMessage());
$opportunity = null;
}
if ($opportunity === null) {
$this->resetActivityOpportunity($activity);
continue;
}
$activity->update(['opportunity_id' => $opportunity->getId()]);
$this->info('Opportunity updated for activity: ' . $activity->getId());
}
}
private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity
{
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
$match = $decorator->matchExactlyByEmail($emailAddress, $userId);
if (empty($match)) {
$match = $decorator->matchByDomain($emailAddress, $userId);
}
if (empty($match)) {
return null;
}
[, , $opportunity, ,] = $match;
return $opportunity;
}
private function resetActivityOpportunity(Activity $activity): void
{
$this->info('Reset opportunity for activity: ' . $activity->getId());
$activity->update(['opportunity_id' => null]);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
43635
|
NULL
|
NULL
|
NULL
|
|
43639
|
1591
|
9
|
2026-05-14T13:03:26.621824+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763806621_m1.jpg...
|
PhpStorm
|
faVsco.js – HubspotPaginationService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
1 file committed
JY-20903 revert changes in comman 1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
12
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot\Pagination;
use Jiminny\Services\Crm\Hubspot\Client;
use Jiminny\Services\Crm\Hubspot\PayloadBuilder;
use Psr\Log\LoggerInterface;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
class HubspotPaginationService
{
public function __construct(
private LoggerInterface $logger
) {
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
Client $client,
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
$state = new PaginationState(offset: $offset);
$endpoint = Client::BASE_URL . "/crm/v3/objects/{$type}/search";
$defaultFilter = $payload['filters'] ?? [];
$resultsPerPage = PayloadBuilder::MAX_SEARCH_REQUEST_LIMIT;
$teamId = $client->getConfig()->getTeam()->getId();
$delay = $this->calculateDelayInMicroseconds();
do {
if ($this->shouldStopPagination($state, $teamId)) {
break;
}
$payload = $this->handlePaginationStrategy($payload, $defaultFilter, $state, $resultsPerPage, $teamId);
$this->validateTokenIfNeeded($client, $state);
usleep($delay);
$page = $this->executeSearchRequest($client, $endpoint, $payload, $state);
$state->setTotal($page['total'] ?? 0);
$this->updateLastRecordId($page, $state);
// Safely iterate over results with null check
$results = $page['results'] ?? [];
foreach ($results as $row) {
$state->incrementTotalRecords();
yield $row;
}
$state->setOffset($this->getNextOffset($page));
$state->incrementRequestCount();
$this->logPaginationProgress($state, $teamId, $endpoint);
} while ($state->offset && ! empty($page['results']));
// Log final pagination completion stats
$this->logger->info('[Hubspot] Pagination completed', [
'team_id' => $teamId,
'endpoint' => $endpoint,
'total_requests' => $state->requestCount,
'total_records_fetched' => $state->totalRecords,
'total_elapsed_seconds' => round($state->getElapsedSeconds(), 2),
'average_seconds_per_request' => $state->requestCount > 0 ? round($state->getElapsedSeconds() / $state->requestCount, 2) : 0,
]);
// Update reference parameters
$total = $state->total;
$lastRecordId = $state->lastRecordId;
}
private function shouldStopPagination(PaginationState $state, int $teamId): bool
{
if ($state->hasReachedSafetyLimit()) {
$this->logger->warning('[Hubspot] Reached maximum request limit during pagination', [
'team_id' => $teamId,
'safety_limit' => PaginationConfig::LOOP_SAFETY_LIMIT,
'total_fetched' => $state->totalRecords,
]);
return true;
}
return false;
}
private function handlePaginationStrategy(
array $payload,
array $defaultFilter,
PaginationState $state,
int $resultsPerPage,
int $teamId
): array {
if ($this->shouldSwitchToKeysetPagination($state, $resultsPerPage)) {
$payload['filters'] = $defaultFilter;
$payload['filters'][] = [
'propertyName' => 'hs_object_id',
'operator' => 'LT',
'value' => $state->lastRecordId,
];
$this->logger->info('[Hubspot] Search keyset pagination request', [
'team_id' => $teamId,
'sequence' => $state->requestCount,
'itemsPerPage' => $resultsPerPage,
'payload' => $payload,
'total' => $state->total,
]);
unset($payload['after']);
$state->setOffset(0);
}
if ($state->offset) {
$payload['after'] = $state->offset;
}
return $payload;
}
private function shouldSwitchToKeysetPagination(PaginationState $state, int $resultsPerPage): bool
{
// Check if we've hit the offset limit
$shouldSwitch = $state->requestCount > 0 && ($state->offset + $resultsPerPage) > PaginationConfig::TOTAL_QUERY_LIMIT;
if ($shouldSwitch && $state->lastRecordId === null) {
$this->logger->warning('[Hubspot] Cannot switch to keyset pagination: lastRecordId is null', [
'request_count' => $state->requestCount,
'current_offset' => $state->offset,
'results_per_page' => $resultsPerPage,
'total_query_limit' => PaginationConfig::TOTAL_QUERY_LIMIT,
]);
return false; // Continue with offset pagination
}
return $shouldSwitch;
}
private function validateTokenIfNeeded(Client $client, PaginationState $state): void
{
if ($state->shouldValidateToken()) {
$client->ensureValidToken();
$state->updateLastTokenCheck();
}
}
private function executeSearchRequest(Client $client, string $endpoint, array $payload, PaginationState $state): array
{
try {
$response = $client->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
} catch (\Exception $e) {
if ($client->isUnauthorizedException($e)) {
$this->logger->warning('[Hubspot] Got 401 during pagination, attempting token refresh', [
'team_id' => $client->getConfig()->getTeam()->getId(),
'error' => $e->getMessage(),
]);
$client->ensureValidToken();
$state->updateLastTokenCheck();
try {
$response = $client->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
$this->logger->info('[Hubspot] Token refresh and retry successful', [
'team_id' => $client->getConfig()->getTeam()->getId(),
]);
return $response->toArray();
} catch (\Exception $retryException) {
$this->logger->error('[Hubspot] Retry request failed after token refresh', [
'team_id' => $client->getConfig()->getTeam()->getId(),
'original_error' => $e->getMessage(),
'retry_error' => $retryException->getMessage(),
]);
throw $retryException;
}
} else {
throw $e;
}
}
}
private function updateLastRecordId(array $page, PaginationState $state): void
{
$lastRecord = ! empty($page['results']) ? end($page['results']) : null;
$lastRecordId = $lastRecord['id'] ?? null;
$state->updateLastRecordId($lastRecordId);
}
private function getNextOffset(array $page): int
{
return isset($page['paging']['next']['after']) ? (int) $page['paging']['next']['after'] : 0;
}
private function logPaginationProgress(PaginationState $state, int $teamId, string $endpoint): void
{
if ($state->shouldLogProgress()) {
$this->logger->info('[Hubspot] Pagination progress log', [
'team_id' => $teamId,
'endpoint' => $endpoint,
'requests_made' => $state->requestCount,
'records_fetched' => $state->totalRecords,
'elapsed_seconds' => $state->getElapsedSeconds(),
]);
}
}
private function calculateDelayInMicroseconds(): int
{
return (int) (1 / PaginationConfig::SEARCH_RPS_LIMIT * 1000000);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Activities;
use Illuminate\Support\Facades\Validator;
use Jiminny\Console\Commands\Command;
use Jiminny\Contracts\Services\Crm\ServiceInterface;
use Jiminny\Models\Activity;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\EmailHelper;
use Throwable;
class FixActivitiesOpportunity extends Command
{
protected $signature = 'activity:fix-opportunity {--from=} {--to=}';
public function handle(EmailHelper $emailHelper): int
{
$from = $this->option('from');
$to = $this->option('to');
$validator = Validator::make(
['from' => $from, 'to' => $to],
[
'from' => ['required', 'date'],
'to' => ['required', 'date'],
]
);
if ($validator->fails()) {
$this->error('Validation failed:');
$this->output->block($validator->errors()->all());
return Command::FAILURE;
}
$this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);
$activityIds = Activity::select('activities.id')
->whereBetween('activities.created_at', [$from, $to])
->join('users', 'activities.user_id', '=', 'users.id')
->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')
->whereColumn('opportunities.team_id', '<>', 'users.team_id')
->pluck('id');
$this->info('Found activities: ' . $activityIds->count());
foreach ($activityIds as $activityId) {
$activity = Activity::where('id', $activityId)
->with(['user', 'participants'])
->first();
$crmService = $this->getCrmService($activity->getTeam());
if ($crmService === null) {
$this->resetActivityOpportunity($activity);
continue;
}
$this->processParticipants($crmService, $emailHelper, $activity);
}
return Command::SUCCESS;
}
private function getCrmService(Team $team): ?ServiceInterface
{
$config = $team->getCrmConfiguration();
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $team->getOwner(),
'providerSlug' => $config->getProviderName(),
]);
try {
return $crmResolver->prepareCrmService();
} catch (Throwable $e) {
$this->error('Could not prepare CRM service: ' . $e->getMessage());
return null;
}
}
private function processParticipants(
ServiceInterface $crmService,
EmailHelper $emailHelper,
Activity $activity
): void {
$team = $activity->getTeam();
$user = $activity->getUser();
$participants = $activity->getParticipants();
foreach ($participants as $participant) {
if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {
continue;
}
$emailAddress = $participant->getEmailAddress();
if ($emailHelper->isCompanyEmail($team, $emailAddress)) {
continue;
}
try {
$opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());
} catch (Throwable $e) {
$this->error('Could not find opportunity: ' . $e->getMessage());
$opportunity = null;
}
if ($opportunity === null) {
$this->resetActivityOpportunity($activity);
continue;
}
$activity->update(['opportunity_id' => $opportunity->getId()]);
$this->info('Opportunity updated for activity: ' . $activity->getId());
}
}
private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity
{
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
$match = $decorator->matchExactlyByEmail($emailAddress, $userId);
if (empty($match)) {
$match = $decorator->matchByDomain($emailAddress, $userId);
}
if (empty($match)) {
return null;
}
[, , $opportunity, ,] = $match;
return $opportunity;
}
private function resetActivityOpportunity(Activity $activity): void
{
$this->info('Reset opportunity for activity: ' . $activity->getId());
$activity->update(['opportunity_id' => null]);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"1 file committed","depth":2,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20903 revert changes in command","depth":3,"on_screen":true,"value":"JY-20903 revert changes in command","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"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":"#12077 on JY-20903-update_activity-stage-on…hange, menu","depth":5,"on_screen":true,"help_text":"Pull request #12077 exists for current branch JY-20903-update__activity-stage-on…hange","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":"12","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\\Hubspot\\Pagination;\n\nuse Jiminny\\Services\\Crm\\Hubspot\\Client;\nuse Jiminny\\Services\\Crm\\Hubspot\\PayloadBuilder;\nuse Psr\\Log\\LoggerInterface;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\n\nclass HubspotPaginationService\n{\n public function __construct(\n private LoggerInterface $logger\n ) {\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n Client $client,\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n $state = new PaginationState(offset: $offset);\n $endpoint = Client::BASE_URL . \"/crm/v3/objects/{$type}/search\";\n $defaultFilter = $payload['filters'] ?? [];\n $resultsPerPage = PayloadBuilder::MAX_SEARCH_REQUEST_LIMIT;\n $teamId = $client->getConfig()->getTeam()->getId();\n $delay = $this->calculateDelayInMicroseconds();\n\n do {\n if ($this->shouldStopPagination($state, $teamId)) {\n break;\n }\n\n $payload = $this->handlePaginationStrategy($payload, $defaultFilter, $state, $resultsPerPage, $teamId);\n\n $this->validateTokenIfNeeded($client, $state);\n usleep($delay);\n\n $page = $this->executeSearchRequest($client, $endpoint, $payload, $state);\n\n $state->setTotal($page['total'] ?? 0);\n $this->updateLastRecordId($page, $state);\n\n // Safely iterate over results with null check\n $results = $page['results'] ?? [];\n foreach ($results as $row) {\n $state->incrementTotalRecords();\n yield $row;\n }\n\n $state->setOffset($this->getNextOffset($page));\n $state->incrementRequestCount();\n\n $this->logPaginationProgress($state, $teamId, $endpoint);\n } while ($state->offset && ! empty($page['results']));\n\n // Log final pagination completion stats\n $this->logger->info('[Hubspot] Pagination completed', [\n 'team_id' => $teamId,\n 'endpoint' => $endpoint,\n 'total_requests' => $state->requestCount,\n 'total_records_fetched' => $state->totalRecords,\n 'total_elapsed_seconds' => round($state->getElapsedSeconds(), 2),\n 'average_seconds_per_request' => $state->requestCount > 0 ? round($state->getElapsedSeconds() / $state->requestCount, 2) : 0,\n ]);\n\n // Update reference parameters\n $total = $state->total;\n $lastRecordId = $state->lastRecordId;\n }\n\n private function shouldStopPagination(PaginationState $state, int $teamId): bool\n {\n if ($state->hasReachedSafetyLimit()) {\n $this->logger->warning('[Hubspot] Reached maximum request limit during pagination', [\n 'team_id' => $teamId,\n 'safety_limit' => PaginationConfig::LOOP_SAFETY_LIMIT,\n 'total_fetched' => $state->totalRecords,\n ]);\n\n return true;\n }\n\n return false;\n }\n\n private function handlePaginationStrategy(\n array $payload,\n array $defaultFilter,\n PaginationState $state,\n int $resultsPerPage,\n int $teamId\n ): array {\n if ($this->shouldSwitchToKeysetPagination($state, $resultsPerPage)) {\n $payload['filters'] = $defaultFilter;\n $payload['filters'][] = [\n 'propertyName' => 'hs_object_id',\n 'operator' => 'LT',\n 'value' => $state->lastRecordId,\n ];\n\n $this->logger->info('[Hubspot] Search keyset pagination request', [\n 'team_id' => $teamId,\n 'sequence' => $state->requestCount,\n 'itemsPerPage' => $resultsPerPage,\n 'payload' => $payload,\n 'total' => $state->total,\n ]);\n\n unset($payload['after']);\n $state->setOffset(0);\n }\n\n if ($state->offset) {\n $payload['after'] = $state->offset;\n }\n\n return $payload;\n }\n\n private function shouldSwitchToKeysetPagination(PaginationState $state, int $resultsPerPage): bool\n {\n // Check if we've hit the offset limit\n $shouldSwitch = $state->requestCount > 0 && ($state->offset + $resultsPerPage) > PaginationConfig::TOTAL_QUERY_LIMIT;\n\n if ($shouldSwitch && $state->lastRecordId === null) {\n $this->logger->warning('[Hubspot] Cannot switch to keyset pagination: lastRecordId is null', [\n 'request_count' => $state->requestCount,\n 'current_offset' => $state->offset,\n 'results_per_page' => $resultsPerPage,\n 'total_query_limit' => PaginationConfig::TOTAL_QUERY_LIMIT,\n ]);\n\n return false; // Continue with offset pagination\n }\n\n return $shouldSwitch;\n }\n\n private function validateTokenIfNeeded(Client $client, PaginationState $state): void\n {\n if ($state->shouldValidateToken()) {\n $client->ensureValidToken();\n $state->updateLastTokenCheck();\n }\n }\n\n private function executeSearchRequest(Client $client, string $endpoint, array $payload, PaginationState $state): array\n {\n try {\n $response = $client->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n } catch (\\Exception $e) {\n if ($client->isUnauthorizedException($e)) {\n $this->logger->warning('[Hubspot] Got 401 during pagination, attempting token refresh', [\n 'team_id' => $client->getConfig()->getTeam()->getId(),\n 'error' => $e->getMessage(),\n ]);\n\n $client->ensureValidToken();\n $state->updateLastTokenCheck();\n\n try {\n $response = $client->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n $this->logger->info('[Hubspot] Token refresh and retry successful', [\n 'team_id' => $client->getConfig()->getTeam()->getId(),\n ]);\n\n return $response->toArray();\n } catch (\\Exception $retryException) {\n $this->logger->error('[Hubspot] Retry request failed after token refresh', [\n 'team_id' => $client->getConfig()->getTeam()->getId(),\n 'original_error' => $e->getMessage(),\n 'retry_error' => $retryException->getMessage(),\n ]);\n\n throw $retryException;\n }\n } else {\n throw $e;\n }\n }\n }\n\n private function updateLastRecordId(array $page, PaginationState $state): void\n {\n $lastRecord = ! empty($page['results']) ? end($page['results']) : null;\n $lastRecordId = $lastRecord['id'] ?? null;\n $state->updateLastRecordId($lastRecordId);\n }\n\n private function getNextOffset(array $page): int\n {\n return isset($page['paging']['next']['after']) ? (int) $page['paging']['next']['after'] : 0;\n }\n\n private function logPaginationProgress(PaginationState $state, int $teamId, string $endpoint): void\n {\n if ($state->shouldLogProgress()) {\n $this->logger->info('[Hubspot] Pagination progress log', [\n 'team_id' => $teamId,\n 'endpoint' => $endpoint,\n 'requests_made' => $state->requestCount,\n 'records_fetched' => $state->totalRecords,\n 'elapsed_seconds' => $state->getElapsedSeconds(),\n ]);\n }\n }\n\n private function calculateDelayInMicroseconds(): int\n {\n return (int) (1 / PaginationConfig::SEARCH_RPS_LIMIT * 1000000);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot\\Pagination;\n\nuse Jiminny\\Services\\Crm\\Hubspot\\Client;\nuse Jiminny\\Services\\Crm\\Hubspot\\PayloadBuilder;\nuse Psr\\Log\\LoggerInterface;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\n\nclass HubspotPaginationService\n{\n public function __construct(\n private LoggerInterface $logger\n ) {\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n Client $client,\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n $state = new PaginationState(offset: $offset);\n $endpoint = Client::BASE_URL . \"/crm/v3/objects/{$type}/search\";\n $defaultFilter = $payload['filters'] ?? [];\n $resultsPerPage = PayloadBuilder::MAX_SEARCH_REQUEST_LIMIT;\n $teamId = $client->getConfig()->getTeam()->getId();\n $delay = $this->calculateDelayInMicroseconds();\n\n do {\n if ($this->shouldStopPagination($state, $teamId)) {\n break;\n }\n\n $payload = $this->handlePaginationStrategy($payload, $defaultFilter, $state, $resultsPerPage, $teamId);\n\n $this->validateTokenIfNeeded($client, $state);\n usleep($delay);\n\n $page = $this->executeSearchRequest($client, $endpoint, $payload, $state);\n\n $state->setTotal($page['total'] ?? 0);\n $this->updateLastRecordId($page, $state);\n\n // Safely iterate over results with null check\n $results = $page['results'] ?? [];\n foreach ($results as $row) {\n $state->incrementTotalRecords();\n yield $row;\n }\n\n $state->setOffset($this->getNextOffset($page));\n $state->incrementRequestCount();\n\n $this->logPaginationProgress($state, $teamId, $endpoint);\n } while ($state->offset && ! empty($page['results']));\n\n // Log final pagination completion stats\n $this->logger->info('[Hubspot] Pagination completed', [\n 'team_id' => $teamId,\n 'endpoint' => $endpoint,\n 'total_requests' => $state->requestCount,\n 'total_records_fetched' => $state->totalRecords,\n 'total_elapsed_seconds' => round($state->getElapsedSeconds(), 2),\n 'average_seconds_per_request' => $state->requestCount > 0 ? round($state->getElapsedSeconds() / $state->requestCount, 2) : 0,\n ]);\n\n // Update reference parameters\n $total = $state->total;\n $lastRecordId = $state->lastRecordId;\n }\n\n private function shouldStopPagination(PaginationState $state, int $teamId): bool\n {\n if ($state->hasReachedSafetyLimit()) {\n $this->logger->warning('[Hubspot] Reached maximum request limit during pagination', [\n 'team_id' => $teamId,\n 'safety_limit' => PaginationConfig::LOOP_SAFETY_LIMIT,\n 'total_fetched' => $state->totalRecords,\n ]);\n\n return true;\n }\n\n return false;\n }\n\n private function handlePaginationStrategy(\n array $payload,\n array $defaultFilter,\n PaginationState $state,\n int $resultsPerPage,\n int $teamId\n ): array {\n if ($this->shouldSwitchToKeysetPagination($state, $resultsPerPage)) {\n $payload['filters'] = $defaultFilter;\n $payload['filters'][] = [\n 'propertyName' => 'hs_object_id',\n 'operator' => 'LT',\n 'value' => $state->lastRecordId,\n ];\n\n $this->logger->info('[Hubspot] Search keyset pagination request', [\n 'team_id' => $teamId,\n 'sequence' => $state->requestCount,\n 'itemsPerPage' => $resultsPerPage,\n 'payload' => $payload,\n 'total' => $state->total,\n ]);\n\n unset($payload['after']);\n $state->setOffset(0);\n }\n\n if ($state->offset) {\n $payload['after'] = $state->offset;\n }\n\n return $payload;\n }\n\n private function shouldSwitchToKeysetPagination(PaginationState $state, int $resultsPerPage): bool\n {\n // Check if we've hit the offset limit\n $shouldSwitch = $state->requestCount > 0 && ($state->offset + $resultsPerPage) > PaginationConfig::TOTAL_QUERY_LIMIT;\n\n if ($shouldSwitch && $state->lastRecordId === null) {\n $this->logger->warning('[Hubspot] Cannot switch to keyset pagination: lastRecordId is null', [\n 'request_count' => $state->requestCount,\n 'current_offset' => $state->offset,\n 'results_per_page' => $resultsPerPage,\n 'total_query_limit' => PaginationConfig::TOTAL_QUERY_LIMIT,\n ]);\n\n return false; // Continue with offset pagination\n }\n\n return $shouldSwitch;\n }\n\n private function validateTokenIfNeeded(Client $client, PaginationState $state): void\n {\n if ($state->shouldValidateToken()) {\n $client->ensureValidToken();\n $state->updateLastTokenCheck();\n }\n }\n\n private function executeSearchRequest(Client $client, string $endpoint, array $payload, PaginationState $state): array\n {\n try {\n $response = $client->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n } catch (\\Exception $e) {\n if ($client->isUnauthorizedException($e)) {\n $this->logger->warning('[Hubspot] Got 401 during pagination, attempting token refresh', [\n 'team_id' => $client->getConfig()->getTeam()->getId(),\n 'error' => $e->getMessage(),\n ]);\n\n $client->ensureValidToken();\n $state->updateLastTokenCheck();\n\n try {\n $response = $client->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n $this->logger->info('[Hubspot] Token refresh and retry successful', [\n 'team_id' => $client->getConfig()->getTeam()->getId(),\n ]);\n\n return $response->toArray();\n } catch (\\Exception $retryException) {\n $this->logger->error('[Hubspot] Retry request failed after token refresh', [\n 'team_id' => $client->getConfig()->getTeam()->getId(),\n 'original_error' => $e->getMessage(),\n 'retry_error' => $retryException->getMessage(),\n ]);\n\n throw $retryException;\n }\n } else {\n throw $e;\n }\n }\n }\n\n private function updateLastRecordId(array $page, PaginationState $state): void\n {\n $lastRecord = ! empty($page['results']) ? end($page['results']) : null;\n $lastRecordId = $lastRecord['id'] ?? null;\n $state->updateLastRecordId($lastRecordId);\n }\n\n private function getNextOffset(array $page): int\n {\n return isset($page['paging']['next']['after']) ? (int) $page['paging']['next']['after'] : 0;\n }\n\n private function logPaginationProgress(PaginationState $state, int $teamId, string $endpoint): void\n {\n if ($state->shouldLogProgress()) {\n $this->logger->info('[Hubspot] Pagination progress log', [\n 'team_id' => $teamId,\n 'endpoint' => $endpoint,\n 'requests_made' => $state->requestCount,\n 'records_fetched' => $state->totalRecords,\n 'elapsed_seconds' => $state->getElapsedSeconds(),\n ]);\n }\n }\n\n private function calculateDelayInMicroseconds(): int\n {\n return (int) (1 / PaginationConfig::SEARCH_RPS_LIMIT * 1000000);\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":"AXStaticText","text":"2","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\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\EmailHelper;\nuse Throwable;\n\nclass FixActivitiesOpportunity extends Command\n{\n protected $signature = 'activity:fix-opportunity {--from=} {--to=}';\n\n public function handle(EmailHelper $emailHelper): int\n {\n $from = $this->option('from');\n $to = $this->option('to');\n\n $validator = Validator::make(\n ['from' => $from, 'to' => $to],\n [\n 'from' => ['required', 'date'],\n 'to' => ['required', 'date'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return Command::FAILURE;\n }\n\n $this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);\n\n $activityIds = Activity::select('activities.id')\n ->whereBetween('activities.created_at', [$from, $to])\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')\n ->whereColumn('opportunities.team_id', '<>', 'users.team_id')\n ->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n\n foreach ($activityIds as $activityId) {\n $activity = Activity::where('id', $activityId)\n ->with(['user', 'participants'])\n ->first();\n\n $crmService = $this->getCrmService($activity->getTeam());\n if ($crmService === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $this->processParticipants($crmService, $emailHelper, $activity);\n }\n\n return Command::SUCCESS;\n }\n\n private function getCrmService(Team $team): ?ServiceInterface\n {\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n try {\n return $crmResolver->prepareCrmService();\n } catch (Throwable $e) {\n $this->error('Could not prepare CRM service: ' . $e->getMessage());\n\n return null;\n }\n }\n\n private function processParticipants(\n ServiceInterface $crmService,\n EmailHelper $emailHelper,\n Activity $activity\n ): void {\n $team = $activity->getTeam();\n $user = $activity->getUser();\n $participants = $activity->getParticipants();\n\n foreach ($participants as $participant) {\n if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {\n continue;\n }\n\n $emailAddress = $participant->getEmailAddress();\n if ($emailHelper->isCompanyEmail($team, $emailAddress)) {\n continue;\n }\n\n try {\n $opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());\n } catch (Throwable $e) {\n $this->error('Could not find opportunity: ' . $e->getMessage());\n\n $opportunity = null;\n }\n\n if ($opportunity === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $activity->update(['opportunity_id' => $opportunity->getId()]);\n\n $this->info('Opportunity updated for activity: ' . $activity->getId());\n }\n }\n\n private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity\n {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n $match = $decorator->matchExactlyByEmail($emailAddress, $userId);\n\n if (empty($match)) {\n $match = $decorator->matchByDomain($emailAddress, $userId);\n }\n\n if (empty($match)) {\n return null;\n }\n\n [, , $opportunity, ,] = $match;\n\n return $opportunity;\n }\n\n private function resetActivityOpportunity(Activity $activity): void\n {\n $this->info('Reset opportunity for activity: ' . $activity->getId());\n $activity->update(['opportunity_id' => null]);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Console\\Commands\\Activities;\n\nuse Illuminate\\Support\\Facades\\Validator;\nuse Jiminny\\Console\\Commands\\Command;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Crm\\CachedCrmServiceDecorator;\nuse Jiminny\\Services\\Crm\\EmailHelper;\nuse Throwable;\n\nclass FixActivitiesOpportunity extends Command\n{\n protected $signature = 'activity:fix-opportunity {--from=} {--to=}';\n\n public function handle(EmailHelper $emailHelper): int\n {\n $from = $this->option('from');\n $to = $this->option('to');\n\n $validator = Validator::make(\n ['from' => $from, 'to' => $to],\n [\n 'from' => ['required', 'date'],\n 'to' => ['required', 'date'],\n ]\n );\n\n if ($validator->fails()) {\n $this->error('Validation failed:');\n $this->output->block($validator->errors()->all());\n\n return Command::FAILURE;\n }\n\n $this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);\n\n $activityIds = Activity::select('activities.id')\n ->whereBetween('activities.created_at', [$from, $to])\n ->join('users', 'activities.user_id', '=', 'users.id')\n ->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')\n ->whereColumn('opportunities.team_id', '<>', 'users.team_id')\n ->pluck('id');\n\n $this->info('Found activities: ' . $activityIds->count());\n\n foreach ($activityIds as $activityId) {\n $activity = Activity::where('id', $activityId)\n ->with(['user', 'participants'])\n ->first();\n\n $crmService = $this->getCrmService($activity->getTeam());\n if ($crmService === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $this->processParticipants($crmService, $emailHelper, $activity);\n }\n\n return Command::SUCCESS;\n }\n\n private function getCrmService(Team $team): ?ServiceInterface\n {\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n try {\n return $crmResolver->prepareCrmService();\n } catch (Throwable $e) {\n $this->error('Could not prepare CRM service: ' . $e->getMessage());\n\n return null;\n }\n }\n\n private function processParticipants(\n ServiceInterface $crmService,\n EmailHelper $emailHelper,\n Activity $activity\n ): void {\n $team = $activity->getTeam();\n $user = $activity->getUser();\n $participants = $activity->getParticipants();\n\n foreach ($participants as $participant) {\n if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {\n continue;\n }\n\n $emailAddress = $participant->getEmailAddress();\n if ($emailHelper->isCompanyEmail($team, $emailAddress)) {\n continue;\n }\n\n try {\n $opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());\n } catch (Throwable $e) {\n $this->error('Could not find opportunity: ' . $e->getMessage());\n\n $opportunity = null;\n }\n\n if ($opportunity === null) {\n $this->resetActivityOpportunity($activity);\n\n continue;\n }\n\n $activity->update(['opportunity_id' => $opportunity->getId()]);\n\n $this->info('Opportunity updated for activity: ' . $activity->getId());\n }\n }\n\n private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity\n {\n $decorator = resolve(CachedCrmServiceDecorator::class);\n $decorator->setCrmService($crmService);\n\n $match = $decorator->matchExactlyByEmail($emailAddress, $userId);\n\n if (empty($match)) {\n $match = $decorator->matchByDomain($emailAddress, $userId);\n }\n\n if (empty($match)) {\n return null;\n }\n\n [, , $opportunity, ,] = $match;\n\n return $opportunity;\n }\n\n private function resetActivityOpportunity(Activity $activity): void\n {\n $this->info('Reset opportunity for activity: ' . $activity->getId());\n $activity->update(['opportunity_id' => null]);\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}]...
|
-7245130343451937535
|
2318460834565305250
|
click
|
accessibility
|
NULL
|
1 file committed
JY-20903 revert changes in comman 1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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
12
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot\Pagination;
use Jiminny\Services\Crm\Hubspot\Client;
use Jiminny\Services\Crm\Hubspot\PayloadBuilder;
use Psr\Log\LoggerInterface;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
class HubspotPaginationService
{
public function __construct(
private LoggerInterface $logger
) {
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
Client $client,
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
$state = new PaginationState(offset: $offset);
$endpoint = Client::BASE_URL . "/crm/v3/objects/{$type}/search";
$defaultFilter = $payload['filters'] ?? [];
$resultsPerPage = PayloadBuilder::MAX_SEARCH_REQUEST_LIMIT;
$teamId = $client->getConfig()->getTeam()->getId();
$delay = $this->calculateDelayInMicroseconds();
do {
if ($this->shouldStopPagination($state, $teamId)) {
break;
}
$payload = $this->handlePaginationStrategy($payload, $defaultFilter, $state, $resultsPerPage, $teamId);
$this->validateTokenIfNeeded($client, $state);
usleep($delay);
$page = $this->executeSearchRequest($client, $endpoint, $payload, $state);
$state->setTotal($page['total'] ?? 0);
$this->updateLastRecordId($page, $state);
// Safely iterate over results with null check
$results = $page['results'] ?? [];
foreach ($results as $row) {
$state->incrementTotalRecords();
yield $row;
}
$state->setOffset($this->getNextOffset($page));
$state->incrementRequestCount();
$this->logPaginationProgress($state, $teamId, $endpoint);
} while ($state->offset && ! empty($page['results']));
// Log final pagination completion stats
$this->logger->info('[Hubspot] Pagination completed', [
'team_id' => $teamId,
'endpoint' => $endpoint,
'total_requests' => $state->requestCount,
'total_records_fetched' => $state->totalRecords,
'total_elapsed_seconds' => round($state->getElapsedSeconds(), 2),
'average_seconds_per_request' => $state->requestCount > 0 ? round($state->getElapsedSeconds() / $state->requestCount, 2) : 0,
]);
// Update reference parameters
$total = $state->total;
$lastRecordId = $state->lastRecordId;
}
private function shouldStopPagination(PaginationState $state, int $teamId): bool
{
if ($state->hasReachedSafetyLimit()) {
$this->logger->warning('[Hubspot] Reached maximum request limit during pagination', [
'team_id' => $teamId,
'safety_limit' => PaginationConfig::LOOP_SAFETY_LIMIT,
'total_fetched' => $state->totalRecords,
]);
return true;
}
return false;
}
private function handlePaginationStrategy(
array $payload,
array $defaultFilter,
PaginationState $state,
int $resultsPerPage,
int $teamId
): array {
if ($this->shouldSwitchToKeysetPagination($state, $resultsPerPage)) {
$payload['filters'] = $defaultFilter;
$payload['filters'][] = [
'propertyName' => 'hs_object_id',
'operator' => 'LT',
'value' => $state->lastRecordId,
];
$this->logger->info('[Hubspot] Search keyset pagination request', [
'team_id' => $teamId,
'sequence' => $state->requestCount,
'itemsPerPage' => $resultsPerPage,
'payload' => $payload,
'total' => $state->total,
]);
unset($payload['after']);
$state->setOffset(0);
}
if ($state->offset) {
$payload['after'] = $state->offset;
}
return $payload;
}
private function shouldSwitchToKeysetPagination(PaginationState $state, int $resultsPerPage): bool
{
// Check if we've hit the offset limit
$shouldSwitch = $state->requestCount > 0 && ($state->offset + $resultsPerPage) > PaginationConfig::TOTAL_QUERY_LIMIT;
if ($shouldSwitch && $state->lastRecordId === null) {
$this->logger->warning('[Hubspot] Cannot switch to keyset pagination: lastRecordId is null', [
'request_count' => $state->requestCount,
'current_offset' => $state->offset,
'results_per_page' => $resultsPerPage,
'total_query_limit' => PaginationConfig::TOTAL_QUERY_LIMIT,
]);
return false; // Continue with offset pagination
}
return $shouldSwitch;
}
private function validateTokenIfNeeded(Client $client, PaginationState $state): void
{
if ($state->shouldValidateToken()) {
$client->ensureValidToken();
$state->updateLastTokenCheck();
}
}
private function executeSearchRequest(Client $client, string $endpoint, array $payload, PaginationState $state): array
{
try {
$response = $client->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
} catch (\Exception $e) {
if ($client->isUnauthorizedException($e)) {
$this->logger->warning('[Hubspot] Got 401 during pagination, attempting token refresh', [
'team_id' => $client->getConfig()->getTeam()->getId(),
'error' => $e->getMessage(),
]);
$client->ensureValidToken();
$state->updateLastTokenCheck();
try {
$response = $client->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
$this->logger->info('[Hubspot] Token refresh and retry successful', [
'team_id' => $client->getConfig()->getTeam()->getId(),
]);
return $response->toArray();
} catch (\Exception $retryException) {
$this->logger->error('[Hubspot] Retry request failed after token refresh', [
'team_id' => $client->getConfig()->getTeam()->getId(),
'original_error' => $e->getMessage(),
'retry_error' => $retryException->getMessage(),
]);
throw $retryException;
}
} else {
throw $e;
}
}
}
private function updateLastRecordId(array $page, PaginationState $state): void
{
$lastRecord = ! empty($page['results']) ? end($page['results']) : null;
$lastRecordId = $lastRecord['id'] ?? null;
$state->updateLastRecordId($lastRecordId);
}
private function getNextOffset(array $page): int
{
return isset($page['paging']['next']['after']) ? (int) $page['paging']['next']['after'] : 0;
}
private function logPaginationProgress(PaginationState $state, int $teamId, string $endpoint): void
{
if ($state->shouldLogProgress()) {
$this->logger->info('[Hubspot] Pagination progress log', [
'team_id' => $teamId,
'endpoint' => $endpoint,
'requests_made' => $state->requestCount,
'records_fetched' => $state->totalRecords,
'elapsed_seconds' => $state->getElapsedSeconds(),
]);
}
}
private function calculateDelayInMicroseconds(): int
{
return (int) (1 / PaginationConfig::SEARCH_RPS_LIMIT * 1000000);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands\Activities;
use Illuminate\Support\Facades\Validator;
use Jiminny\Console\Commands\Command;
use Jiminny\Contracts\Services\Crm\ServiceInterface;
use Jiminny\Models\Activity;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Crm\CachedCrmServiceDecorator;
use Jiminny\Services\Crm\EmailHelper;
use Throwable;
class FixActivitiesOpportunity extends Command
{
protected $signature = 'activity:fix-opportunity {--from=} {--to=}';
public function handle(EmailHelper $emailHelper): int
{
$from = $this->option('from');
$to = $this->option('to');
$validator = Validator::make(
['from' => $from, 'to' => $to],
[
'from' => ['required', 'date'],
'to' => ['required', 'date'],
]
);
if ($validator->fails()) {
$this->error('Validation failed:');
$this->output->block($validator->errors()->all());
return Command::FAILURE;
}
$this->info('Fixing opportunity for activities from ' . $from . ' to ' . $to);
$activityIds = Activity::select('activities.id')
->whereBetween('activities.created_at', [$from, $to])
->join('users', 'activities.user_id', '=', 'users.id')
->join('opportunities', 'activities.opportunity_id', '=', 'opportunities.id')
->whereColumn('opportunities.team_id', '<>', 'users.team_id')
->pluck('id');
$this->info('Found activities: ' . $activityIds->count());
foreach ($activityIds as $activityId) {
$activity = Activity::where('id', $activityId)
->with(['user', 'participants'])
->first();
$crmService = $this->getCrmService($activity->getTeam());
if ($crmService === null) {
$this->resetActivityOpportunity($activity);
continue;
}
$this->processParticipants($crmService, $emailHelper, $activity);
}
return Command::SUCCESS;
}
private function getCrmService(Team $team): ?ServiceInterface
{
$config = $team->getCrmConfiguration();
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $team->getOwner(),
'providerSlug' => $config->getProviderName(),
]);
try {
return $crmResolver->prepareCrmService();
} catch (Throwable $e) {
$this->error('Could not prepare CRM service: ' . $e->getMessage());
return null;
}
}
private function processParticipants(
ServiceInterface $crmService,
EmailHelper $emailHelper,
Activity $activity
): void {
$team = $activity->getTeam();
$user = $activity->getUser();
$participants = $activity->getParticipants();
foreach ($participants as $participant) {
if ($participant->getUserId() !== null || $participant->getEmailAddress() === null) {
continue;
}
$emailAddress = $participant->getEmailAddress();
if ($emailHelper->isCompanyEmail($team, $emailAddress)) {
continue;
}
try {
$opportunity = $this->findOpportunityInCrm($crmService, $emailAddress, $user->getId());
} catch (Throwable $e) {
$this->error('Could not find opportunity: ' . $e->getMessage());
$opportunity = null;
}
if ($opportunity === null) {
$this->resetActivityOpportunity($activity);
continue;
}
$activity->update(['opportunity_id' => $opportunity->getId()]);
$this->info('Opportunity updated for activity: ' . $activity->getId());
}
}
private function findOpportunityInCrm(ServiceInterface $crmService, string $emailAddress, int $userId): ?Opportunity
{
$decorator = resolve(CachedCrmServiceDecorator::class);
$decorator->setCrmService($crmService);
$match = $decorator->matchExactlyByEmail($emailAddress, $userId);
if (empty($match)) {
$match = $decorator->matchByDomain($emailAddress, $userId);
}
if (empty($match)) {
return null;
}
[, , $opportunity, ,] = $match;
return $opportunity;
}
private function resetActivityOpportunity(Activity $activity): void
{
$this->info('Reset opportunity for activity: ' . $activity->getId());
$activity->update(['opportunity_id' => null]);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
43640
|
1592
|
9
|
2026-05-14T13:03:26.621903+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778763806621_m2.jpg...
|
PhpStorm
|
faVsco.js – HubspotPaginationService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
1 file committed
JY-20903 revert changes in comman 1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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:...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"1 file committed","depth":2,"bounds":{"left":0.8753325,"top":0.91300875,"width":0.100398935,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"JY-20903 revert changes in command","depth":3,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.11037234,"height":0.013567438},"on_screen":true,"value":"JY-20903 revert changes in command","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.0787899,"height":0.013567438},"on_screen":true,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"on_screen":false,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"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":"#12077 on JY-20903-update_activity-stage-on…hange, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12566489,"height":0.025538707},"on_screen":true,"help_text":"Pull request #12077 exists for current branch JY-20903-update__activity-stage-on…hange","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}]...
|
-1307072091985428106
|
-8708621191463335486
|
click
|
hybrid
|
NULL
|
1 file committed
JY-20903 revert changes in comman 1 file committed
JY-20903 revert changes in command
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12077 on JY-20903-update_activity-stage-on…hange, 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:
PhostormcodeFV faVsco.js#12077 on JY-20903-update_activity-stage-on...hroledey) CheckAndRetryRemoteMatch.php> D OpportunitySyncStraterCo kematchactviyoncrmobjectbetach.ongC) Service.pnpo Cllentonpv D Pagination© HubspotPaginationS©Paginationcontig.on© Matchermobiect.ongm A12 ^ V• _ Prospectsearchstrateo> C Redis› use ...v W ServiceTraits• Opportunitysynctraclass HubspotPaqinationServiceT suncermEntitiestraiTSuncFieldstrait.phpTWritecrmtrait.php→DUusWeohookC BatchSvncCollector.ohrC) BatchSvncRedisServicel© Client.phpC) ClosedDealStadesServi@ DealFieldsService.phpC) DecorateActivitv nhoC) SieldDefinitions nhnC) FieldTvoeConverter.ong0 HubsnotClientinterfaco(e) HubsnotTokenManager(e) DavloadBuilder.ono© RemoteCrmObjectMani€ ResponseNormalize.ph:© Service.php© SyncFieldAction.php© SyncRelatedActivityMac WebhooksyncBatchProv D IntegrationApp> ( Accessors.> M Api• Contio• GoтO.M.Jobs> ProspectSearchStrateg 104> MServiceTraitsC) Dataclient.ohnC) DecorateActivitv. ohnC) Loca|Search.nhn |@ LocalSearchinterface.nl 151© RemoteSearch.phpC) Service nhnv MlistenersC Convortl ondActivitioc re Duraol aokunGacho nhr 140l• MMotadata• MMiarationpublic function -_constructprivate LoggerInterface SLogger* athrows HubsnotExceot.ion*@throws SocialAccountTokeninvalidExcent.ion* Othrows. BadRequest13 usagespublic function getPaginatedDataGeneratorCClient Sclientarray spayload,string suype.int Soffset = 0int &$total = 0?string &$lastRecordId = null): \Generator {.private function shouldStopPagination(PaqinationState $state, int SteamId): boolf...}PaginationState Sstate.int SresultsPerPage.iarray s...private function shouldSwitchToKeysetPagination(PaginationState $state, int SresultsPerPage): boolf...}nnivate function validateTokenTfNeedediClient Sclient PadinationState Sstate)• void ..private function executeSearchRequest(Client Sclient, string $endpoint, array Spayload, PaginationState $sDuched 1 commit to oriain/IV.20902-undate activitv-ctaae-on-onnortunitvcchande /| View null requect (1 minutes aao)= custom.log= laravel.logA SF jiminny@localhost]& ho_local Uiminny@localnost& console [PROD]A console (EU]tiò accounts [EU]fii stages (EU]iiò teams [EU]ImporbotkecoraingJoo.pnp© Activity.php© FixActivitiesOpportunity.php& console SlAGiNGclass rixacciviclesupoorcunlcy excenas commanaT106:10811131116tunccion processrarclcloantsSteam = Sactivity->qetTeamosuser = sactivitv->qetuserossoarticioants=sactivitv->oetparticioantsorforeach (Sparticioants as Soarticioant) <if ($participant->getUserId() |== null || $participant->getEmailAddress() === null) {continue:SemailAddness = Snanticinant->ae+FmailAddnecso•if (SemailHelper->isCompanyEmail(Steam, $emailAddress)) {continue.try fSopportunity = $this->find0pportunityInCrm($crmService, SemailAddress, Suser->getId);} catch (Throwable $e) {$this->error( string: 'Could not find opportunity: ' . $e->getMessage());Sopportunity = nullif (Sopportunity === null) {Sthis->resetActivity0pportunitv(Sactivitv):cascadePipedrive SDK EvaluaActivity Stage Discrer40 hl100% S2• Thu 14 May 16:03:26AskJiminnyReportActivityServiceTest vImport CRM Activity T+0 ..m 82^Cascade Code x .Kick off a new project. Make changesacross your entire codedaseSactivity->update(['opportunity id' => Sopportunitv->qetldO1):Sthis->info( string: 'Opportunity updated for activity: ' • Sactivity->getidO):128Tusageprivate function findOpportunityInCrm(ServiceInterface $crmService, string SemailAddress, int $userId): ?Opportuniprivate function resetActivity0pportunity(Activity Sactivity): void{...}@, Activity Stage Discrepancy Analysis• Your included weekly usage quota is exhausted. Purchase extra usage to continue using premium models. Quota resets May 17, 11:00 x# 1 file committedwhere isJY-20903 revert changes in command÷ @Code SWF-1.6Edit Commit Messaae.WN Windsurf Toams 26.21UTF.8io 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|