|
40791
|
NULL
|
0
|
2026-05-14T09:20:53.252970+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750453252_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
FirefoxFileEditViewHistoryBookmarksProfilesCTools FirefoxFileEditViewHistoryBookmarksProfilesCTools WindowHelpmeet.google.com/mie-gawc-dsi?authuser=lukas.kovalik%40jiminny.com>0 lhl • | Daily - Platform - now+100% <478•Thu 14 May 9:45:36...
|
NULL
|
-708492635982512963
|
NULL
|
idle
|
ocr
|
NULL
|
FirefoxFileEditViewHistoryBookmarksProfilesCTools FirefoxFileEditViewHistoryBookmarksProfilesCTools WindowHelpmeet.google.com/mie-gawc-dsi?authuser=lukas.kovalik%40jiminny.com>0 lhl • | Daily - Platform - now+100% <478•Thu 14 May 9:45:36...
|
40787
|
NULL
|
NULL
|
NULL
|
|
40792
|
1508
|
0
|
2026-05-14T09:21:15.232795+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750475232_m2.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
slackw Usage | Windsurf• JY-20891 add support for slackw Usage | Windsurf• JY-20891 add support for second:[SRD-6848] Sidekick SMS issue -Platform Sprint 4 Q2 - Platform TeDependabot alerts • jiminny/proph(JY-19958] Upgrade BE librariesWY-20773) User Pilot not receivini( JY-19957 | Remove abanded sympTypeError: Leaque|Flysystem\Files1. Userpilot I Ask Jiminny Report Gen[JY-19957] Upgrade BE libraries -Dependabot alerts - iminny/app11Y-208011 Sidekick SMS iccue -[SRD-6849] Recorded call does n8 Jiminnv8 Jiminny8 Jiminny* Configure SSH access to multiple≥ Useful conDev Tools - ElasticJiminny-7 (SRD-68531 Moxso - Potential des& CloudWatch I eu-west-1CloudWatch | eu-west-1Platform Sorint 4 02 - Platform TeJY-20891 add support for secondaService-Desk - Queues - Platfc XIL Now TohMIStOMwindowhelg1y.dulasslan.nelIld/servicedesk/oroeeJ JIMINNYg For you(• RecentSpaces / Service-Desk / QueuesPlatform team* Starred0+ Apps|:= ListQ SpacesQ Search workJiminny (New)s work lems14 Service-DeskKeyE QueuesSRD-6853Team Priority|©, All open tickets 12SRD-68495 Unassigned t... 3Ej Support tea….SpN-69A9•, Raised by meE Assigned to ..Ej Service requ..E Plattorm teamE Processing t...Ej Site reliability... 0•, New features... 0bi InfoSec issues 0j Ready for Cu... 0•1 Resolved ti….. 999+= View all queuesF Service requestsA IncidentsHl ReportsC Operations• Knowledae Base0 Customers• Channolel• Email loasI< Develoner escalationsl: Slack integration< Reporting Center• Search IRequest tvpe vStatus vAssianee vSummaryMoxso - Potential deal stages bugkecorded call does not aobear on the casnooaroSidekick SMS issueMore tilters vPriority levelP2 MediumPe MediumP2 MediumHomeDMSActivityLateMoreJiminny...yS Starred8 jiminny-x-integrati…..•olattorm-inner-teamE) Channels# ai-chapter# alerts# backend# bugs# confusion-clinid# curiosity lab# engineering# general# jiminny-bg# platform-tickets# product launches# randomi released# sofia-officea suodort# thank-yous# the people of iimi..A Direct messages• Vasil VasilevM Stefka StovanovaMario GeorgievNikolav Ivanovo James Graham8 Stovan Tanev© Galva DimitrovaStelivan Georgiey( Petko KashinskiR Aneliva Angelova EFa Lukas Kovali#: AppsS lira GloudToastm) Google Cale!YDally - Plau100% 1∞' Inu 14 May 9:40:30@ Describe what you are looking for& e. Vasil Vasilev• MessagestAdd canvas( FilesX Pins+1 new messageVasil Vasilley 9.39 AMIдобро утровчера забравих за тебопоави ли се с инлексите, или оше ти липоват ланнииначе имах прелвлиmake docker-updateи реоилдване на локалните контеинерипри мен преди време се бе случило така, че не върваха процесите за индексиране, понеже es-update-worker-а лиспвашеа пьк менажирането на тея процеси от scheduler беше спряноLukas Kovalik 9:42 AMоправих се, но трябваше да пипна команда ще намираше грешно активитиVasi Vasiley 9•43 AMкакьв беше точно проблема всъшност?Lukas Kovalik # 9:43 AMiny# php artisan activity:update:es 422003rouna aeloieysu.s, u. уooовасато 5аоeesending activity tor ts update..Done.това е вече с повече логове422003 -> 16трябва да го видя ощеVasil Vasiley 9:44 ANSactivity = Activity::id0rUuId(SactivityId)->firstO;това е пооблема.Lukas Kovalik 9:44.AMVasil Vasilev 9:44 AMActivity:.dOrludsactivitvicheтова само по себе си връша правилния моделобаче като извикаш върху Activity инстанция допълнтиелно ->first()бюка чаново в базата и рзима пиориа спошнат запискоито винаги в най ниското И ліMessage Vasil Vasilev+ Аal...
|
NULL
|
8912455784959274687
|
NULL
|
click
|
ocr
|
NULL
|
slackw Usage | Windsurf• JY-20891 add support for slackw Usage | Windsurf• JY-20891 add support for second:[SRD-6848] Sidekick SMS issue -Platform Sprint 4 Q2 - Platform TeDependabot alerts • jiminny/proph(JY-19958] Upgrade BE librariesWY-20773) User Pilot not receivini( JY-19957 | Remove abanded sympTypeError: Leaque|Flysystem\Files1. Userpilot I Ask Jiminny Report Gen[JY-19957] Upgrade BE libraries -Dependabot alerts - iminny/app11Y-208011 Sidekick SMS iccue -[SRD-6849] Recorded call does n8 Jiminnv8 Jiminny8 Jiminny* Configure SSH access to multiple≥ Useful conDev Tools - ElasticJiminny-7 (SRD-68531 Moxso - Potential des& CloudWatch I eu-west-1CloudWatch | eu-west-1Platform Sorint 4 02 - Platform TeJY-20891 add support for secondaService-Desk - Queues - Platfc XIL Now TohMIStOMwindowhelg1y.dulasslan.nelIld/servicedesk/oroeeJ JIMINNYg For you(• RecentSpaces / Service-Desk / QueuesPlatform team* Starred0+ Apps|:= ListQ SpacesQ Search workJiminny (New)s work lems14 Service-DeskKeyE QueuesSRD-6853Team Priority|©, All open tickets 12SRD-68495 Unassigned t... 3Ej Support tea….SpN-69A9•, Raised by meE Assigned to ..Ej Service requ..E Plattorm teamE Processing t...Ej Site reliability... 0•, New features... 0bi InfoSec issues 0j Ready for Cu... 0•1 Resolved ti….. 999+= View all queuesF Service requestsA IncidentsHl ReportsC Operations• Knowledae Base0 Customers• Channolel• Email loasI< Develoner escalationsl: Slack integration< Reporting Center• Search IRequest tvpe vStatus vAssianee vSummaryMoxso - Potential deal stages bugkecorded call does not aobear on the casnooaroSidekick SMS issueMore tilters vPriority levelP2 MediumPe MediumP2 MediumHomeDMSActivityLateMoreJiminny...yS Starred8 jiminny-x-integrati…..•olattorm-inner-teamE) Channels# ai-chapter# alerts# backend# bugs# confusion-clinid# curiosity lab# engineering# general# jiminny-bg# platform-tickets# product launches# randomi released# sofia-officea suodort# thank-yous# the people of iimi..A Direct messages• Vasil VasilevM Stefka StovanovaMario GeorgievNikolav Ivanovo James Graham8 Stovan Tanev© Galva DimitrovaStelivan Georgiey( Petko KashinskiR Aneliva Angelova EFa Lukas Kovali#: AppsS lira GloudToastm) Google Cale!YDally - Plau100% 1∞' Inu 14 May 9:40:30@ Describe what you are looking for& e. Vasil Vasilev• MessagestAdd canvas( FilesX Pins+1 new messageVasil Vasilley 9.39 AMIдобро утровчера забравих за тебопоави ли се с инлексите, или оше ти липоват ланнииначе имах прелвлиmake docker-updateи реоилдване на локалните контеинерипри мен преди време се бе случило така, че не върваха процесите за индексиране, понеже es-update-worker-а лиспвашеа пьк менажирането на тея процеси от scheduler беше спряноLukas Kovalik 9:42 AMоправих се, но трябваше да пипна команда ще намираше грешно активитиVasi Vasiley 9•43 AMкакьв беше точно проблема всъшност?Lukas Kovalik # 9:43 AMiny# php artisan activity:update:es 422003rouna aeloieysu.s, u. уooовасато 5аоeesending activity tor ts update..Done.това е вече с повече логове422003 -> 16трябва да го видя ощеVasil Vasiley 9:44 ANSactivity = Activity::id0rUuId(SactivityId)->firstO;това е пооблема.Lukas Kovalik 9:44.AMVasil Vasilev 9:44 AMActivity:.dOrludsactivitvicheтова само по себе си връша правилния моделобаче като извикаш върху Activity инстанция допълнтиелно ->first()бюка чаново в базата и рзима пиориа спошнат запискоито винаги в най ниското И ліMessage Vasil Vasilev+ Аal...
|
40788
|
NULL
|
NULL
|
NULL
|
|
40793
|
1507
|
0
|
2026-05-14T09:21:15.246254+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750475246_m1.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
FirefoxFileEditViewHistoryBookmarksProfilesCTools FirefoxFileEditViewHistoryBookmarksProfilesCTools WindowHelpmeet.google.com/mie-gawc-dsi?authuser=lukas.kovalik%40jiminny.com>0 lhl • | Daily - Platform - now+100% <478•Thu 14 May 9:45:36...
|
NULL
|
-708492635982512963
|
NULL
|
click
|
ocr
|
NULL
|
FirefoxFileEditViewHistoryBookmarksProfilesCTools FirefoxFileEditViewHistoryBookmarksProfilesCTools WindowHelpmeet.google.com/mie-gawc-dsi?authuser=lukas.kovalik%40jiminny.com>0 lhl • | Daily - Platform - now+100% <478•Thu 14 May 9:45:36...
|
40787
|
NULL
|
NULL
|
NULL
|
|
40794
|
1508
|
1
|
2026-05-14T09:21:18.751528+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750478751_m2.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
slackw Usage | Windsurf• JY-20891 add support for slackw Usage | Windsurf• JY-20891 add support for second:[SRD-6848] Sidekick SMS issue -Platform Sprint 4 Q2 - Platform TeDependabot alerts • jiminny/proph(JY-19958] Upgrade BE librariesWY-20773) User Pilot not receivini( JY-19957 | Remove abanded sympTypeError: Leaque|Flysystem\Files1. Userpilot I Ask Jiminny Report Gen[JY-19957] Upgrade BE libraries -Dependabot alerts - iminny/app11Y-208011 Sidekick SMS iccue -[SRD-6849] Recorded call does n8 Jiminnv8 Jiminny8 Jiminny* Configure SSH access to multiple≥ Useful conDev Tools - ElasticJiminny-7 (SRD-68531 Moxso - Potential des& CloudWatch I eu-west-1CloudWatch | eu-west-1Platform Sorint 4 02 - Platform TeJY-20891 add support for secondaService-Desk - Queues - Platfc XIL Now TohMIStOMwindowhelg1y.dulasslan.nelIld/servicedesk/oroeeJ JIMINNYg For you(• RecentSpaces / Service-Desk / QueuesPlatform team* Starred0+ Apps|:= ListQ SpacesQ Search workJiminny (New)s work lems14 Service-DeskKeyE QueuesSRD-6853Team Priority|©, All open tickets 12SRD-68495 Unassigned t... 3Ej Support tea….SpN-69A9•, Raised by meE Assigned to ..Ej Service requ..E Plattorm teamE Processing t...Ej Site reliability... 0•, New features... 0bi InfoSec issues 0j Ready for Cu... 0•1 Resolved ti….. 999+= View all queuesF Service requestsA IncidentsHl ReportsC Operations• Knowledae Base0 Customers• Channolel• Email loasI< Develoner escalationsl: Slack integration< Reporting Center• Search IRequest tvpe vStatus vAssianee vSummaryMoxso - Potential deal stages bugkecorded call does not aobear on the casnooaroSidekick SMS issueMore tilters vPriority levelP2 MediumPe MediumP2 MediumHomeDMSActivityLateMoreJiminny...yS Starred8 jiminny-x-integrati…..•olattorm-inner-teamE) Channels# ai-chapter# alerts# backend# bugs# confusion-clinid# curiosity lab# engineering# general# jiminny-bg# platform-tickets# product launches# randomi released# sofia-officea suodort# thank-yous# the people of iimi..A Direct messages• Vasil VasilevM Stefka StovanovaMario GeorgievNikolav Ivanovo James Graham8 Stovan Tanev© Galva DimitrovaStelivan Georgiey( Petko KashinskiR Aneliva Angelova EFa Lukas Kovali#: AppsS lira GloudToastm) Google Cale!YDally - Plau100% 1∞' Inu 14 May 9:40:30@ Describe what you are looking for& e. Vasil Vasilev• MessagestAdd canvas( FilesX Pins+1 new messageVasil Vasilley 9.39 AMIдобро утровчера забравих за тебопоави ли се с инлексите, или оше ти липоват ланнииначе имах прелвлиmake docker-updateи реоилдване на локалните контеинерипри мен преди време се бе случило така, че не върваха процесите за индексиране, понеже es-update-worker-а лиспвашеа пьк менажирането на тея процеси от scheduler беше спряноLukas Kovalik 9:42 AMоправих се, но трябваше да пипна команда ще намираше грешно активитиVasi Vasiley 9•43 AMкакьв беше точно проблема всъшност?Lukas Kovalik # 9:43 AMiny# php artisan activity:update:es 422003rouna aeloieysu.s, u. уooовасато 5аоeesending activity tor ts update..Done.това е вече с повече логове422003 -> 16трябва да го видя ощеVasil Vasiley 9:44 ANSactivity = Activity::id0rUuId(SactivityId)->firstO;това е пооблема.Lukas Kovalik 9:44.AMVasil Vasilev 9:44 AMActivity:.dOrludsactivitvicheтова само по себе си връша правилния моделобаче като извикаш върху Activity инстанция допълнтиелно ->first()бюка чаново в базата и рзима пиориа спошнат запискоито винаги в най ниското И ліMessage Vasil Vasilev+ Аal...
|
NULL
|
8912455784959274687
|
NULL
|
click
|
ocr
|
NULL
|
slackw Usage | Windsurf• JY-20891 add support for slackw Usage | Windsurf• JY-20891 add support for second:[SRD-6848] Sidekick SMS issue -Platform Sprint 4 Q2 - Platform TeDependabot alerts • jiminny/proph(JY-19958] Upgrade BE librariesWY-20773) User Pilot not receivini( JY-19957 | Remove abanded sympTypeError: Leaque|Flysystem\Files1. Userpilot I Ask Jiminny Report Gen[JY-19957] Upgrade BE libraries -Dependabot alerts - iminny/app11Y-208011 Sidekick SMS iccue -[SRD-6849] Recorded call does n8 Jiminnv8 Jiminny8 Jiminny* Configure SSH access to multiple≥ Useful conDev Tools - ElasticJiminny-7 (SRD-68531 Moxso - Potential des& CloudWatch I eu-west-1CloudWatch | eu-west-1Platform Sorint 4 02 - Platform TeJY-20891 add support for secondaService-Desk - Queues - Platfc XIL Now TohMIStOMwindowhelg1y.dulasslan.nelIld/servicedesk/oroeeJ JIMINNYg For you(• RecentSpaces / Service-Desk / QueuesPlatform team* Starred0+ Apps|:= ListQ SpacesQ Search workJiminny (New)s work lems14 Service-DeskKeyE QueuesSRD-6853Team Priority|©, All open tickets 12SRD-68495 Unassigned t... 3Ej Support tea….SpN-69A9•, Raised by meE Assigned to ..Ej Service requ..E Plattorm teamE Processing t...Ej Site reliability... 0•, New features... 0bi InfoSec issues 0j Ready for Cu... 0•1 Resolved ti….. 999+= View all queuesF Service requestsA IncidentsHl ReportsC Operations• Knowledae Base0 Customers• Channolel• Email loasI< Develoner escalationsl: Slack integration< Reporting Center• Search IRequest tvpe vStatus vAssianee vSummaryMoxso - Potential deal stages bugkecorded call does not aobear on the casnooaroSidekick SMS issueMore tilters vPriority levelP2 MediumPe MediumP2 MediumHomeDMSActivityLateMoreJiminny...yS Starred8 jiminny-x-integrati…..•olattorm-inner-teamE) Channels# ai-chapter# alerts# backend# bugs# confusion-clinid# curiosity lab# engineering# general# jiminny-bg# platform-tickets# product launches# randomi released# sofia-officea suodort# thank-yous# the people of iimi..A Direct messages• Vasil VasilevM Stefka StovanovaMario GeorgievNikolav Ivanovo James Graham8 Stovan Tanev© Galva DimitrovaStelivan Georgiey( Petko KashinskiR Aneliva Angelova EFa Lukas Kovali#: AppsS lira GloudToastm) Google Cale!YDally - Plau100% 1∞' Inu 14 May 9:40:30@ Describe what you are looking for& e. Vasil Vasilev• MessagestAdd canvas( FilesX Pins+1 new messageVasil Vasilley 9.39 AMIдобро утровчера забравих за тебопоави ли се с инлексите, или оше ти липоват ланнииначе имах прелвлиmake docker-updateи реоилдване на локалните контеинерипри мен преди време се бе случило така, че не върваха процесите за индексиране, понеже es-update-worker-а лиспвашеа пьк менажирането на тея процеси от scheduler беше спряноLukas Kovalik 9:42 AMоправих се, но трябваше да пипна команда ще намираше грешно активитиVasi Vasiley 9•43 AMкакьв беше точно проблема всъшност?Lukas Kovalik # 9:43 AMiny# php artisan activity:update:es 422003rouna aeloieysu.s, u. уooовасато 5аоeesending activity tor ts update..Done.това е вече с повече логове422003 -> 16трябва да го видя ощеVasil Vasiley 9:44 ANSactivity = Activity::id0rUuId(SactivityId)->firstO;това е пооблема.Lukas Kovalik 9:44.AMVasil Vasilev 9:44 AMActivity:.dOrludsactivitvicheтова само по себе си връша правилния моделобаче като извикаш върху Activity инстанция допълнтиелно ->first()бюка чаново в базата и рзима пиориа спошнат запискоито винаги в най ниското И ліMessage Vasil Vasilev+ Аal...
|
40788
|
NULL
|
NULL
|
NULL
|
|
40795
|
1507
|
1
|
2026-05-14T09:21:19.931898+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750479931_m1.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, menu
Start Listening for PHP Debug Connections...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20903-update_activity-stage-on-opportunity-change, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20903-update_activity-stage-on-opportunity-change","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_expanded":false}]...
|
2309948694457577418
|
-8629521083764847645
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, menu
Start Listening for PHP Debug Connections
FirefoxFileEditViewHistoryBookmarksProfilesCTools WindowHelpmeet.google.com/mie-gawc-dsi?authuser=lukas.kovalik%40jiminny.com>0 lhl • | Daily - Platform - now+100% <478•Thu 14 May 9:45:36...
|
40787
|
NULL
|
NULL
|
NULL
|
|
40796
|
1508
|
2
|
2026-05-14T09:21:51.120145+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750511120_m2.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20903-update_activity-stage-on-opportunity-change, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12932181,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20903-update_activity-stage-on-opportunity-change","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":"1","depth":4,"bounds":{"left":0.37466756,"top":0.22426178,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.38397607,"top":0.22426178,"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.22266561,"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.22266561,"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\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-6829246039589479462
|
5524662269748952700
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}...
|
40788
|
NULL
|
NULL
|
NULL
|
|
40797
|
1507
|
2
|
2026-05-14T09:21:51.514849+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750511514_m1.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}
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(),
'stage_id' => $opportunity->getStageId(),
]);
$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":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20903-update_activity-stage-on-opportunity-change, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20903-update_activity-stage-on-opportunity-change","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":"1","depth":4,"on_screen":true,"role_description":"text"},{"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\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\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([\n 'opportunity_id' => $opportunity->getId(),\n 'stage_id' => $opportunity->getStageId(),\n ]);\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([\n 'opportunity_id' => $opportunity->getId(),\n 'stage_id' => $opportunity->getStageId(),\n ]);\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":true,"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}]...
|
2631951404533170602
|
5525541880020581932
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}
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(),
'stage_id' => $opportunity->getStageId(),
]);
$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
|
|
40798
|
1508
|
3
|
2026-05-14T09:22:21.647149+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750541647_m2.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20903-update_activity-stage-on-opportunity-change, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12932181,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20903-update_activity-stage-on-opportunity-change","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}]...
|
-3949932067310954691
|
-8204069599714235454
|
idle
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
slackw Usage | Windsurf• JY-20891 add support for second:[SRD-6848] Sidekick SMS issue -Platform Sprint 4 Q2 - Platform TeDependabot alerts • jiminny/proph(JY-19958] Upgrade BE librariesWY-20773) User Pilot not receivini( JY-19957 | Remove abanded sympTypeError: Leaque|Flysystem\Files1. Userpilot I Ask Jiminny Report Gen[JY-19957] Upgrade BE libraries -Dependabot alerts - iminny/app11Y-208011 Sidekick SMS iccue -[SRD-6849] Recorded call does n8 Jiminnv8 Jiminny8 Jiminny* Configure SSH access to multiple≥ Useful conDev Tools - ElasticJiminny-7 (SRD-68531 Moxso - Potential des& CloudWatch I eu-west-1CloudWatch | eu-west-1Platform Sorint 4 02 - Platform TeJY-20891 add support for secondaService-Desk - Queues - Platfc XIL Now TohMIStOMwindowhelg1y.dulasslan.nelIld/servicedesk/oroeeJ JIMINNYg For you(• RecentSpaces / Service-Desk / QueuesPlatform team* Starred0+ Apps|:= ListQ SpacesQ Search workJiminny (New)s work lems14 Service-DeskKeyE QueuesSRD-6853Team Priority|©, All open tickets 12SRD-68495 Unassigned t... 3Ej Support tea….SpN-69A9•, Raised by meE Assigned to ..Ej Service requ..E Plattorm teamE Processing t...Ej Site reliability... 0•, New features... 0bi InfoSec issues 0j Ready for Cu... 0•1 Resolved ti….. 999+= View all queuesF Service requestsA IncidentsHl ReportsC Operations• Knowledae Base0 Customers• Channolel• Email loasI< Develoner escalationsl: Slack integration< Reporting Center• Search IRequest tvpe vStatus vAssianee vSummaryMoxso - Potential deal stages bugkecorded call does not aobear on the casnooaroSidekick SMS issueMore tilters vPriority levelP2 MediumPe MediumP2 MediumHomeDMSActivityLateMoreJiminny...yS Starred8 jiminny-x-integrati…..•olattorm-inner-teamE) Channels# ai-chapter# alerts# backend# bugs# confusion-clinid# curiosity lab# engineering# general# jiminny-bg# platform-tickets# product launches# randomi released# sofia-officea suodort# thank-yous# the people of iimi..A Direct messages• Vasil VasilevM Stefka StovanovaMario GeorgievNikolav Ivanovo James Graham8 Stovan Tanev© Galva DimitrovaStelivan Georgiey( Petko KashinskiR Aneliva Angelova EFa Lukas Kovali#: AppsS lira GloudToastm) Google Cale!YDally - Plau100% 1∞' Inu 14 May 9:40:30@ Describe what you are looking for& e. Vasil Vasilev• MessagestAdd canvas( FilesX Pins+1 new messageVasil Vasilley 9.39 AMIдобро утровчера забравих за тебопоави ли се с инлексите, или оше ти липоват ланнииначе имах прелвлиmake docker-updateи реоилдване на локалните контеинерипри мен преди време се бе случило така, че не върваха процесите за индексиране, понеже es-update-worker-а лиспвашеа пьк менажирането на тея процеси от scheduler беше спряноLukas Kovalik 9:42 AMоправих се, но трябваше да пипна команда ще намираше грешно активитиVasi Vasiley 9•43 AMкакьв беше точно проблема всъшност?Lukas Kovalik # 9:43 AMiny# php artisan activity:update:es 422003rouna aeloieysu.s, u. уooовасато 5аоeesending activity tor ts update..Done.това е вече с повече логове422003 -> 16трябва да го видя ощеVasil Vasiley 9:44 ANSactivity = Activity::id0rUuId(SactivityId)->firstO;това е пооблема.Lukas Kovalik 9:44.AMVasil Vasilev 9:44 AMActivity:.dOrludsactivitvicheтова само по себе си връша правилния моделобаче като извикаш върху Activity инстанция допълнтиелно ->first()бюка чаново в базата и рзима пиориа спошнат запискоито винаги в най ниското И ліMessage Vasil Vasilev+ Аal...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
40799
|
1507
|
3
|
2026-05-14T09:22:21.890875+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750541890_m1.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20903-update_activity-stage-on-opportunity-change, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20903-update_activity-stage-on-opportunity-change","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}]...
|
-1752939377238947509
|
589208677557718466
|
idle
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
FirefoxFileEditViewHistoryBookmarksProfilesCTools WindowHelpmeet.google.com/mie-gawc-dsi?authuser=lukas.kovalik%40jiminny.com>0 lhl • | Daily - Platform - now+100% <478•Thu 14 May 9:45:36...
|
40797
|
NULL
|
NULL
|
NULL
|
|
40800
|
1508
|
4
|
2026-05-14T09:22:54.276401+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750574276_m2.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}
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(),
'stage_id' => $opportunity->getStageId(),
]);
$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":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20903-update_activity-stage-on-opportunity-change, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12932181,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20903-update_activity-stage-on-opportunity-change","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":"1","depth":4,"bounds":{"left":0.37466756,"top":0.22426178,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.38397607,"top":0.22426178,"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.22266561,"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.22266561,"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\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\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([\n 'opportunity_id' => $opportunity->getId(),\n 'stage_id' => $opportunity->getStageId(),\n ]);\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([\n 'opportunity_id' => $opportunity->getId(),\n 'stage_id' => $opportunity->getStageId(),\n ]);\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":true,"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}]...
|
2631951404533170602
|
5525541880020581932
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}
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(),
'stage_id' => $opportunity->getStageId(),
]);
$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...
|
40798
|
NULL
|
NULL
|
NULL
|
|
40801
|
1507
|
4
|
2026-05-14T09:22:55.129441+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750575129_m1.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}
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(),
'stage_id' => $opportunity->getStageId(),
]);
$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":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20903-update_activity-stage-on-opportunity-change, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20903-update_activity-stage-on-opportunity-change","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":"1","depth":4,"on_screen":true,"role_description":"text"},{"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\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\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([\n 'opportunity_id' => $opportunity->getId(),\n 'stage_id' => $opportunity->getStageId(),\n ]);\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([\n 'opportunity_id' => $opportunity->getId(),\n 'stage_id' => $opportunity->getStageId(),\n ]);\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":true,"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}]...
|
2631951404533170602
|
5525541880020581932
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}
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(),
'stage_id' => $opportunity->getStageId(),
]);
$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
|
|
40802
|
1508
|
5
|
2026-05-14T09:23:24.823231+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750604823_m2.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}
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(),
'stage_id' => $opportunity->getStageId(),
]);
$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":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20903-update_activity-stage-on-opportunity-change, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12932181,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20903-update_activity-stage-on-opportunity-change","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":"1","depth":4,"bounds":{"left":0.37466756,"top":0.22426178,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.38397607,"top":0.22426178,"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.22266561,"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.22266561,"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\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\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([\n 'opportunity_id' => $opportunity->getId(),\n 'stage_id' => $opportunity->getStageId(),\n ]);\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([\n 'opportunity_id' => $opportunity->getId(),\n 'stage_id' => $opportunity->getStageId(),\n ]);\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":true,"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}]...
|
2631951404533170602
|
5525541880020581932
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}
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(),
'stage_id' => $opportunity->getStageId(),
]);
$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
|
|
40803
|
1507
|
5
|
2026-05-14T09:23:25.495226+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750605495_m1.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20903-update_activity-stage-on-opportunity-change, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20903-update_activity-stage-on-opportunity-change","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}]...
|
-5359167344889750601
|
-8204351074690946106
|
idle
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
FirefoxFileEditViewHistoryBookmarksProfilesCTools WindowHelpmeet.google.com/mie-gawc-dsi?authuser=lukas.kovalik%40jiminny.com>0 lhl • | Daily - Platform - now+100% <478•Thu 14 May 9:45:36...
|
40801
|
NULL
|
NULL
|
NULL
|
|
40804
|
1508
|
6
|
2026-05-14T09:23:55.344697+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750635344_m2.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}
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(),
'stage_id' => $opportunity->getStageId(),
]);
$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":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20903-update_activity-stage-on-opportunity-change, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12932181,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20903-update_activity-stage-on-opportunity-change","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":"1","depth":4,"bounds":{"left":0.37466756,"top":0.22426178,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.38397607,"top":0.22426178,"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.22266561,"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.22266561,"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\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\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([\n 'opportunity_id' => $opportunity->getId(),\n 'stage_id' => $opportunity->getStageId(),\n ]);\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([\n 'opportunity_id' => $opportunity->getId(),\n 'stage_id' => $opportunity->getStageId(),\n ]);\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":true,"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}]...
|
2631951404533170602
|
5525541880020581932
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}
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(),
'stage_id' => $opportunity->getStageId(),
]);
$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...
|
40802
|
NULL
|
NULL
|
NULL
|
|
40805
|
1507
|
6
|
2026-05-14T09:23:56.433968+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750636433_m1.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}
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(),
'stage_id' => $opportunity->getStageId(),
]);
$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":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20903-update_activity-stage-on-opportunity-change, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20903-update_activity-stage-on-opportunity-change","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":"1","depth":4,"on_screen":true,"role_description":"text"},{"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\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\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([\n 'opportunity_id' => $opportunity->getId(),\n 'stage_id' => $opportunity->getStageId(),\n ]);\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([\n 'opportunity_id' => $opportunity->getId(),\n 'stage_id' => $opportunity->getStageId(),\n ]);\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":true,"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}]...
|
2631951404533170602
|
5525541880020581932
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}
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(),
'stage_id' => $opportunity->getStageId(),
]);
$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
|
|
40806
|
1508
|
7
|
2026-05-14T09:24:25.889082+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750665889_m2.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}
Sync Changes...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20903-update_activity-stage-on-opportunity-change, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12932181,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20903-update_activity-stage-on-opportunity-change","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":"1","depth":4,"bounds":{"left":0.37466756,"top":0.22426178,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.38397607,"top":0.22426178,"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.22266561,"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.22266561,"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\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\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}]...
|
-8582345798148833720
|
5524662269748952700
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}
Sync Changes...
|
40802
|
NULL
|
NULL
|
NULL
|
|
40807
|
1507
|
7
|
2026-05-14T09:24:26.765211+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750666765_m1.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}
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(),
'stage_id' => $opportunity->getStageId(),
]);
$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":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20903-update_activity-stage-on-opportunity-change, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20903-update_activity-stage-on-opportunity-change","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":"1","depth":4,"on_screen":true,"role_description":"text"},{"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\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\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([\n 'opportunity_id' => $opportunity->getId(),\n 'stage_id' => $opportunity->getStageId(),\n ]);\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([\n 'opportunity_id' => $opportunity->getId(),\n 'stage_id' => $opportunity->getStageId(),\n ]);\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":true,"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}]...
|
2631951404533170602
|
5525541880020581932
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}
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(),
'stage_id' => $opportunity->getStageId(),
]);
$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...
|
40805
|
NULL
|
NULL
|
NULL
|
|
40808
|
1507
|
8
|
2026-05-14T09:24:49.601526+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750689601_m1.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
FirefoxFileEditViewHistoryBookmarksProfilesCTools FirefoxFileEditViewHistoryBookmarksProfilesCTools WindowHelpmeet.google.com/mie-gawc-dsi?authuser=lukas.kovalik%40jiminny.com>0 lhl • | Daily - Platform - now+100% <478•Thu 14 May 9:45:36...
|
NULL
|
-708492635982512963
|
NULL
|
click
|
ocr
|
NULL
|
FirefoxFileEditViewHistoryBookmarksProfilesCTools FirefoxFileEditViewHistoryBookmarksProfilesCTools WindowHelpmeet.google.com/mie-gawc-dsi?authuser=lukas.kovalik%40jiminny.com>0 lhl • | Daily - Platform - now+100% <478•Thu 14 May 9:45:36...
|
40805
|
NULL
|
NULL
|
NULL
|
|
40809
|
1508
|
8
|
2026-05-14T09:24:49.630073+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750689630_m2.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
slackw Usage | Windsurf• JY-20891 add support for slackw Usage | Windsurf• JY-20891 add support for second:[SRD-6848] Sidekick SMS issue -Platform Sprint 4 Q2 - Platform TeDependabot alerts • jiminny/proph(JY-19958] Upgrade BE librariesWY-20773) User Pilot not receivini( JY-19957 | Remove abanded sympTypeError: Leaque|Flysystem\Files1. Userpilot I Ask Jiminny Report Gen[JY-19957] Upgrade BE libraries -Dependabot alerts - iminny/app11Y-208011 Sidekick SMS iccue -[SRD-6849] Recorded call does n8 Jiminnv8 Jiminny8 Jiminny* Configure SSH access to multiple≥ Useful conDev Tools - ElasticJiminny-7 (SRD-68531 Moxso - Potential des& CloudWatch I eu-west-1CloudWatch | eu-west-1Platform Sorint 4 02 - Platform TeJY-20891 add support for secondaService-Desk - Queues - Platfc XIL Now TohMIStOMwindowhelg1y.dulasslan.nelIld/servicedesk/oroeeJ JIMINNYg For you(• RecentSpaces / Service-Desk / QueuesPlatform team* Starred0+ Apps|:= ListQ SpacesQ Search workJiminny (New)s work lems14 Service-DeskKeyE QueuesSRD-6853Team Priority|©, All open tickets 12SRD-68495 Unassigned t... 3Ej Support tea….SpN-69A9•, Raised by meE Assigned to ..Ej Service requ..E Plattorm teamE Processing t...Ej Site reliability... 0•, New features... 0bi InfoSec issues 0j Ready for Cu... 0•1 Resolved ti….. 999+= View all queuesF Service requestsA IncidentsHl ReportsC Operations• Knowledae Base0 Customers• Channolel• Email loasI< Develoner escalationsl: Slack integration< Reporting Center• Search IRequest tvpe vStatus vAssianee vSummaryMoxso - Potential deal stages bugkecorded call does not aobear on the casnooaroSidekick SMS issueMore tilters vPriority levelP2 MediumPe MediumP2 MediumHomeDMSActivityLateMoreJiminny...yS Starred8 jiminny-x-integrati…..•olattorm-inner-teamE) Channels# ai-chapter# alerts# backend# bugs# confusion-clinid# curiosity lab# engineering# general# jiminny-bg# platform-tickets# product launches# randomi released# sofia-officea suodort# thank-yous# the people of iimi..A Direct messages• Vasil VasilevM Stefka StovanovaMario GeorgievNikolav Ivanovo James Graham8 Stovan Tanev© Galva DimitrovaStelivan Georgiey( Petko KashinskiR Aneliva Angelova EFa Lukas Kovali#: AppsS lira GloudToastm) Google Cale!YDally - Plau100% 1∞' Inu 14 May 9:40:30@ Describe what you are looking for& e. Vasil Vasilev• MessagestAdd canvas( FilesX Pins+1 new messageVasil Vasilley 9.39 AMIдобро утровчера забравих за тебопоави ли се с инлексите, или оше ти липоват ланнииначе имах прелвлиmake docker-updateи реоилдване на локалните контеинерипри мен преди време се бе случило така, че не върваха процесите за индексиране, понеже es-update-worker-а лиспвашеа пьк менажирането на тея процеси от scheduler беше спряноLukas Kovalik 9:42 AMоправих се, но трябваше да пипна команда ще намираше грешно активитиVasi Vasiley 9•43 AMкакьв беше точно проблема всъшност?Lukas Kovalik # 9:43 AMiny# php artisan activity:update:es 422003rouna aeloieysu.s, u. уooовасато 5аоeesending activity tor ts update..Done.това е вече с повече логове422003 -> 16трябва да го видя ощеVasil Vasiley 9:44 ANSactivity = Activity::id0rUuId(SactivityId)->firstO;това е пооблема.Lukas Kovalik 9:44.AMVasil Vasilev 9:44 AMActivity:.dOrludsactivitvicheтова само по себе си връша правилния моделобаче като извикаш върху Activity инстанция допълнтиелно ->first()бюка чаново в базата и рзима пиориа спошнат запискоито винаги в най ниското И ліMessage Vasil Vasilev+ Аal...
|
NULL
|
8912455784959274687
|
NULL
|
click
|
ocr
|
NULL
|
slackw Usage | Windsurf• JY-20891 add support for slackw Usage | Windsurf• JY-20891 add support for second:[SRD-6848] Sidekick SMS issue -Platform Sprint 4 Q2 - Platform TeDependabot alerts • jiminny/proph(JY-19958] Upgrade BE librariesWY-20773) User Pilot not receivini( JY-19957 | Remove abanded sympTypeError: Leaque|Flysystem\Files1. Userpilot I Ask Jiminny Report Gen[JY-19957] Upgrade BE libraries -Dependabot alerts - iminny/app11Y-208011 Sidekick SMS iccue -[SRD-6849] Recorded call does n8 Jiminnv8 Jiminny8 Jiminny* Configure SSH access to multiple≥ Useful conDev Tools - ElasticJiminny-7 (SRD-68531 Moxso - Potential des& CloudWatch I eu-west-1CloudWatch | eu-west-1Platform Sorint 4 02 - Platform TeJY-20891 add support for secondaService-Desk - Queues - Platfc XIL Now TohMIStOMwindowhelg1y.dulasslan.nelIld/servicedesk/oroeeJ JIMINNYg For you(• RecentSpaces / Service-Desk / QueuesPlatform team* Starred0+ Apps|:= ListQ SpacesQ Search workJiminny (New)s work lems14 Service-DeskKeyE QueuesSRD-6853Team Priority|©, All open tickets 12SRD-68495 Unassigned t... 3Ej Support tea….SpN-69A9•, Raised by meE Assigned to ..Ej Service requ..E Plattorm teamE Processing t...Ej Site reliability... 0•, New features... 0bi InfoSec issues 0j Ready for Cu... 0•1 Resolved ti….. 999+= View all queuesF Service requestsA IncidentsHl ReportsC Operations• Knowledae Base0 Customers• Channolel• Email loasI< Develoner escalationsl: Slack integration< Reporting Center• Search IRequest tvpe vStatus vAssianee vSummaryMoxso - Potential deal stages bugkecorded call does not aobear on the casnooaroSidekick SMS issueMore tilters vPriority levelP2 MediumPe MediumP2 MediumHomeDMSActivityLateMoreJiminny...yS Starred8 jiminny-x-integrati…..•olattorm-inner-teamE) Channels# ai-chapter# alerts# backend# bugs# confusion-clinid# curiosity lab# engineering# general# jiminny-bg# platform-tickets# product launches# randomi released# sofia-officea suodort# thank-yous# the people of iimi..A Direct messages• Vasil VasilevM Stefka StovanovaMario GeorgievNikolav Ivanovo James Graham8 Stovan Tanev© Galva DimitrovaStelivan Georgiey( Petko KashinskiR Aneliva Angelova EFa Lukas Kovali#: AppsS lira GloudToastm) Google Cale!YDally - Plau100% 1∞' Inu 14 May 9:40:30@ Describe what you are looking for& e. Vasil Vasilev• MessagestAdd canvas( FilesX Pins+1 new messageVasil Vasilley 9.39 AMIдобро утровчера забравих за тебопоави ли се с инлексите, или оше ти липоват ланнииначе имах прелвлиmake docker-updateи реоилдване на локалните контеинерипри мен преди време се бе случило така, че не върваха процесите за индексиране, понеже es-update-worker-а лиспвашеа пьк менажирането на тея процеси от scheduler беше спряноLukas Kovalik 9:42 AMоправих се, но трябваше да пипна команда ще намираше грешно активитиVasi Vasiley 9•43 AMкакьв беше точно проблема всъшност?Lukas Kovalik # 9:43 AMiny# php artisan activity:update:es 422003rouna aeloieysu.s, u. уooовасато 5аоeesending activity tor ts update..Done.това е вече с повече логове422003 -> 16трябва да го видя ощеVasil Vasiley 9:44 ANSactivity = Activity::id0rUuId(SactivityId)->firstO;това е пооблема.Lukas Kovalik 9:44.AMVasil Vasilev 9:44 AMActivity:.dOrludsactivitvicheтова само по себе си връша правилния моделобаче като извикаш върху Activity инстанция допълнтиелно ->first()бюка чаново в базата и рзима пиориа спошнат запискоито винаги в най ниското И ліMessage Vasil Vasilev+ Аal...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
40810
|
1507
|
9
|
2026-05-14T09:25:21.543675+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750721543_m1.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}
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(),
'stage_id' => $opportunity->getStageId(),
]);
$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":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20903-update_activity-stage-on-opportunity-change, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20903-update_activity-stage-on-opportunity-change","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":"1","depth":4,"on_screen":true,"role_description":"text"},{"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\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\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([\n 'opportunity_id' => $opportunity->getId(),\n 'stage_id' => $opportunity->getStageId(),\n ]);\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([\n 'opportunity_id' => $opportunity->getId(),\n 'stage_id' => $opportunity->getStageId(),\n ]);\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}]...
|
2631951404533170602
|
5525541880020581932
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}
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(),
'stage_id' => $opportunity->getStageId(),
]);
$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
|
|
40811
|
1508
|
9
|
2026-05-14T09:25:23.444610+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750723444_m2.jpg...
|
PhpStorm
|
faVsco.js – FixActivitiesOpportunity.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}
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(),
'stage_id' => $opportunity->getStageId(),
]);
$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":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20903-update_activity-stage-on-opportunity-change, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12932181,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20903-update_activity-stage-on-opportunity-change","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":"1","depth":4,"bounds":{"left":0.37466756,"top":0.22426178,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.38397607,"top":0.22426178,"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.22266561,"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.22266561,"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\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Repositories\\Crm;\n\nuse DateTimeInterface;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Jiminny\\Contracts\\Repositories\\RetentionRepositoryInterface;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Team;\n\n/**\n * @implements RetentionRepositoryInterface<Opportunity>\n */\nclass OpportunityRepository implements RetentionRepositoryInterface\n{\n /**\n * @param array<string,scalar|null> $data\n */\n public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity\n {\n /* @var Opportunity */\n return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);\n }\n\n public function find(int $id): ?Opportunity\n {\n return Opportunity::find($id);\n }\n\n /**\n * @param array $ids\n *\n * @return Collection<Opportunity>\n */\n public function findMany(array $ids): Collection\n {\n return Opportunity::findMany($ids);\n }\n\n public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity\n {\n return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();\n }\n\n public function findOneByAccountAndOpportunityAssignmentRule(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();\n }\n\n public function findOneByAccountAndOpportunityOwner(\n Configuration $configuration,\n Account $account,\n int $userId,\n ?int $contactId = null\n ): ?Opportunity {\n return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)\n ->where('user_id', $userId)\n ->first()\n ;\n }\n\n private function buildAccountOpportunityQuery(\n Configuration $configuration,\n Account $account,\n ?int $contactId = null\n ): HasMany {\n $criteria = $this->resolveOpportunityOrder($configuration);\n\n return $configuration\n ->opportunities()\n ->where('account_id', $account->getId())\n ->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))\n ->when(\n $contactId !== null,\n fn ($query) => $query->orderByRaw(\n 'EXISTS (SELECT 1 FROM opportunity_contacts ' .\n 'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .\n 'AND opportunity_contacts.contact_id = ?) DESC',\n [$contactId]\n )\n )\n ->orderBy($criteria['order_by'], $criteria['direction'])\n ;\n }\n\n\n /**\n * Find all non-internal opportunities by account ID and configuration\n */\n public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection\n {\n return $configuration->opportunities()\n ->where('account_id', $accountId)\n ->get();\n }\n\n /**\n * @throws InvalidArgumentException\n *\n * @return array{order_by: string, direction: string, only_open: bool}\n */\n public function resolveOpportunityOrder(Configuration $configuration): array\n {\n $params = ['only_open' => true];\n\n switch ($configuration->getOpportunityAssignmentRule()) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'DESC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['order_by'] = 'remotely_created_at';\n $params['direction'] = 'ASC';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['order_by'] = 'updated_at';\n $params['direction'] = 'DESC';\n $params['only_open'] = false;\n\n break;\n\n default:\n throw new InvalidArgumentException('Invalid opportunity assignment rule');\n }\n\n return $params;\n }\n\n public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity\n {\n return $team\n ->opportunities()\n ->where('id', $opportunityId)\n ->first();\n }\n\n public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder\n {\n /** @var Builder<Opportunity> */\n return Opportunity::query()\n ->forTeam($teamId)\n ->where('is_closed', '=', true)\n ->whereBetween('created_at', [$from, $to]);\n }\n\n public function findByUuid(string $uuid): ?Opportunity\n {\n return Opportunity::uuid($uuid, false)->first();\n }\n\n public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity\n {\n return $team->opportunities()\n ->where('crm_provider_id', '=', $crmProviderId)\n ->first();\n }\n\n public function findWithTrashed(int $id): ?Opportunity\n {\n return Opportunity::withTrashed()->find($id);\n }\n\n public function detachStages(Opportunity $opportunity): void\n {\n $opportunity->stages()->withTrashed()->detach();\n }\n\n public function detachContactReferences(Opportunity $opportunity): void\n {\n $opportunity->contacts()->withTrashed()->detach();\n }\n\n public function nullifyLeadConversionReferences(int $opportunityId): void\n {\n Lead::withTrashed()\n ->where('converted_opportunity_id', $opportunityId)\n ->update(['converted_opportunity_id' => null]);\n }\n\n public function hasOwnerCommented(Opportunity $opportunity): bool\n {\n $ownerId = $opportunity->getUserId();\n\n if ($ownerId === null) {\n return false;\n }\n\n return $opportunity->comments()\n ->where('user_id', '=', $ownerId)\n ->exists();\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([\n 'opportunity_id' => $opportunity->getId(),\n 'stage_id' => $opportunity->getStageId(),\n ]);\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([\n 'opportunity_id' => $opportunity->getId(),\n 'stage_id' => $opportunity->getStageId(),\n ]);\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}]...
|
2631951404533170602
|
5525541880020581932
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20903-update_activity- Project: faVsco.js, menu
JY-20903-update_activity-stage-on-opportunity-change, 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
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Repositories\Crm;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Jiminny\Contracts\Repositories\RetentionRepositoryInterface;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Team;
/**
* @implements RetentionRepositoryInterface<Opportunity>
*/
class OpportunityRepository implements RetentionRepositoryInterface
{
/**
* @param array<string,scalar|null> $data
*/
public function updateOrCreate(Configuration $configuration, string $opportunityId, array $data): Opportunity
{
/* @var Opportunity */
return $configuration->opportunities()->updateOrCreate(['crm_provider_id' => $opportunityId], $data);
}
public function find(int $id): ?Opportunity
{
return Opportunity::find($id);
}
/**
* @param array $ids
*
* @return Collection<Opportunity>
*/
public function findMany(array $ids): Collection
{
return Opportunity::findMany($ids);
}
public function findByConfigAndCrmProviderId(Configuration $configuration, string $crmProviderId): ?Opportunity
{
return $configuration->opportunities()->where('crm_provider_id', $crmProviderId)->first();
}
public function findOneByAccountAndOpportunityAssignmentRule(
Configuration $configuration,
Account $account,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)->first();
}
public function findOneByAccountAndOpportunityOwner(
Configuration $configuration,
Account $account,
int $userId,
?int $contactId = null
): ?Opportunity {
return $this->buildAccountOpportunityQuery($configuration, $account, $contactId)
->where('user_id', $userId)
->first()
;
}
private function buildAccountOpportunityQuery(
Configuration $configuration,
Account $account,
?int $contactId = null
): HasMany {
$criteria = $this->resolveOpportunityOrder($configuration);
return $configuration
->opportunities()
->where('account_id', $account->getId())
->when($criteria['only_open'], fn ($query) => $query->where('is_closed', false))
->when(
$contactId !== null,
fn ($query) => $query->orderByRaw(
'EXISTS (SELECT 1 FROM opportunity_contacts ' .
'WHERE opportunity_contacts.opportunity_id = opportunities.id ' .
'AND opportunity_contacts.contact_id = ?) DESC',
[$contactId]
)
)
->orderBy($criteria['order_by'], $criteria['direction'])
;
}
/**
* Find all non-internal opportunities by account ID and configuration
*/
public function findAllByConfigurationAndAccountId(Configuration $configuration, int $accountId): Collection
{
return $configuration->opportunities()
->where('account_id', $accountId)
->get();
}
/**
* @throws InvalidArgumentException
*
* @return array{order_by: string, direction: string, only_open: bool}
*/
public function resolveOpportunityOrder(Configuration $configuration): array
{
$params = ['only_open' => true];
switch ($configuration->getOpportunityAssignmentRule()) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'DESC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['order_by'] = 'remotely_created_at';
$params['direction'] = 'ASC';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['order_by'] = 'updated_at';
$params['direction'] = 'DESC';
$params['only_open'] = false;
break;
default:
throw new InvalidArgumentException('Invalid opportunity assignment rule');
}
return $params;
}
public function findConvertedOpportunityById(Team $team, $opportunityId): ?Opportunity
{
return $team
->opportunities()
->where('id', $opportunityId)
->first();
}
public function getRetentionQueryBuilder(int $teamId, DateTimeInterface $from, DateTimeInterface $to): Builder
{
/** @var Builder<Opportunity> */
return Opportunity::query()
->forTeam($teamId)
->where('is_closed', '=', true)
->whereBetween('created_at', [$from, $to]);
}
public function findByUuid(string $uuid): ?Opportunity
{
return Opportunity::uuid($uuid, false)->first();
}
public function getOpportunityByTeamAndExternalId(Team $team, string $crmProviderId): ?Opportunity
{
return $team->opportunities()
->where('crm_provider_id', '=', $crmProviderId)
->first();
}
public function findWithTrashed(int $id): ?Opportunity
{
return Opportunity::withTrashed()->find($id);
}
public function detachStages(Opportunity $opportunity): void
{
$opportunity->stages()->withTrashed()->detach();
}
public function detachContactReferences(Opportunity $opportunity): void
{
$opportunity->contacts()->withTrashed()->detach();
}
public function nullifyLeadConversionReferences(int $opportunityId): void
{
Lead::withTrashed()
->where('converted_opportunity_id', $opportunityId)
->update(['converted_opportunity_id' => null]);
}
public function hasOwnerCommented(Opportunity $opportunity): bool
{
$ownerId = $opportunity->getUserId();
if ($ownerId === null) {
return false;
}
return $opportunity->comments()
->where('user_id', '=', $ownerId)
->exists();
}
}
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(),
'stage_id' => $opportunity->getStageId(),
]);
$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...
|
40809
|
NULL
|
NULL
|
NULL
|
|
40812
|
1507
|
10
|
2026-05-14T09:25:30.958183+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750730958_m1.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira...
|
[{"role":"AXRadioButton","text [{"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":"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":"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}]...
|
3368902698547384054
|
-759902979962830635
|
app_switch
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
40813
|
1508
|
10
|
2026-05-14T09:25:30.958185+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750730958_m2.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"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":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"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.08459697,"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.09577015,"width":0.029920213,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-9097865644379327290
|
-1997829926999547755
|
app_switch
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
40814
|
1507
|
11
|
2026-05-14T09:25:32.156257+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750732156_m1.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you...
|
[{"role":"AXRadioButton","text [{"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":"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":"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":"[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":"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":"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":"AXRadioButton","text":"Dev Tools - Elastic","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dev Tools - Elastic","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":"[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":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","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":"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":true},{"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":"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":"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":"AXStaticText","text":"Skip to:","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collapse sidebar [","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":10,"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":"Switch sites or apps","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":11,"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"Create","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Rovo","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Help","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","depth":12,"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":"Settings","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","depth":12,"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":"lukas.kovalik@jiminny.com","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-3250113048299203066
|
1735097905058693216
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you...
|
40812
|
NULL
|
NULL
|
NULL
|
|
40815
|
1508
|
11
|
2026-05-14T09:25:32.168935+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750732168_m2.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"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":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"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.08459697,"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.09577015,"width":0.029920213,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6848] Sidekick SMS issue - Jira","depth":4,"bounds":{"left":0.0,"top":0.11731844,"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":"[SRD-6848] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"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.0,"top":0.15003991,"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":"[JY-20891] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.16121309,"width":0.064494684,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":4,"bounds":{"left":0.0,"top":0.18276137,"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":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.19393456,"width":0.11735372,"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.21548285,"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.22665602,"width":0.013131649,"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.2482043,"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.25937748,"width":0.013131649,"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.28092578,"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.29209897,"width":0.013131649,"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.31364724,"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.32482043,"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.3463687,"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.3575419,"width":0.079288565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Dev Tools - Elastic","depth":4,"bounds":{"left":0.0,"top":0.3790902,"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":"Dev Tools - Elastic","depth":5,"bounds":{"left":0.013297873,"top":0.39026338,"width":0.032247342,"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.41181165,"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.42298484,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":4,"bounds":{"left":0.0,"top":0.4445331,"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":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.4557063,"width":0.09158909,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.4772546,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.4884278,"width":0.041722074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.509976,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.5211492,"width":0.041722074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.54269755,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.55387074,"width":0.041722074,"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.0,"top":0.575419,"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":"JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.5865922,"width":0.15658244,"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.0,"top":0.60814047,"width":0.07962101,"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] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.61931366,"width":0.11619016,"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.61532325,"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":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.6424581,"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":"AXStaticText","text":"Skip to:","depth":9,"bounds":{"left":0.090259306,"top":0.07861133,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":10,"bounds":{"left":0.090259306,"top":0.097765364,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":11,"bounds":{"left":0.090259306,"top":0.097765364,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":10,"bounds":{"left":0.090259306,"top":0.11691939,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":11,"bounds":{"left":0.090259306,"top":0.11691939,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":10,"bounds":{"left":0.090259306,"top":0.13607343,"width":0.029421542,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":11,"bounds":{"left":0.090259306,"top":0.13607343,"width":0.029421542,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":9,"bounds":{"left":0.08361037,"top":0.057861134,"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":"AXStaticText","text":"Collapse sidebar [","depth":11,"bounds":{"left":0.0887633,"top":0.06344773,"width":0.039727394,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":10,"bounds":{"left":0.095578454,"top":0.057861134,"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":"AXStaticText","text":"Switch sites or apps","depth":12,"bounds":{"left":0.10073138,"top":0.06344773,"width":0.044215426,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":9,"bounds":{"left":0.10887633,"top":0.057861134,"width":0.029421542,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":11,"bounds":{"left":0.40475398,"top":0.06264964,"width":0.24268617,"height":0.015961692},"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":10,"bounds":{"left":0.65575135,"top":0.057861134,"width":0.030086435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"Create","depth":12,"bounds":{"left":0.66705453,"top":0.06384677,"width":0.014793883,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":12,"bounds":{"left":0.91223407,"top":0.057861134,"width":0.035904255,"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":"Ask Rovo","depth":14,"bounds":{"left":0.92353725,"top":0.06384677,"width":0.020611702,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":12,"bounds":{"left":0.9494681,"top":0.057861134,"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":"AXStaticText","text":"Notifications","depth":14,"bounds":{"left":0.954621,"top":0.06344773,"width":0.027759308,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":12,"bounds":{"left":0.96143615,"top":0.057861134,"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":"AXStaticText","text":"Help","depth":14,"bounds":{"left":0.9665891,"top":0.06344773,"width":0.010139627,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","depth":12,"bounds":{"left":0.9734042,"top":0.057861134,"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":"AXStaticText","text":"Settings","depth":14,"bounds":{"left":0.97855717,"top":0.06344773,"width":0.017952127,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
1283528918383615622
|
1735115514424606816
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings...
|
40813
|
NULL
|
NULL
|
NULL
|
|
40816
|
1507
|
12
|
2026-05-14T09:25:39.451728+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750739451_m1.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)
Platform Team
Platform Team
Board actions
Board actions
Capture Team
Capture Team
Board actions
Board actions
Enterprise Stability Issues 🤕
Enterprise Stability Issues 🤕
Board actions
Board actions
Processing Team
Processing Team
Board actions
Board actions
SE Kanban
SE Kanban
Board actions...
|
[{"role":"AXRadioButton","text [{"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":"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":"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":"[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":"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":"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":"AXRadioButton","text":"Dev Tools - Elastic","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dev Tools - Elastic","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":"[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":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","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":"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":true},{"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":"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":"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":"AXStaticText","text":"Skip to:","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collapse sidebar [","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":11,"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":"Switch sites or apps","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":12,"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Rovo","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Help","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","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":"Settings","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","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":"lukas.kovalik@jiminny.com","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"For you","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Recent","depth":13,"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":"Recent","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Starred","depth":13,"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":"Starred","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Apps","depth":13,"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":"Apps","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Apps","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":"More actions for Apps","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Spaces","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Spaces","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create space","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create space","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for spaces","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":"More actions for spaces","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Recent","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New)","depth":18,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny (New)","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Jiminny (New)","depth":19,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXMenuButton","text":"Create board","depth":19,"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":"Create board","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Jiminny (New)","depth":19,"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":"More actions for Jiminny (New)","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Platform Team","depth":20,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Team","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"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":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Capture Team","depth":20,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Capture Team","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"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":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Enterprise Stability Issues 🤕","depth":20,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enterprise Stability Issues 🤕","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"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":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Processing Team","depth":20,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Processing Team","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"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":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SE Kanban","depth":20,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SE Kanban","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
6633076103841376506
|
1735097844929155172
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)
Platform Team
Platform Team
Board actions
Board actions
Capture Team
Capture Team
Board actions
Board actions
Enterprise Stability Issues 🤕
Enterprise Stability Issues 🤕
Board actions
Board actions
Processing Team
Processing Team
Board actions
Board actions
SE Kanban
SE Kanban
Board actions...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
40817
|
1508
|
12
|
2026-05-14T09:25:39.464697+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750739464_m2.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)
Platform Team
Platform Team
Board actions
Board actions
Capture Team
Capture Team
Board actions
Board actions
Enterprise Stability Issues 🤕
Enterprise Stability Issues 🤕
Board actions
Board actions
Processing Team
Processing Team
Board actions
Board actions
SE Kanban
SE Kanban...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"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":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"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.08459697,"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.09577015,"width":0.029920213,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6848] Sidekick SMS issue - Jira","depth":4,"bounds":{"left":0.0,"top":0.11731844,"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":"[SRD-6848] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"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.0,"top":0.15003991,"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":"[JY-20891] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.16121309,"width":0.064494684,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":4,"bounds":{"left":0.0,"top":0.18276137,"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":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.19393456,"width":0.11735372,"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.21548285,"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.22665602,"width":0.013131649,"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.2482043,"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.25937748,"width":0.013131649,"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.28092578,"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.29209897,"width":0.013131649,"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.31364724,"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.32482043,"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.3463687,"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.3575419,"width":0.079288565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Dev Tools - Elastic","depth":4,"bounds":{"left":0.0,"top":0.3790902,"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":"Dev Tools - Elastic","depth":5,"bounds":{"left":0.013297873,"top":0.39026338,"width":0.032247342,"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.41181165,"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.42298484,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":4,"bounds":{"left":0.0,"top":0.4445331,"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":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.4557063,"width":0.09158909,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.4772546,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.4884278,"width":0.041722074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.509976,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.5211492,"width":0.041722074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.54269755,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.55387074,"width":0.041722074,"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.0,"top":0.575419,"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":"JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.5865922,"width":0.15658244,"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.0,"top":0.60814047,"width":0.07962101,"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] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.61931366,"width":0.11619016,"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.61532325,"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":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.6424581,"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":"AXStaticText","text":"Skip to:","depth":10,"bounds":{"left":0.090259306,"top":0.07861133,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":11,"bounds":{"left":0.090259306,"top":0.097765364,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":12,"bounds":{"left":0.090259306,"top":0.097765364,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":11,"bounds":{"left":0.090259306,"top":0.11691939,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":12,"bounds":{"left":0.090259306,"top":0.11691939,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":11,"bounds":{"left":0.090259306,"top":0.13607343,"width":0.029421542,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":12,"bounds":{"left":0.090259306,"top":0.13607343,"width":0.029421542,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":10,"bounds":{"left":0.08361037,"top":0.057861134,"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":"AXStaticText","text":"Collapse sidebar [","depth":12,"bounds":{"left":0.0887633,"top":0.06344773,"width":0.039727394,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":11,"bounds":{"left":0.095578454,"top":0.057861134,"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":"AXStaticText","text":"Switch sites or apps","depth":13,"bounds":{"left":0.10073138,"top":0.06344773,"width":0.044215426,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":10,"bounds":{"left":0.10887633,"top":0.057861134,"width":0.029421542,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":12,"bounds":{"left":0.40475398,"top":0.06264964,"width":0.24268617,"height":0.015961692},"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":11,"bounds":{"left":0.65575135,"top":0.057861134,"width":0.030086435,"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":"Create","depth":13,"bounds":{"left":0.66705453,"top":0.06384677,"width":0.014793883,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":13,"bounds":{"left":0.91223407,"top":0.057861134,"width":0.035904255,"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":"Ask Rovo","depth":15,"bounds":{"left":0.92353725,"top":0.06384677,"width":0.020611702,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":13,"bounds":{"left":0.9494681,"top":0.057861134,"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":"AXStaticText","text":"Notifications","depth":15,"bounds":{"left":0.954621,"top":0.06344773,"width":0.027759308,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":13,"bounds":{"left":0.96143615,"top":0.057861134,"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":"AXStaticText","text":"Help","depth":15,"bounds":{"left":0.9665891,"top":0.06344773,"width":0.010139627,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","depth":13,"bounds":{"left":0.9734042,"top":0.057861134,"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":"AXStaticText","text":"Settings","depth":15,"bounds":{"left":0.97855717,"top":0.06344773,"width":0.017952127,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","depth":13,"bounds":{"left":0.98537236,"top":0.057861134,"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":"AXStaticText","text":"lukas.kovalik@jiminny.com","depth":15,"bounds":{"left":0.99052525,"top":0.06344773,"width":0.009474754,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":13,"bounds":{"left":0.08361037,"top":0.09976058,"width":0.071476065,"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":"For you","depth":16,"bounds":{"left":0.09424867,"top":0.10574621,"width":0.01662234,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Recent","depth":13,"bounds":{"left":0.08361037,"top":0.12529927,"width":0.071476065,"height":0.025538707},"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":"Recent","depth":16,"bounds":{"left":0.09424867,"top":0.13128492,"width":0.015458777,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Starred","depth":13,"bounds":{"left":0.08361037,"top":0.15083799,"width":0.071476065,"height":0.025538707},"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":"Starred","depth":16,"bounds":{"left":0.09424867,"top":0.15682362,"width":0.016456118,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Apps","depth":13,"bounds":{"left":0.08361037,"top":0.1763767,"width":0.071476065,"height":0.025538707},"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":"Apps","depth":16,"bounds":{"left":0.09424867,"top":0.18236233,"width":0.011635638,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Apps","depth":14,"bounds":{"left":0.15309176,"top":0.17956904,"width":0.0039893617,"height":0.01915403},"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":"More actions for Apps","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Spaces","depth":13,"bounds":{"left":0.08361037,"top":0.2019154,"width":0.071476065,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Spaces","depth":16,"bounds":{"left":0.09424867,"top":0.20790103,"width":0.016456118,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create space","depth":14,"bounds":{"left":0.13646941,"top":0.20510775,"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":"AXStaticText","text":"Create space","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for spaces","depth":14,"bounds":{"left":0.14577793,"top":0.20510775,"width":0.007978723,"height":0.01915403},"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":"More actions for spaces","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Recent","depth":17,"bounds":{"left":0.08959442,"top":0.23423783,"width":0.013464096,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New)","depth":18,"bounds":{"left":0.08759973,"top":0.2529928,"width":0.0674867,"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 (New)","depth":21,"bounds":{"left":0.09823803,"top":0.25897846,"width":0.032081116,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Jiminny (New)","depth":19,"bounds":{"left":0.08892952,"top":0.25618514,"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,"is_expanded":true},{"role":"AXMenuButton","text":"Create board","depth":19,"bounds":{"left":0.13646941,"top":0.25618514,"width":0.007978723,"height":0.01915403},"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":"Create board","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Jiminny (New)","depth":19,"bounds":{"left":0.14577793,"top":0.25618514,"width":0.007978723,"height":0.01915403},"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":"More actions for Jiminny (New)","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Platform Team","depth":20,"bounds":{"left":0.09158909,"top":0.27853152,"width":0.06349734,"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":"Platform Team","depth":23,"bounds":{"left":0.1022274,"top":0.28451717,"width":0.032247342,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"bounds":{"left":0.15309176,"top":0.28172386,"width":0.0039893617,"height":0.01915403},"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":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Capture Team","depth":20,"bounds":{"left":0.09158909,"top":0.30407023,"width":0.06349734,"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":"Capture Team","depth":23,"bounds":{"left":0.1022274,"top":0.31005585,"width":0.03125,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"bounds":{"left":0.15309176,"top":0.30726257,"width":0.0039893617,"height":0.01915403},"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":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Enterprise Stability Issues 🤕","depth":20,"bounds":{"left":0.09158909,"top":0.32960895,"width":0.06349734,"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":"Enterprise Stability Issues 🤕","depth":23,"bounds":{"left":0.1022274,"top":0.33559456,"width":0.050531916,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"bounds":{"left":0.15309176,"top":0.33280128,"width":0.0039893617,"height":0.01915403},"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":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Processing Team","depth":20,"bounds":{"left":0.09158909,"top":0.35514766,"width":0.06349734,"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":"Processing Team","depth":23,"bounds":{"left":0.1022274,"top":0.36113328,"width":0.038231384,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"bounds":{"left":0.15309176,"top":0.35834,"width":0.0039893617,"height":0.01915403},"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":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SE Kanban","depth":20,"bounds":{"left":0.09158909,"top":0.38068634,"width":0.06349734,"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":"SE Kanban","depth":23,"bounds":{"left":0.1022274,"top":0.386672,"width":0.024102394,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-1655878352646486997
|
1735115437115199588
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)
Platform Team
Platform Team
Board actions
Board actions
Capture Team
Capture Team
Board actions
Board actions
Enterprise Stability Issues 🤕
Enterprise Stability Issues 🤕
Board actions
Board actions
Processing Team
Processing Team
Board actions
Board actions
SE Kanban
SE Kanban...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
40819
|
NULL
|
0
|
2026-05-14T09:25:51.057405+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750751057_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
slackw Usage | Windsurf• JY-20891 add support for slackw Usage | Windsurf• JY-20891 add support for second:[SRD-6848] Sidekick SMS issue -Platform Sprint 4 Q2 - Platform TeDependabot alerts • jiminny/proph(JY-19958] Upgrade BE librariesWY-20773) User Pilot not receivini( JY-19957 | Remove abanded sympTypeError: Leaque|Flysystem\Files1. Userpilot I Ask Jiminny Report Gen[JY-19957] Upgrade BE libraries -Dependabot alerts - iminny/app11Y-208011 Sidekick SMS iccue -[SRD-6849] Recorded call does n8 Jiminnv8 Jiminny8 Jiminny* Configure SSH access to multiple≥ Useful conDev Tools - ElasticJiminny-7 (SRD-68531 Moxso - Potential des& CloudWatch I eu-west-1CloudWatch | eu-west-1Platform Sorint 4 02 - Platform TeJY-20891 add support for secondaService-Desk - Queues - Platfc XIL Now TohMIStOMwindowhelg1y.dulasslan.nelIld/servicedesk/oroeeJ JIMINNYg For you(• RecentSpaces / Service-Desk / QueuesPlatform team* Starred0+ Apps|:= ListQ SpacesQ Search workJiminny (New)s work lems14 Service-DeskKeyE QueuesSRD-6853Team Priority|©, All open tickets 12SRD-68495 Unassigned t... 3Ej Support tea….SpN-69A9•, Raised by meE Assigned to ..Ej Service requ..E Plattorm teamE Processing t...Ej Site reliability... 0•, New features... 0bi InfoSec issues 0j Ready for Cu... 0•1 Resolved ti….. 999+= View all queuesF Service requestsA IncidentsHl ReportsC Operations• Knowledae Base0 Customers• Channolel• Email loasI< Develoner escalationsl: Slack integration< Reporting Center• Search IRequest tvpe vStatus vAssianee vSummaryMoxso - Potential deal stages bugkecorded call does not aobear on the casnooaroSidekick SMS issueMore tilters vPriority levelP2 MediumPe MediumP2 MediumHomeDMSActivityLateMoreJiminny...yS Starred8 jiminny-x-integrati…..•olattorm-inner-teamE) Channels# ai-chapter# alerts# backend# bugs# confusion-clinid# curiosity lab# engineering# general# jiminny-bg# platform-tickets# product launches# randomi released# sofia-officea suodort# thank-yous# the people of iimi..A Direct messages• Vasil VasilevM Stefka StovanovaMario GeorgievNikolav Ivanovo James Graham8 Stovan Tanev© Galva DimitrovaStelivan Georgiey( Petko KashinskiR Aneliva Angelova EFa Lukas Kovali#: AppsS lira GloudToastm) Google Cale!YDally - Plau100% 1∞' Inu 14 May 9:40:30@ Describe what you are looking for& e. Vasil Vasilev• MessagestAdd canvas( FilesX Pins+1 new messageVasil Vasilley 9.39 AMIдобро утровчера забравих за тебопоави ли се с инлексите, или оше ти липоват ланнииначе имах прелвлиmake docker-updateи реоилдване на локалните контеинерипри мен преди време се бе случило така, че не върваха процесите за индексиране, понеже es-update-worker-а лиспвашеа пьк менажирането на тея процеси от scheduler беше спряноLukas Kovalik 9:42 AMоправих се, но трябваше да пипна команда ще намираше грешно активитиVasi Vasiley 9•43 AMкакьв беше точно проблема всъшност?Lukas Kovalik # 9:43 AMiny# php artisan activity:update:es 422003rouna aeloieysu.s, u. уooовасато 5аоeesending activity tor ts update..Done.това е вече с повече логове422003 -> 16трябва да го видя ощеVasil Vasiley 9:44 ANSactivity = Activity::id0rUuId(SactivityId)->firstO;това е пооблема.Lukas Kovalik 9:44.AMVasil Vasilev 9:44 AMActivity:.dOrludsactivitvicheтова само по себе си връша правилния моделобаче като извикаш върху Activity инстанция допълнтиелно ->first()бюка чаново в базата и рзима пиориа спошнат запискоито винаги в най ниското И ліMessage Vasil Vasilev+ Аal...
|
NULL
|
8912455784959274687
|
NULL
|
click
|
ocr
|
NULL
|
slackw Usage | Windsurf• JY-20891 add support for slackw Usage | Windsurf• JY-20891 add support for second:[SRD-6848] Sidekick SMS issue -Platform Sprint 4 Q2 - Platform TeDependabot alerts • jiminny/proph(JY-19958] Upgrade BE librariesWY-20773) User Pilot not receivini( JY-19957 | Remove abanded sympTypeError: Leaque|Flysystem\Files1. Userpilot I Ask Jiminny Report Gen[JY-19957] Upgrade BE libraries -Dependabot alerts - iminny/app11Y-208011 Sidekick SMS iccue -[SRD-6849] Recorded call does n8 Jiminnv8 Jiminny8 Jiminny* Configure SSH access to multiple≥ Useful conDev Tools - ElasticJiminny-7 (SRD-68531 Moxso - Potential des& CloudWatch I eu-west-1CloudWatch | eu-west-1Platform Sorint 4 02 - Platform TeJY-20891 add support for secondaService-Desk - Queues - Platfc XIL Now TohMIStOMwindowhelg1y.dulasslan.nelIld/servicedesk/oroeeJ JIMINNYg For you(• RecentSpaces / Service-Desk / QueuesPlatform team* Starred0+ Apps|:= ListQ SpacesQ Search workJiminny (New)s work lems14 Service-DeskKeyE QueuesSRD-6853Team Priority|©, All open tickets 12SRD-68495 Unassigned t... 3Ej Support tea….SpN-69A9•, Raised by meE Assigned to ..Ej Service requ..E Plattorm teamE Processing t...Ej Site reliability... 0•, New features... 0bi InfoSec issues 0j Ready for Cu... 0•1 Resolved ti….. 999+= View all queuesF Service requestsA IncidentsHl ReportsC Operations• Knowledae Base0 Customers• Channolel• Email loasI< Develoner escalationsl: Slack integration< Reporting Center• Search IRequest tvpe vStatus vAssianee vSummaryMoxso - Potential deal stages bugkecorded call does not aobear on the casnooaroSidekick SMS issueMore tilters vPriority levelP2 MediumPe MediumP2 MediumHomeDMSActivityLateMoreJiminny...yS Starred8 jiminny-x-integrati…..•olattorm-inner-teamE) Channels# ai-chapter# alerts# backend# bugs# confusion-clinid# curiosity lab# engineering# general# jiminny-bg# platform-tickets# product launches# randomi released# sofia-officea suodort# thank-yous# the people of iimi..A Direct messages• Vasil VasilevM Stefka StovanovaMario GeorgievNikolav Ivanovo James Graham8 Stovan Tanev© Galva DimitrovaStelivan Georgiey( Petko KashinskiR Aneliva Angelova EFa Lukas Kovali#: AppsS lira GloudToastm) Google Cale!YDally - Plau100% 1∞' Inu 14 May 9:40:30@ Describe what you are looking for& e. Vasil Vasilev• MessagestAdd canvas( FilesX Pins+1 new messageVasil Vasilley 9.39 AMIдобро утровчера забравих за тебопоави ли се с инлексите, или оше ти липоват ланнииначе имах прелвлиmake docker-updateи реоилдване на локалните контеинерипри мен преди време се бе случило така, че не върваха процесите за индексиране, понеже es-update-worker-а лиспвашеа пьк менажирането на тея процеси от scheduler беше спряноLukas Kovalik 9:42 AMоправих се, но трябваше да пипна команда ще намираше грешно активитиVasi Vasiley 9•43 AMкакьв беше точно проблема всъшност?Lukas Kovalik # 9:43 AMiny# php artisan activity:update:es 422003rouna aeloieysu.s, u. уooовасато 5аоeesending activity tor ts update..Done.това е вече с повече логове422003 -> 16трябва да го видя ощеVasil Vasiley 9:44 ANSactivity = Activity::id0rUuId(SactivityId)->firstO;това е пооблема.Lukas Kovalik 9:44.AMVasil Vasilev 9:44 AMActivity:.dOrludsactivitvicheтова само по себе си връша правилния моделобаче като извикаш върху Activity инстанция допълнтиелно ->first()бюка чаново в базата и рзима пиориа спошнат запискоито винаги в най ниското И ліMessage Vasil Vasilev+ Аal...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
40818
|
NULL
|
0
|
2026-05-14T09:25:51.078653+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750751078_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
FirefoxFileEditViewHistoryBookmarksProfilesCTools FirefoxFileEditViewHistoryBookmarksProfilesCTools WindowHelpmeet.google.com/mie-gawc-dsi?authuser=lukas.kovalik%40jiminny.com>0 lhl • | Daily - Platform - now+100% <478•Thu 14 May 9:45:36...
|
NULL
|
-708492635982512963
|
NULL
|
click
|
ocr
|
NULL
|
FirefoxFileEditViewHistoryBookmarksProfilesCTools FirefoxFileEditViewHistoryBookmarksProfilesCTools WindowHelpmeet.google.com/mie-gawc-dsi?authuser=lukas.kovalik%40jiminny.com>0 lhl • | Daily - Platform - now+100% <478•Thu 14 May 9:45:36...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
40820
|
1509
|
0
|
2026-05-14T09:26:15.284171+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750775284_m1.jpg...
|
PhpStorm
|
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Find in Files
1 match in 1 file
File mask:
*.php
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Find in Files","depth":1,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1 match in 1 file","depth":1,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"File mask:","depth":1,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXComboBox","text":"*.php","depth":1,"on_screen":true,"value":"*.php","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
8913433514524508491
|
984603400652877259
|
click
|
hybrid
|
NULL
|
Find in Files
1 match in 1 file
File mask:
*.php
F Find in Files
1 match in 1 file
File mask:
*.php
FirefoxFileEditViewHistoryBookmarksProfilesCTools WindowHelpmeet.google.com/mie-gawc-dsi?authuser=lukas.kovalik%40jiminny.com>0 lhl • | Daily - Platform - now+100% <478•Thu 14 May 9:45:36...
|
40818
|
NULL
|
NULL
|
NULL
|
|
40821
|
1510
|
0
|
2026-05-14T09:26:15.302749+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750775302_m2.jpg...
|
PhpStorm
|
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Find in Files
1 match in 1 file
File mask:
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Find in Files","depth":1,"bounds":{"left":0.2992021,"top":0.12609737,"width":0.024601065,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1 match in 1 file","depth":1,"bounds":{"left":0.32779256,"top":0.12609737,"width":0.03125,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"File mask:","depth":1,"bounds":{"left":0.5315825,"top":0.12290503,"width":0.029587766,"height":0.019952115},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
4191700142949013876
|
119346019413789131
|
click
|
hybrid
|
NULL
|
Find in Files
1 match in 1 file
File mask:
slackw Find in Files
1 match in 1 file
File mask:
slackw Usage | Windsurf• JY-20891 add support for second:[SRD-6848] Sidekick SMS issue -Platform Sprint 4 Q2 - Platform TeDependabot alerts • jiminny/proph(JY-19958] Upgrade BE librariesWY-20773) User Pilot not receivini( JY-19957 | Remove abanded sympTypeError: Leaque|Flysystem\Files1. Userpilot I Ask Jiminny Report Gen[JY-19957] Upgrade BE libraries -Dependabot alerts - iminny/app11Y-208011 Sidekick SMS iccue -[SRD-6849] Recorded call does n8 Jiminnv8 Jiminny8 Jiminny* Configure SSH access to multiple≥ Useful conDev Tools - ElasticJiminny-7 (SRD-68531 Moxso - Potential des& CloudWatch I eu-west-1CloudWatch | eu-west-1Platform Sorint 4 02 - Platform TeJY-20891 add support for secondaService-Desk - Queues - Platfc XIL Now TohMIStOMwindowhelg1y.dulasslan.nelIld/servicedesk/oroeeJ JIMINNYg For you(• RecentSpaces / Service-Desk / QueuesPlatform team* Starred0+ Apps|:= ListQ SpacesQ Search workJiminny (New)s work lems14 Service-DeskKeyE QueuesSRD-6853Team Priority|©, All open tickets 12SRD-68495 Unassigned t... 3Ej Support tea….SpN-69A9•, Raised by meE Assigned to ..Ej Service requ..E Plattorm teamE Processing t...Ej Site reliability... 0•, New features... 0bi InfoSec issues 0j Ready for Cu... 0•1 Resolved ti….. 999+= View all queuesF Service requestsA IncidentsHl ReportsC Operations• Knowledae Base0 Customers• Channolel• Email loasI< Develoner escalationsl: Slack integration< Reporting Center• Search IRequest tvpe vStatus vAssianee vSummaryMoxso - Potential deal stages bugkecorded call does not aobear on the casnooaroSidekick SMS issueMore tilters vPriority levelP2 MediumPe MediumP2 MediumHomeDMSActivityLateMoreJiminny...yS Starred8 jiminny-x-integrati…..•olattorm-inner-teamE) Channels# ai-chapter# alerts# backend# bugs# confusion-clinid# curiosity lab# engineering# general# jiminny-bg# platform-tickets# product launches# randomi released# sofia-officea suodort# thank-yous# the people of iimi..A Direct messages• Vasil VasilevM Stefka StovanovaMario GeorgievNikolav Ivanovo James Graham8 Stovan Tanev© Galva DimitrovaStelivan Georgiey( Petko KashinskiR Aneliva Angelova EFa Lukas Kovali#: AppsS lira GloudToastm) Google Cale!YDally - Plau100% 1∞' Inu 14 May 9:40:30@ Describe what you are looking for& e. Vasil Vasilev• MessagestAdd canvas( FilesX Pins+1 new messageVasil Vasilley 9.39 AMIдобро утровчера забравих за тебопоави ли се с инлексите, или оше ти липоват ланнииначе имах прелвлиmake docker-updateи реоилдване на локалните контеинерипри мен преди време се бе случило така, че не върваха процесите за индексиране, понеже es-update-worker-а лиспвашеа пьк менажирането на тея процеси от scheduler беше спряноLukas Kovalik 9:42 AMоправих се, но трябваше да пипна команда ще намираше грешно активитиVasi Vasiley 9•43 AMкакьв беше точно проблема всъшност?Lukas Kovalik # 9:43 AMiny# php artisan activity:update:es 422003rouna aeloieysu.s, u. уooовасато 5аоeesending activity tor ts update..Done.това е вече с повече логове422003 -> 16трябва да го видя ощеVasil Vasiley 9:44 ANSactivity = Activity::id0rUuId(SactivityId)->firstO;това е пооблема.Lukas Kovalik 9:44.AMVasil Vasilev 9:44 AMActivity:.dOrludsactivitvicheтова само по себе си връша правилния моделобаче като извикаш върху Activity инстанция допълнтиелно ->first()бюка чаново в базата и рзима пиориа спошнат запискоито винаги в най ниското И ліMessage Vasil Vasilev+ Аal...
|
40819
|
NULL
|
NULL
|
NULL
|
|
40822
|
1509
|
1
|
2026-05-14T09:26:18.588359+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750778588_m1.jpg...
|
PhpStorm
|
faVsco.js – UpdateActivityElasticSearchDocumentCom faVsco.js – UpdateActivityElasticSearchDocumentCommand.php...
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
FirefoxFileEditViewHistoryBookmarksProfilesCTools FirefoxFileEditViewHistoryBookmarksProfilesCTools WindowHelpmeet.google.com/mie-gawc-dsi?authuser=lukas.kovalik%40jiminny.com>0 lhl • | Daily - Platform - now+100% <478•Thu 14 May 9:45:36...
|
NULL
|
-708492635982512963
|
NULL
|
click
|
ocr
|
NULL
|
FirefoxFileEditViewHistoryBookmarksProfilesCTools FirefoxFileEditViewHistoryBookmarksProfilesCTools WindowHelpmeet.google.com/mie-gawc-dsi?authuser=lukas.kovalik%40jiminny.com>0 lhl • | Daily - Platform - now+100% <478•Thu 14 May 9:45:36...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
40824
|
1510
|
1
|
2026-05-14T09:26:36.618024+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750796618_m2.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"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":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"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.08459697,"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.09577015,"width":0.029920213,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6848] Sidekick SMS issue - Jira","depth":4,"bounds":{"left":0.0,"top":0.11731844,"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":"[SRD-6848] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"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.0,"top":0.15003991,"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":"[JY-20891] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.16121309,"width":0.064494684,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":4,"bounds":{"left":0.0,"top":0.18276137,"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":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.19393456,"width":0.11735372,"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.21548285,"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.22665602,"width":0.013131649,"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.2482043,"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.25937748,"width":0.013131649,"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.28092578,"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.29209897,"width":0.013131649,"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.31364724,"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.32482043,"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.3463687,"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.3575419,"width":0.079288565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Dev Tools - Elastic","depth":4,"bounds":{"left":0.0,"top":0.3790902,"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":"Dev Tools - Elastic","depth":5,"bounds":{"left":0.013297873,"top":0.39026338,"width":0.032247342,"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.41181165,"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.42298484,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":4,"bounds":{"left":0.0,"top":0.4445331,"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":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.4557063,"width":0.09158909,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.4772546,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.4884278,"width":0.041722074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.509976,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.5211492,"width":0.041722074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.54269755,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.55387074,"width":0.041722074,"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.0,"top":0.575419,"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":"JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.5865922,"width":0.15658244,"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.0,"top":0.60814047,"width":0.07962101,"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] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.61931366,"width":0.11619016,"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.61532325,"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":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.6424581,"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":"AXStaticText","text":"Skip to:","depth":10,"bounds":{"left":0.090259306,"top":0.07861133,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":11,"bounds":{"left":0.090259306,"top":0.097765364,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":12,"bounds":{"left":0.090259306,"top":0.097765364,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":11,"bounds":{"left":0.090259306,"top":0.11691939,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":12,"bounds":{"left":0.090259306,"top":0.11691939,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":11,"bounds":{"left":0.090259306,"top":0.13607343,"width":0.029421542,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":12,"bounds":{"left":0.090259306,"top":0.13607343,"width":0.029421542,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":10,"bounds":{"left":0.08361037,"top":0.057861134,"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":"AXStaticText","text":"Collapse sidebar [","depth":12,"bounds":{"left":0.0887633,"top":0.06344773,"width":0.039727394,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":11,"bounds":{"left":0.095578454,"top":0.057861134,"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":"AXStaticText","text":"Switch sites or apps","depth":13,"bounds":{"left":0.10073138,"top":0.06344773,"width":0.044215426,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":10,"bounds":{"left":0.10887633,"top":0.057861134,"width":0.029421542,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":12,"bounds":{"left":0.40475398,"top":0.06264964,"width":0.24268617,"height":0.015961692},"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":11,"bounds":{"left":0.65575135,"top":0.057861134,"width":0.030086435,"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":"Create","depth":13,"bounds":{"left":0.66705453,"top":0.06384677,"width":0.014793883,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":13,"bounds":{"left":0.91223407,"top":0.057861134,"width":0.035904255,"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":"Ask Rovo","depth":15,"bounds":{"left":0.92353725,"top":0.06384677,"width":0.020611702,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":13,"bounds":{"left":0.9494681,"top":0.057861134,"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":"AXStaticText","text":"Notifications","depth":15,"bounds":{"left":0.954621,"top":0.06344773,"width":0.027759308,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":13,"bounds":{"left":0.96143615,"top":0.057861134,"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":"AXStaticText","text":"Help","depth":15,"bounds":{"left":0.9665891,"top":0.06344773,"width":0.010139627,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","depth":13,"bounds":{"left":0.9734042,"top":0.057861134,"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":"AXStaticText","text":"Settings","depth":15,"bounds":{"left":0.97855717,"top":0.06344773,"width":0.017952127,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","depth":13,"bounds":{"left":0.98537236,"top":0.057861134,"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":"AXStaticText","text":"lukas.kovalik@jiminny.com","depth":15,"bounds":{"left":0.99052525,"top":0.06344773,"width":0.009474754,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":13,"bounds":{"left":0.08361037,"top":0.09976058,"width":0.071476065,"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":"For you","depth":16,"bounds":{"left":0.09424867,"top":0.10574621,"width":0.01662234,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Recent","depth":13,"bounds":{"left":0.08361037,"top":0.12529927,"width":0.071476065,"height":0.025538707},"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":"Recent","depth":16,"bounds":{"left":0.09424867,"top":0.13128492,"width":0.015458777,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
8025042685306832423
|
1735097905058701408
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
40823
|
1509
|
2
|
2026-05-14T09:26:36.646128+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750796646_m1.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent...
|
[{"role":"AXRadioButton","text [{"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":"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":"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":"[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":"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":"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":"AXRadioButton","text":"Dev Tools - Elastic","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dev Tools - Elastic","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":"[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":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","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":"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":true},{"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":"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":"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":"AXStaticText","text":"Skip to:","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collapse sidebar [","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":11,"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":"Switch sites or apps","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":12,"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Rovo","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Help","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","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":"Settings","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","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":"lukas.kovalik@jiminny.com","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"For you","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Recent","depth":13,"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":"Recent","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
8025042685306832423
|
1735097905058701408
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
40826
|
1510
|
2
|
2026-05-14T09:26:38.752966+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750798752_m2.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"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":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"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.08459697,"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.09577015,"width":0.029920213,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6848] Sidekick SMS issue - Jira","depth":4,"bounds":{"left":0.0,"top":0.11731844,"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":"[SRD-6848] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"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.0,"top":0.15003991,"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":"[JY-20891] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.16121309,"width":0.064494684,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":4,"bounds":{"left":0.0,"top":0.18276137,"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":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.19393456,"width":0.11735372,"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.21548285,"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.22665602,"width":0.013131649,"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.2482043,"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.25937748,"width":0.013131649,"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.28092578,"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.29209897,"width":0.013131649,"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.31364724,"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.32482043,"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.3463687,"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.3575419,"width":0.079288565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Dev Tools - Elastic","depth":4,"bounds":{"left":0.0,"top":0.3790902,"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":"Dev Tools - Elastic","depth":5,"bounds":{"left":0.013297873,"top":0.39026338,"width":0.032247342,"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.41181165,"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.42298484,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":4,"bounds":{"left":0.0,"top":0.4445331,"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":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.4557063,"width":0.09158909,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.4772546,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.4884278,"width":0.041722074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.509976,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.5211492,"width":0.041722074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.54269755,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.55387074,"width":0.041722074,"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.0,"top":0.575419,"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":"JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.5865922,"width":0.15658244,"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.0,"top":0.60814047,"width":0.07962101,"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] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.61931366,"width":0.11619016,"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.61532325,"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":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.6424581,"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":"AXStaticText","text":"Skip to:","depth":10,"bounds":{"left":0.090259306,"top":0.07861133,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":11,"bounds":{"left":0.090259306,"top":0.097765364,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":12,"bounds":{"left":0.090259306,"top":0.097765364,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":11,"bounds":{"left":0.090259306,"top":0.11691939,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":12,"bounds":{"left":0.090259306,"top":0.11691939,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":11,"bounds":{"left":0.090259306,"top":0.13607343,"width":0.029421542,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":12,"bounds":{"left":0.090259306,"top":0.13607343,"width":0.029421542,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":10,"bounds":{"left":0.08361037,"top":0.057861134,"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":"AXStaticText","text":"Collapse sidebar [","depth":12,"bounds":{"left":0.0887633,"top":0.06344773,"width":0.039727394,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":11,"bounds":{"left":0.095578454,"top":0.057861134,"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":"AXStaticText","text":"Switch sites or apps","depth":13,"bounds":{"left":0.10073138,"top":0.06344773,"width":0.044215426,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":10,"bounds":{"left":0.10887633,"top":0.057861134,"width":0.029421542,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":12,"bounds":{"left":0.40475398,"top":0.06264964,"width":0.24268617,"height":0.015961692},"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":11,"bounds":{"left":0.65575135,"top":0.057861134,"width":0.030086435,"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":"Create","depth":13,"bounds":{"left":0.66705453,"top":0.06384677,"width":0.014793883,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":13,"bounds":{"left":0.91223407,"top":0.057861134,"width":0.035904255,"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":"Ask Rovo","depth":15,"bounds":{"left":0.92353725,"top":0.06384677,"width":0.020611702,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":13,"bounds":{"left":0.9494681,"top":0.057861134,"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":"AXStaticText","text":"Notifications","depth":15,"bounds":{"left":0.954621,"top":0.06344773,"width":0.027759308,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":13,"bounds":{"left":0.96143615,"top":0.057861134,"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":"AXStaticText","text":"Help","depth":15,"bounds":{"left":0.9665891,"top":0.06344773,"width":0.010139627,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","depth":13,"bounds":{"left":0.9734042,"top":0.057861134,"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":"AXStaticText","text":"Settings","depth":15,"bounds":{"left":0.97855717,"top":0.06344773,"width":0.017952127,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","depth":13,"bounds":{"left":0.98537236,"top":0.057861134,"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":"AXStaticText","text":"lukas.kovalik@jiminny.com","depth":15,"bounds":{"left":0.99052525,"top":0.06344773,"width":0.009474754,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":13,"bounds":{"left":0.08361037,"top":0.09976058,"width":0.071476065,"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":"For you","depth":16,"bounds":{"left":0.09424867,"top":0.10574621,"width":0.01662234,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Recent","depth":13,"bounds":{"left":0.08361037,"top":0.12529927,"width":0.071476065,"height":0.025538707},"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":"Recent","depth":16,"bounds":{"left":0.09424867,"top":0.13128492,"width":0.015458777,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Starred","depth":13,"bounds":{"left":0.08361037,"top":0.15083799,"width":0.071476065,"height":0.025538707},"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":"Starred","depth":16,"bounds":{"left":0.09424867,"top":0.15682362,"width":0.016456118,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Apps","depth":13,"bounds":{"left":0.08361037,"top":0.1763767,"width":0.071476065,"height":0.025538707},"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":"Apps","depth":16,"bounds":{"left":0.09424867,"top":0.18236233,"width":0.011635638,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Apps","depth":14,"bounds":{"left":0.15309176,"top":0.17956904,"width":0.0039893617,"height":0.01915403},"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":"More actions for Apps","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Spaces","depth":13,"bounds":{"left":0.08361037,"top":0.2019154,"width":0.071476065,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Spaces","depth":16,"bounds":{"left":0.09424867,"top":0.20790103,"width":0.016456118,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create space","depth":14,"bounds":{"left":0.13646941,"top":0.20510775,"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":"AXStaticText","text":"Create space","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for spaces","depth":14,"bounds":{"left":0.14577793,"top":0.20510775,"width":0.007978723,"height":0.01915403},"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":"More actions for spaces","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Recent","depth":17,"bounds":{"left":0.08959442,"top":0.23423783,"width":0.013464096,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New)","depth":18,"bounds":{"left":0.08759973,"top":0.2529928,"width":0.0674867,"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 (New)","depth":21,"bounds":{"left":0.09823803,"top":0.25897846,"width":0.032081116,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-8442884661630764618
|
1744122638517420132
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)...
|
40824
|
NULL
|
NULL
|
NULL
|
|
40825
|
1509
|
3
|
2026-05-14T09:26:38.776135+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750798776_m1.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)...
|
[{"role":"AXRadioButton","text [{"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":"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":"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":"[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":"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":"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":"AXRadioButton","text":"Dev Tools - Elastic","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dev Tools - Elastic","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":"[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":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","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":"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":true},{"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":"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":"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":"AXStaticText","text":"Skip to:","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collapse sidebar [","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":11,"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":"Switch sites or apps","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":12,"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Rovo","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Help","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","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":"Settings","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","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":"lukas.kovalik@jiminny.com","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"For you","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Recent","depth":13,"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":"Recent","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Starred","depth":13,"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":"Starred","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Apps","depth":13,"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":"Apps","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Apps","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":"More actions for Apps","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Spaces","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Spaces","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create space","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create space","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for spaces","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":"More actions for spaces","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Recent","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New)","depth":18,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny (New)","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Jiminny (New)","depth":19,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXMenuButton","text":"Create board","depth":19,"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":"Create board","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Jiminny (New)","depth":19,"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":"More actions for Jiminny (New)","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-5892422040902704426
|
1744113979863351396
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)...
|
40823
|
NULL
|
NULL
|
NULL
|
|
40827
|
1509
|
4
|
2026-05-14T09:26:41.011200+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750801011_m1.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help...
|
[{"role":"AXRadioButton","text [{"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":"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":"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":"[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":"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":"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":"AXRadioButton","text":"Dev Tools - Elastic","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dev Tools - Elastic","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":"[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":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","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":"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":true},{"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":"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":"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":"AXStaticText","text":"Skip to:","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collapse sidebar [","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":11,"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":"Switch sites or apps","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":12,"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Rovo","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-3275640720674676276
|
1735115514424606816
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
40828
|
1510
|
3
|
2026-05-14T09:26:41.024318+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750801024_m2.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"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":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"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.08459697,"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.09577015,"width":0.029920213,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6848] Sidekick SMS issue - Jira","depth":4,"bounds":{"left":0.0,"top":0.11731844,"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":"[SRD-6848] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"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.0,"top":0.15003991,"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":"[JY-20891] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.16121309,"width":0.064494684,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":4,"bounds":{"left":0.0,"top":0.18276137,"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":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.19393456,"width":0.11735372,"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.21548285,"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.22665602,"width":0.013131649,"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.2482043,"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.25937748,"width":0.013131649,"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.28092578,"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.29209897,"width":0.013131649,"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.31364724,"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.32482043,"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.3463687,"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.3575419,"width":0.079288565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Dev Tools - Elastic","depth":4,"bounds":{"left":0.0,"top":0.3790902,"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":"Dev Tools - Elastic","depth":5,"bounds":{"left":0.013297873,"top":0.39026338,"width":0.032247342,"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.41181165,"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.42298484,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":4,"bounds":{"left":0.0,"top":0.4445331,"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":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.4557063,"width":0.09158909,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.4772546,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.4884278,"width":0.041722074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.509976,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.5211492,"width":0.041722074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.54269755,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.55387074,"width":0.041722074,"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.0,"top":0.575419,"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":"JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.5865922,"width":0.15658244,"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.0,"top":0.60814047,"width":0.07962101,"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] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.61931366,"width":0.11619016,"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.61532325,"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":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.6424581,"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":"AXStaticText","text":"Skip to:","depth":10,"bounds":{"left":0.090259306,"top":0.07861133,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":11,"bounds":{"left":0.090259306,"top":0.097765364,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":12,"bounds":{"left":0.090259306,"top":0.097765364,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":11,"bounds":{"left":0.090259306,"top":0.11691939,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":12,"bounds":{"left":0.090259306,"top":0.11691939,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":11,"bounds":{"left":0.090259306,"top":0.13607343,"width":0.029421542,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":12,"bounds":{"left":0.090259306,"top":0.13607343,"width":0.029421542,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":10,"bounds":{"left":0.08361037,"top":0.057861134,"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":"AXStaticText","text":"Collapse sidebar [","depth":12,"bounds":{"left":0.0887633,"top":0.06344773,"width":0.039727394,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":11,"bounds":{"left":0.095578454,"top":0.057861134,"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":"AXStaticText","text":"Switch sites or apps","depth":13,"bounds":{"left":0.10073138,"top":0.06344773,"width":0.044215426,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":10,"bounds":{"left":0.10887633,"top":0.057861134,"width":0.029421542,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":12,"bounds":{"left":0.40475398,"top":0.06264964,"width":0.24268617,"height":0.015961692},"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":11,"bounds":{"left":0.65575135,"top":0.057861134,"width":0.030086435,"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":"Create","depth":13,"bounds":{"left":0.66705453,"top":0.06384677,"width":0.014793883,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":13,"bounds":{"left":0.91223407,"top":0.057861134,"width":0.035904255,"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":"Ask Rovo","depth":15,"bounds":{"left":0.92353725,"top":0.06384677,"width":0.020611702,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":13,"bounds":{"left":0.9494681,"top":0.057861134,"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":"AXStaticText","text":"Notifications","depth":15,"bounds":{"left":0.954621,"top":0.06344773,"width":0.027759308,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":13,"bounds":{"left":0.96143615,"top":0.057861134,"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":"AXStaticText","text":"Help","depth":15,"bounds":{"left":0.9665891,"top":0.06344773,"width":0.010139627,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","depth":13,"bounds":{"left":0.9734042,"top":0.057861134,"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":"AXStaticText","text":"Settings","depth":15,"bounds":{"left":0.97855717,"top":0.06344773,"width":0.017952127,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","depth":13,"bounds":{"left":0.98537236,"top":0.057861134,"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":"AXStaticText","text":"lukas.kovalik@jiminny.com","depth":15,"bounds":{"left":0.99052525,"top":0.06344773,"width":0.009474754,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":13,"bounds":{"left":0.08361037,"top":0.09976058,"width":0.071476065,"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":"For you","depth":16,"bounds":{"left":0.09424867,"top":0.10574621,"width":0.01662234,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Recent","depth":13,"bounds":{"left":0.08361037,"top":0.12529927,"width":0.071476065,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
3014693927044054193
|
1735097905058701408
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
40829
|
1509
|
5
|
2026-05-14T09:26:44.052088+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750804052_m1.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira...
|
[{"role":"AXRadioButton","text [{"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":"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":"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}]...
|
-7938143961623122586
|
-777917365587410859
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira...
|
40827
|
NULL
|
NULL
|
NULL
|
|
40830
|
1510
|
4
|
2026-05-14T09:26:44.073609+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750804073_m2.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"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":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"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.08459697,"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.09577015,"width":0.029920213,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6848] Sidekick SMS issue - Jira","depth":4,"bounds":{"left":0.0,"top":0.11731844,"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":"[SRD-6848] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.06632314,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-2447754544619944885
|
-759902425912049451
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira...
|
40828
|
NULL
|
NULL
|
NULL
|
|
40831
|
1509
|
6
|
2026-05-14T09:27:14.934578+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750834934_m1.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny...
|
[{"role":"AXRadioButton","text [{"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":"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":"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":"[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":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-2393242320229137228
|
8157365096961433717
|
idle
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
40832
|
1510
|
5
|
2026-05-14T09:27:15.399592+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750835399_m2.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"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":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"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.08459697,"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.09577015,"width":0.029920213,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6848] Sidekick SMS issue - Jira","depth":4,"bounds":{"left":0.0,"top":0.11731844,"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":"[SRD-6848] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"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.0,"top":0.15003991,"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":"[JY-20891] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.16121309,"width":0.064494684,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":4,"bounds":{"left":0.0,"top":0.18276137,"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":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.19393456,"width":0.11735372,"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.21548285,"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.22665602,"width":0.013131649,"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.2482043,"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.25937748,"width":0.013131649,"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.28092578,"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.29209897,"width":0.013131649,"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.31364724,"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.32482043,"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.3463687,"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.3575419,"width":0.079288565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Dev Tools - Elastic","depth":4,"bounds":{"left":0.0,"top":0.3790902,"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":"Dev Tools - Elastic","depth":5,"bounds":{"left":0.013297873,"top":0.39026338,"width":0.032247342,"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.41181165,"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.42298484,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":4,"bounds":{"left":0.0,"top":0.4445331,"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":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.4557063,"width":0.09158909,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.4772546,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.4884278,"width":0.041722074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.509976,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.5211492,"width":0.041722074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.54269755,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.55387074,"width":0.041722074,"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.0,"top":0.575419,"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":"JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.5865922,"width":0.15658244,"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.0,"top":0.60814047,"width":0.07962101,"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] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.61931366,"width":0.11619016,"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.61532325,"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":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.6424581,"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}]...
|
36468730964116217
|
6355791131322368100
|
idle
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
40834
|
1510
|
6
|
2026-05-14T09:27:22.042049+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750842042_m2.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"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":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"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.08459697,"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.09577015,"width":0.029920213,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6848] Sidekick SMS issue - Jira","depth":4,"bounds":{"left":0.0,"top":0.11731844,"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":"[SRD-6848] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"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.0,"top":0.15003991,"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":"[JY-20891] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.16121309,"width":0.064494684,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":4,"bounds":{"left":0.0,"top":0.18276137,"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":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.19393456,"width":0.11735372,"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.21548285,"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.22665602,"width":0.013131649,"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.2482043,"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.25937748,"width":0.013131649,"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.28092578,"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.29209897,"width":0.013131649,"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.31364724,"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.32482043,"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.3463687,"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.3575419,"width":0.079288565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Dev Tools - Elastic","depth":4,"bounds":{"left":0.0,"top":0.3790902,"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":"Dev Tools - Elastic","depth":5,"bounds":{"left":0.013297873,"top":0.39026338,"width":0.032247342,"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.41181165,"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.42298484,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":4,"bounds":{"left":0.0,"top":0.4445331,"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":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.4557063,"width":0.09158909,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.4772546,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.4884278,"width":0.041722074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.509976,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.5211492,"width":0.041722074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.54269755,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.55387074,"width":0.041722074,"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.0,"top":0.575419,"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":"JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.5865922,"width":0.15658244,"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.0,"top":0.60814047,"width":0.07962101,"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] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.61931366,"width":0.11619016,"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.61532325,"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":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.6424581,"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":"AXStaticText","text":"Skip to:","depth":10,"bounds":{"left":0.090259306,"top":0.07861133,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":11,"bounds":{"left":0.090259306,"top":0.097765364,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":12,"bounds":{"left":0.090259306,"top":0.097765364,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":11,"bounds":{"left":0.090259306,"top":0.11691939,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
640376405781576870
|
6355808869545697380
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar...
|
40832
|
NULL
|
NULL
|
NULL
|
|
40833
|
1509
|
7
|
2026-05-14T09:27:22.042056+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750842042_m1.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices...
|
[{"role":"AXRadioButton","text [{"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":"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":"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":"[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":"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":"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":"AXRadioButton","text":"Dev Tools - Elastic","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dev Tools - Elastic","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":"[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":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","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":"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":true},{"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":"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":"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}]...
|
36468730964116217
|
6355791131322368100
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices...
|
40831
|
NULL
|
NULL
|
NULL
|
|
40835
|
1509
|
8
|
2026-05-14T09:27:52.478263+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750872478_m1.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)...
|
[{"role":"AXRadioButton","text [{"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":"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":"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":"[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":"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":"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":"AXRadioButton","text":"Dev Tools - Elastic","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dev Tools - Elastic","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":"[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":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","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":"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":true},{"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":"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":"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":"AXStaticText","text":"Skip to:","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collapse sidebar [","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":11,"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":"Switch sites or apps","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":12,"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Rovo","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Help","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","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":"Settings","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","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":"lukas.kovalik@jiminny.com","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"For you","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Recent","depth":13,"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":"Recent","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Starred","depth":13,"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":"Starred","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Apps","depth":13,"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":"Apps","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Apps","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":"More actions for Apps","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Spaces","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Spaces","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create space","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create space","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for spaces","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":"More actions for spaces","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Recent","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New)","depth":18,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny (New)","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Jiminny (New)","depth":19,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXMenuButton","text":"Create board","depth":19,"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":"Create board","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Jiminny (New)","depth":19,"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":"More actions for Jiminny (New)","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-5892422040902704426
|
1744113979863351396
|
idle
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
40836
|
1510
|
7
|
2026-05-14T09:27:52.671154+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750872671_m2.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)
Platform Team
Platform Team
Board actions
Board actions
Capture Team
Capture Team
Board actions
Board actions
Enterprise Stability Issues 🤕
Enterprise Stability Issues 🤕
Board actions
Board actions
Processing Team
Processing Team
Board actions
Board actions
SE Kanban
SE Kanban
Board actions
Board actions
Service-Desk
Service-Desk
More actions for Service-Desk
More actions for Service-Desk...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"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":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"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.08459697,"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.09577015,"width":0.029920213,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6848] Sidekick SMS issue - Jira","depth":4,"bounds":{"left":0.0,"top":0.11731844,"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":"[SRD-6848] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"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.0,"top":0.15003991,"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":"[JY-20891] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.16121309,"width":0.064494684,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":4,"bounds":{"left":0.0,"top":0.18276137,"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":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.19393456,"width":0.11735372,"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.21548285,"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.22665602,"width":0.013131649,"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.2482043,"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.25937748,"width":0.013131649,"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.28092578,"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.29209897,"width":0.013131649,"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.31364724,"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.32482043,"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.3463687,"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.3575419,"width":0.079288565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Dev Tools - Elastic","depth":4,"bounds":{"left":0.0,"top":0.3790902,"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":"Dev Tools - Elastic","depth":5,"bounds":{"left":0.013297873,"top":0.39026338,"width":0.032247342,"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.41181165,"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.42298484,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":4,"bounds":{"left":0.0,"top":0.4445331,"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":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.4557063,"width":0.09158909,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.4772546,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.4884278,"width":0.041722074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.509976,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.5211492,"width":0.041722074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.54269755,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.55387074,"width":0.041722074,"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.0,"top":0.575419,"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":"JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.5865922,"width":0.15658244,"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.0,"top":0.60814047,"width":0.07962101,"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] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.61931366,"width":0.11619016,"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.61532325,"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":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.6424581,"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":"AXStaticText","text":"Skip to:","depth":10,"bounds":{"left":0.090259306,"top":0.07861133,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":11,"bounds":{"left":0.090259306,"top":0.097765364,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":12,"bounds":{"left":0.090259306,"top":0.097765364,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":11,"bounds":{"left":0.090259306,"top":0.11691939,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":12,"bounds":{"left":0.090259306,"top":0.11691939,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":11,"bounds":{"left":0.090259306,"top":0.13607343,"width":0.029421542,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":12,"bounds":{"left":0.090259306,"top":0.13607343,"width":0.029421542,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":10,"bounds":{"left":0.08361037,"top":0.057861134,"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":"AXStaticText","text":"Collapse sidebar [","depth":12,"bounds":{"left":0.0887633,"top":0.06344773,"width":0.039727394,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":11,"bounds":{"left":0.095578454,"top":0.057861134,"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":"AXStaticText","text":"Switch sites or apps","depth":13,"bounds":{"left":0.10073138,"top":0.06344773,"width":0.044215426,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":10,"bounds":{"left":0.10887633,"top":0.057861134,"width":0.029421542,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":12,"bounds":{"left":0.40475398,"top":0.06264964,"width":0.24268617,"height":0.015961692},"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":11,"bounds":{"left":0.65575135,"top":0.057861134,"width":0.030086435,"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":"Create","depth":13,"bounds":{"left":0.66705453,"top":0.06384677,"width":0.014793883,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":13,"bounds":{"left":0.91223407,"top":0.057861134,"width":0.035904255,"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":"Ask Rovo","depth":15,"bounds":{"left":0.92353725,"top":0.06384677,"width":0.020611702,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":13,"bounds":{"left":0.9494681,"top":0.057861134,"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":"AXStaticText","text":"Notifications","depth":15,"bounds":{"left":0.954621,"top":0.06344773,"width":0.027759308,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":13,"bounds":{"left":0.96143615,"top":0.057861134,"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":"AXStaticText","text":"Help","depth":15,"bounds":{"left":0.9665891,"top":0.06344773,"width":0.010139627,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","depth":13,"bounds":{"left":0.9734042,"top":0.057861134,"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":"AXStaticText","text":"Settings","depth":15,"bounds":{"left":0.97855717,"top":0.06344773,"width":0.017952127,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","depth":13,"bounds":{"left":0.98537236,"top":0.057861134,"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":"AXStaticText","text":"lukas.kovalik@jiminny.com","depth":15,"bounds":{"left":0.99052525,"top":0.06344773,"width":0.009474754,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":13,"bounds":{"left":0.08361037,"top":0.09976058,"width":0.071476065,"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":"For you","depth":16,"bounds":{"left":0.09424867,"top":0.10574621,"width":0.01662234,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Recent","depth":13,"bounds":{"left":0.08361037,"top":0.12529927,"width":0.071476065,"height":0.025538707},"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":"Recent","depth":16,"bounds":{"left":0.09424867,"top":0.13128492,"width":0.015458777,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Starred","depth":13,"bounds":{"left":0.08361037,"top":0.15083799,"width":0.071476065,"height":0.025538707},"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":"Starred","depth":16,"bounds":{"left":0.09424867,"top":0.15682362,"width":0.016456118,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Apps","depth":13,"bounds":{"left":0.08361037,"top":0.1763767,"width":0.071476065,"height":0.025538707},"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":"Apps","depth":16,"bounds":{"left":0.09424867,"top":0.18236233,"width":0.011635638,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Apps","depth":14,"bounds":{"left":0.15309176,"top":0.17956904,"width":0.0039893617,"height":0.01915403},"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":"More actions for Apps","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Spaces","depth":13,"bounds":{"left":0.08361037,"top":0.2019154,"width":0.071476065,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Spaces","depth":16,"bounds":{"left":0.09424867,"top":0.20790103,"width":0.016456118,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create space","depth":14,"bounds":{"left":0.13646941,"top":0.20510775,"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":"AXStaticText","text":"Create space","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for spaces","depth":14,"bounds":{"left":0.14577793,"top":0.20510775,"width":0.007978723,"height":0.01915403},"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":"More actions for spaces","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Recent","depth":17,"bounds":{"left":0.08959442,"top":0.23423783,"width":0.013464096,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New)","depth":18,"bounds":{"left":0.08759973,"top":0.2529928,"width":0.0674867,"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 (New)","depth":21,"bounds":{"left":0.09823803,"top":0.25897846,"width":0.032081116,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Jiminny (New)","depth":19,"bounds":{"left":0.08892952,"top":0.25618514,"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,"is_expanded":true},{"role":"AXMenuButton","text":"Create board","depth":19,"bounds":{"left":0.13646941,"top":0.25618514,"width":0.007978723,"height":0.01915403},"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":"Create board","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Jiminny (New)","depth":19,"bounds":{"left":0.14577793,"top":0.25618514,"width":0.007978723,"height":0.01915403},"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":"More actions for Jiminny (New)","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Platform Team","depth":20,"bounds":{"left":0.09158909,"top":0.27853152,"width":0.06349734,"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":"Platform Team","depth":23,"bounds":{"left":0.1022274,"top":0.28451717,"width":0.032247342,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"bounds":{"left":0.15309176,"top":0.28172386,"width":0.0039893617,"height":0.01915403},"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":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Capture Team","depth":20,"bounds":{"left":0.09158909,"top":0.30407023,"width":0.06349734,"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":"Capture Team","depth":23,"bounds":{"left":0.1022274,"top":0.31005585,"width":0.03125,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"bounds":{"left":0.15309176,"top":0.30726257,"width":0.0039893617,"height":0.01915403},"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":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Enterprise Stability Issues 🤕","depth":20,"bounds":{"left":0.09158909,"top":0.32960895,"width":0.06349734,"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":"Enterprise Stability Issues 🤕","depth":23,"bounds":{"left":0.1022274,"top":0.33559456,"width":0.050531916,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"bounds":{"left":0.15309176,"top":0.33280128,"width":0.0039893617,"height":0.01915403},"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":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Processing Team","depth":20,"bounds":{"left":0.09158909,"top":0.35514766,"width":0.06349734,"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":"Processing Team","depth":23,"bounds":{"left":0.1022274,"top":0.36113328,"width":0.038231384,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"bounds":{"left":0.15309176,"top":0.35834,"width":0.0039893617,"height":0.01915403},"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":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SE Kanban","depth":20,"bounds":{"left":0.09158909,"top":0.38068634,"width":0.06349734,"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":"SE Kanban","depth":23,"bounds":{"left":0.1022274,"top":0.386672,"width":0.024102394,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"bounds":{"left":0.15309176,"top":0.38387868,"width":0.0039893617,"height":0.01915403},"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":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Service-Desk","depth":18,"bounds":{"left":0.08759973,"top":0.40622506,"width":0.0674867,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Service-Desk","depth":21,"bounds":{"left":0.09823803,"top":0.4122107,"width":0.03025266,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Service-Desk","depth":19,"bounds":{"left":0.14577793,"top":0.4094174,"width":0.007978723,"height":0.01915403},"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":"More actions for Service-Desk","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-6059944130091073323
|
1735027476184977508
|
idle
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)
Platform Team
Platform Team
Board actions
Board actions
Capture Team
Capture Team
Board actions
Board actions
Enterprise Stability Issues 🤕
Enterprise Stability Issues 🤕
Board actions
Board actions
Processing Team
Processing Team
Board actions
Board actions
SE Kanban
SE Kanban
Board actions
Board actions
Service-Desk
Service-Desk
More actions for Service-Desk
More actions for Service-Desk...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
40838
|
1510
|
8
|
2026-05-14T09:28:06.408022+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750886408_m2.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"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":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"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.08459697,"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.09577015,"width":0.029920213,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6848] Sidekick SMS issue - Jira","depth":4,"bounds":{"left":0.0,"top":0.11731844,"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":"[SRD-6848] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"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.0,"top":0.15003991,"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":"[JY-20891] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.16121309,"width":0.064494684,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":4,"bounds":{"left":0.0,"top":0.18276137,"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":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.19393456,"width":0.11735372,"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.21548285,"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}]...
|
-2393242320229137228
|
8157365096961433717
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny...
|
40836
|
NULL
|
NULL
|
NULL
|
|
40837
|
1509
|
9
|
2026-05-14T09:28:06.408082+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750886408_m1.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny...
|
[{"role":"AXRadioButton","text [{"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":"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":"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":"[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":"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"}]...
|
-4029595037331829798
|
8157365096961433716
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny...
|
40835
|
NULL
|
NULL
|
NULL
|
|
40840
|
1510
|
9
|
2026-05-14T09:28:28.201801+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750908201_m2.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"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":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"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.08459697,"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.09577015,"width":0.029920213,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6848] Sidekick SMS issue - Jira","depth":4,"bounds":{"left":0.0,"top":0.11731844,"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":"[SRD-6848] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"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.0,"top":0.15003991,"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":"[JY-20891] Sidekick SMS issue - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.16121309,"width":0.064494684,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":4,"bounds":{"left":0.0,"top":0.18276137,"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":"[SRD-6849] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.19393456,"width":0.11735372,"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.21548285,"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.22665602,"width":0.013131649,"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.2482043,"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.25937748,"width":0.013131649,"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.28092578,"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.29209897,"width":0.013131649,"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.31364724,"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.32482043,"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.3463687,"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.3575419,"width":0.079288565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Dev Tools - Elastic","depth":4,"bounds":{"left":0.0,"top":0.3790902,"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":"Dev Tools - Elastic","depth":5,"bounds":{"left":0.013297873,"top":0.39026338,"width":0.032247342,"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.41181165,"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.42298484,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":4,"bounds":{"left":0.0,"top":0.4445331,"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":"[SRD-6853] Moxso - Potential deal stages bug - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.4557063,"width":0.09158909,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.4772546,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.4884278,"width":0.041722074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.509976,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.5211492,"width":0.041722074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"bounds":{"left":0.0,"top":0.54269755,"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":"CloudWatch | eu-west-1","depth":5,"bounds":{"left":0.013297873,"top":0.55387074,"width":0.041722074,"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.0,"top":0.575419,"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":"JY-20891 add support for secondary email by LakyLak · Pull Request #12073 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.5865922,"width":0.15658244,"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.0,"top":0.60814047,"width":0.07962101,"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] Recorded call does not appear on the dashboard - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.61931366,"width":0.11619016,"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.61532325,"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":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.6424581,"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}]...
|
6913790665093042775
|
6355791131330756708
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
40839
|
1509
|
10
|
2026-05-14T09:28:28.201880+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778750908201_m1.jpg...
|
Firefox
|
[JY-20903] Recorded call does not appear on the da [JY-20903] Recorded call does not appear on the dashboard - Jira — Work...
|
1
|
jiminny.atlassian.net/browse/JY-20903
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab...
|
[{"role":"AXRadioButton","text [{"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":"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":"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":"[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":"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":"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":"AXRadioButton","text":"Dev Tools - Elastic","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dev Tools - Elastic","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":"[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":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | eu-west-1","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | eu-west-1","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":"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":true},{"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":"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":"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}]...
|
9027651473819569423
|
6355808714918486116
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Usage | Windsurf
Usage | Windsurf
[SRD-6848] Sidekick SMS issue - Jira
[SRD-6848] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[JY-20891] Sidekick SMS issue - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
[SRD-6849] Recorded call does not appear on the dashboard - Jira
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Configure SSH access to multiple environment - Engineering - Confluence
Configure SSH access to multiple environment - Engineering - Confluence
Useful commands - Engineering - Confluence
Useful commands - Engineering - Confluence
Dev Tools - Elastic
Dev Tools - Elastic
Jiminny
Jiminny
[SRD-6853] Moxso - Potential deal stages bug - Jira
[SRD-6853] Moxso - Potential deal stages bug - Jira
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
CloudWatch | eu-west-1
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
[JY-20903] Recorded call does not appear on the dashboard - Jira
[JY-20903] Recorded call does not appear on the dashboard - Jira
Close tab
New Tab...
|
NULL
|
NULL
|
NULL
|
NULL
|